Skip to content

Latest commit

 

History

25 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

devcon

A personal, self-contained dev environment container, for my own use.

An encapsulated place to work, so anything the tooling does stays inside the container instead of touching the host.

Included tools

  • Core development: git, GitHub CLI (gh), Python 3 with pip/venv, Node/npm, and a native build toolchain for Python and npm packages.
  • AI coding: Claude Code (claude) and Codex CLI (codex).
  • Editors and sessions: code-server, Vim (vi/vim), and GNU Screen (screen).
  • Files and search: less, tree, file, zip/unzip, rg, fd, and jq. (fd is provided as the conventional alias for Ubuntu's fdfind.)
  • Network diagnostics: curl, wget, ping, nslookup, ip, nc, and traceroute.
  • Process diagnostics: ps/top, lsof, strace, and htop.
  • Shell productivity: Bash completion, fzf, direnv, and shellcheck.
  • Remote and containers: key-only SSH plus rootless Podman through docker/docker compose, without a host daemon.

Built on ghcr.io/linuxserver/code-server for a maintained code-server with s6 init and PUID/PGID handling, so files created in the volume are owned by my own user, not root.

Image

Built and pushed automatically to ghcr.io/dermute/devcon:latest by GitHub Actions — on every push to main, weekly (to pick up base image, Node and Claude Code updates), and on manual dispatch. Architecture: linux/amd64.

Run

cp .env.example .env      # set DEVCON_PASSWORD, ports, config path
docker compose up -d

Then:

  • code-serverhttp://<host>:8443 (password from .env)
  • sshssh -p 2222 <DEVCON_USER>@<host> (abc by default)

SSH access

Key-only by default. Provide a public key one of two ways:

# via .env — installed into authorized_keys on startup
DEVCON_SSH_PUBKEY="ssh-ed25519 AAAA... you@host"

# or drop it into the volume yourself
cat ~/.ssh/id_ed25519.pub >> <config>/.ssh/authorized_keys

To use a password instead, set DEVCON_SSH_PASSWORD_AUTH=true and DEVCON_SSH_PASSWORD=... in .env. Key auth stays enabled alongside it.

Docker (rootless Podman)

Docker inside the container is provided by rootless Podman — no daemon on the host, no host Docker socket. The docker command, docker compose, and a DOCKER_HOST socket all work out of the box:

docker run --rm hello-world
docker build -t myapp .
docker compose up -d
  • docker is a shim over podman; podman works directly too.
  • docker compose is upstream Compose v2 (the distro package, so it tracks the base image on each weekly rebuild — no pinned version), driving the Podman socket via DOCKER_HOST. podman-compose is installed as a fallback provider.
  • Images and containers persist under /config (the volume), so they survive rebuilds.
  • DOCKER_HOST points at a rootless Podman API socket, so other tools that speak the Docker API — the VS Code Docker extension, testcontainers — work too.
  • Set DEVCON_DOCKER=false in .env to turn the API socket off.

This needs the outer devcon container to run with privileged: true, plus /dev/fuse, as configured in docker-compose.yml. The privilege is required at the outer boundary so newuidmap can create nested user namespaces and startup can make the mount tree recursively shared. Podman and the containers it starts still run as the non-root login user, and no host Docker/Podman socket is mounted. This is nevertheless a meaningful security relaxation: only run this image on a host where devcon and its users are trusted. If nested containers are not needed, remove privileged, security_opt, and devices from the Compose file and set DEVCON_DOCKER=false.

First-run auth (inside the container)

gh auth login       # GitHub
claude              # Claude Code — follow the login flow
codex               # Codex CLI — follow the login flow

Both persist under the /config volume, so they survive rebuilds.

Configuration

Env var Default Purpose
DEVCON_PASSWORD code-server web password
DEVCON_WEB_PORT 8443 host port for the code-server UI
DEVCON_SSH_PORT 2222 host port for ssh
DEVCON_CONFIG /.config host path for the persisted /config
DEVCON_USER abc login username inside the container
DEVCON_PUID / DEVCON_PGID 1000/100 user/group id that owns files in the volume
DEVCON_SSH_PUBKEY public key installed into authorized_keys
DEVCON_SSH_PASSWORD_AUTH false allow ssh password login (else key-only)
DEVCON_SSH_PASSWORD login user's ssh password (when password auth is on)
DEVCON_DOCKER true rootless podman API socket + DOCKER_HOST
GIT_USER_NAME git config --global user.name
GIT_USER_EMAIL git config --global user.email

Notes

  • No host Docker/Podman socket is mounted; Docker inside uses an independent, rootless Podman store under /config.
  • The outer devcon container is privileged so nested rootless Podman can create user and mount namespaces. Treat devcon as a trusted personal environment, not as a security boundary against hostile code.
  • Passwords are passed as env vars, so DEVCON_PASSWORD / DEVCON_SSH_PASSWORD are visible in docker inspect and to any process in the container. Fine for a personal box; use compose secrets if that ever stops being true.
  • DEVCON_USER must be a normal lowercase login name — root and malformed names are rejected at startup and fall back to abc.
  • To update: docker compose pull && docker compose up -d.

AI attribution

This project was developed with AI assistance from:

About

Personal, self-contained dev environment container (git, gh, Claude Code, code-server, sshd)

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages