Skip to main content

Persistence

What survives container rebuilds

Everything in /config is a Docker volume: it lives on the host and survives docker compose down && docker compose up -d:

/config/
├── .bashrc # Shell config (PATH, aliases, env vars)
├── .zshrc # Zsh config
├── .bash_profile # Login shell hook
├── .gitconfig # Git identity + GitHub token
├── .nvm/ # nvm + Node LTS installations
├── .npm-global/ # Global npm packages (Claude Code)
└── .local/ # User-local data

What does NOT survive

System packages installed via apt-get are lost on container rebuild. The init script (init.sh) reinstalls them on every boot:

PackageWhy it's reinstalled
openssh-serverRuns the SSH daemon
build-essentialgcc, make, etc.
python3-pip, python3-venvPython tooling
default-jdkJava
git, curl, wgetCore utilities
docker.ioDocker CLI
tmux, zsh, nanoShell + editor
ttydWeb terminal binary

Reinstall takes a few seconds, apt-get is fast.

The golden rule

If it lands in /config, it persists forever. If it needs sudo or apt, add it to init.sh.

Examples

# ✅ Persists: lives in /config
npm install -g some-package
pip install --user some-package

# ❌ Does NOT persist: add to init.sh
sudo apt-get install some-package

Adding persistent packages

To make an apt package survive rebuilds, add it to the apt-get install line in init.sh:

# In init.sh, find this line and add your package:
apt-get install -y -qq \
openssh-server \
your-package-here \
...

Then recreate the container:

docker compose up -d --force-recreate

Environment variables

Claude Code and Git config are written fresh on every boot from the env vars in compose.yaml. Edit compose.yaml, recreate the container, and changes take effect.

See Environment Variables for the full reference.