{"id":19456142,"url":"https://github.com/jakub-stastny/dev","last_synced_at":"2025-10-30T03:17:56.918Z","repository":{"id":152360773,"uuid":"306992645","full_name":"jakub-stastny/dev","owner":"jakub-stastny","description":"Docker image of my development environment.","archived":false,"fork":false,"pushed_at":"2023-04-28T23:14:58.000Z","size":632,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"dev","last_synced_at":"2025-02-25T10:51:53.578Z","etag":null,"topics":["development-environment","docker-image"],"latest_commit_sha":null,"homepage":"https://jakub-stastny.github.io/dev/","language":null,"has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jakub-stastny.png","metadata":{"files":{"readme":"README.org","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-10-24T23:55:51.000Z","updated_at":"2023-03-14T23:53:12.000Z","dependencies_parsed_at":null,"dependency_job_id":"d741130d-1f2e-4fa9-a5ff-ca1ec3bbfb06","html_url":"https://github.com/jakub-stastny/dev","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/jakub-stastny/dev","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jakub-stastny%2Fdev","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jakub-stastny%2Fdev/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jakub-stastny%2Fdev/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jakub-stastny%2Fdev/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jakub-stastny","download_url":"https://codeload.github.com/jakub-stastny/dev/tar.gz/refs/heads/dev","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jakub-stastny%2Fdev/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272339300,"owners_count":24917147,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-27T02:00:09.397Z","response_time":76,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["development-environment","docker-image"],"created_at":"2024-11-10T17:16:13.306Z","updated_at":"2025-10-30T03:17:56.565Z","avatar_url":"https://github.com/jakub-stastny.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"#+OPTIONS: toc:nil html-postamble:nil tex:nil\n#+HTML_HEAD: \u003clink rel=\"stylesheet\" type=\"text/css\" href=\"styles.css\"/\u003e\n\n* About\n#+INCLUDE: _badge.org\n\nMy development environment with my favourite tools and dotfiles packed as a Docker image.\n\nThis way I can use it as a base for per-project image and spin containers off of it, in order to separate my projects and keep my host system clean and state-less and therefore easily reinstallable.\n\nAlthough containers are ephemeral, we can keep our SSH keys, shell history and other desirable files by using Docker volumes.\n\nWe can manage these images either manually, or with [[https://github.com/jakub-stastny/docker-project-manager][docker-project-manager]], which I created *specifically for this purpose*.\n\n* Software\n\n- Development version of *Emacs 28* with native compilation.\n- *NeoVim* 0.4.3.\n- *Babashka* 0.5.0.\n- *Clojure CLI* 1.10.3.855.\n- *GH CLI* 1.12.0 (2021-06-29).\n- My [[https://github.com/jakub-stastny/dotfiles][dotfiles]].\n- APT sources for Node.js and Yarn.\n\n** TODO Add et.jar and et alias\nOr babashka version (exec)\nor both.\n\n* My specific use-case\n\nI use iPad Pro as my main work machine and I work on my VPS, since Linux really is what I want as my development environment.\n\nFor that reason, my image is based on the OpenSSH server, and I can connect to my development environments directly, without having to touch the host machine at all.\n\nHowever would you be using this locally, you're better of /not using SSH/, but rather =docker exec -it zsh= or whatever your favourite shell is.\n\nWhy? Because this way your =ENV=, =WORKDIR= and possibly other settings from your =Dockerfile= will be respected.\n\nBy that I mean that if I put =ENV AWS_DEV_SECRET=1234567890= into my =Dockerfile=, if I connect with =docker exec=, the variable =AWS_DEV_SECRET= will be defined. However if I connect with the OpenSSH server, the variable is not going to be defined.\n\n/The rest of the documentation assumes your workflow is similar. Given how simple this is, I'm sure you can figure out for yourself which way is best for your usecase and adjust the [[https://jakub-stastny.github.io/dev/][build scripts]] appropriately./\n\n* Usage\n\nFirst, let's create a new directory for our project. Let's call it =rpm=:\n\n#+begin_src shell\n  mkdir rpm \u0026\u0026 cd rpm\n#+end_src\n\n** Dockerfile\n\nNext, let's start with the =Dockerfile=. Obviously we use the =dev= image as our base:\n\n#+begin_src dockerfile\nFROM jakubstastny/dev:latest\n#+end_src\n\n*** SSH keys\n\nFirst, we need to copy our public SSH key into =.ssh/authorized_keys=:\n\n#+begin_src shell\n  mkdir .ssh \u0026\u0026 chmod 700 .ssh \u0026\u0026 echo \"\u003cyour-public-ssh-key\u003e\" \u003e .ssh/authorized_keys\n#+end_src\n\nThis is important, so you can SSH into the running container.\n\nNext, let's generate a new pair of SSH keys for the project:\n\n#+begin_src shell\n  mkdir .ssh \u0026\u0026 ssh-keygen -t rsa -C rpm -f .ssh/id_rsa\n#+end_src\n\nYou will need to add the generated /public/ SSH key into your GitHub settings, in order to be able to push to your repositories (and clone any private repository that you might need).\n\nNow let's copy the key pair to the image:\n\n#+begin_src dockerfile\nCOPY .ssh /root/.ssh\n#+end_src\n\n*** Clone your repo and set up your projects\n\nThis is really up to you. You might use something like this:\n\n#+begin_src dockerfile\nRUN ssh-keyscan -H github.com \u003e\u003e ~/.ssh/known_hosts \u0026\u0026 dotfiles pull -r \u0026\u0026 git clone git@github.com:jakub-stastny/dev.git\n#+end_src\n\n*** SSHD port\n\nFor your first image, you don't have to worry about this. The default =SSHD_PORT= is =2222=.\n\nHowever if you want to run multiple of these images in paralel, you'll need to override the =SSHD_PORT=, so that it's unique like so:\n\n#+begin_src dockerfile\nENV SSHD_PORT=2223\n#+end_src\n\n** Creating the image\n\nFirst, let's build the image:\n\n#+begin_src shell\n  docker build . -t rpm-dev-env\n#+end_src\n\nAs you can see, the naming convention I use is =\u003cproject-name\u003e-dev-env=. It's not necessary, but it's a useful way of distinguishing the development environments from other Docker images.\n\nNow let's create the image:\n\n#+begin_src shell\n  docker create -it -v /var/run/docker.sock:/var/run/docker.sock -v $PWD/.history:/root/.history --network host --name rpm-dev-env --hostname rpm rpm-dev-env\n#+end_src\n\nLet's break down the most important parts:\n\n*** Docker-in-Docker\n\nProxying =/var/run/docker.sock= from the host to the development environment via =-v /var/run/docker.sock:/var/run/docker.sock= is a way of doing Docker-in-Docker, also known as DinD.\n\nIt's not the most secure way, probably using =--privileged= flag would be better, but since I use my development environment as a stateless, ephemeral thing, I'm not really concerned with security.\n\nAlso note that I've been using this approach for many years: I've seen there are better ways of doing DinD these days, but I haven't had the need to review them so far.\n\n*** Proxying shell history\n\nUnlike the SSH keys, which we simply =COPY= to the image, shell history keeps changing and we don't want to loose the changes when we rebuild the image.\n\nThat's why we proxy it from the host machine as a volume using =-v $PWD/.history:/root/.history=. If your shell history is not named =.history=, replace the file name with the appropriate one.\n\n*** Host networking\n\nHost networking means that we can forget about exposing ports manually: if you start a server on port =8000= in your development environment, it will be available on port =8000= on the host machine automatically. This is what =--network host= is for.\n\n** Starting the image\n\n#+begin_src shell\n  docker start rpm-dev-env\n#+end_src\n\n** Connecting to the container via SSH\n\nNow you're good to go. Assuming that you have the container on a VPS like I do, you can connect directly to it by SSH without having to go through the host machine first:\n\n#+begin_src shell\n  ssh root@ip:2222\n#+end_src\n\nAs a side note, I highly recommend using [[https://mosh.org][Mosh]] instead of SSH. You won't even notice you're working on a remote machine, that's how fast it is. And it always reconnects, even if you switch network.\n\n* Development\n\n- The development branch is =literate.dev=.\n- The stable branch is =literate.stable=.\n- [[./build.org][Development documentation]] is generated from =literate.stable=.\n- Here is [[./development-environment.org][how to set up the development environment]] to hack on the image itself.\n- Here is what I do to [[./host-setup.org][set up the host machine]].\n- Here is how I [[./publishing.org][publish the documentation]].\n- And finally here is how I [[./release.org][release the image]].\n\nEnjoy!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjakub-stastny%2Fdev","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjakub-stastny%2Fdev","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjakub-stastny%2Fdev/lists"}