Run any AI coding agent (Pi, Codex CLI, Amp, etc.) in a secure, pre-configured container with SSH access and an optional web IDE server.
A batteries-included Docker container that gives you:
- Multiple AI coding agents — Pi, Codex CLI, and Amp pre-installed. Switch with
AGENT_CMD=codex. - Web IDE server — optional OpenCode server for browser-based editing.
- SSH access — connect from anywhere, attach to the tmux session, and work remotely.
- 80,000+ packages via Nix — install anything on the fly.
- Pre-installed tools — git, Node.js, Python, Go, Rust, PostgreSQL client, Redis CLI, and more.
- Persistent workspace — your code and config survive container restarts.
- Language servers — TypeScript, Python, Go, Rust, Lua, YAML, Bash, Dockerfile, HTML/CSS/JSON.
# 1. Set your password and choose an agent
cp .env.example .env
# Edit .env: set WEB_SERVER_PASSWORD=your-password
# 2. Start the container
./start.sh
# 3. Attach to the agent
./start.sh --attachTo also start the web IDE server (requires a password):
WEB_SERVER_PASSWORD=secret ./start.sh --webConnect from an OpenCode client:
opencode attach http://localhost:8888
# Username: opencode
# Password: your-passwordMulti-platform images (linux/amd64, linux/arm64) are published to GitHub Container Registry:
docker pull ghcr.io/etircopyh/containedcode:latest| Tag | Description |
|---|---|
latest |
Latest release |
v1.2.3 |
Specific version |
main |
Latest commit on main branch |
| Agent | AGENT_CMD | Status | Notes |
|---|---|---|---|
| Pi | pi (default) |
✅ Works | v0.79.6 |
| Codex CLI | codex |
✅ Works | v0.140.0 |
| Amp | amp |
Requires glibc (not Alpine's musl) |
Switch agents by setting AGENT_CMD in .env:
# .env
AGENT_CMD=codex
AGENT_ARGS=
WEB_SERVER_PASSWORD=your-password# Default (agent in tmux + SSH, detached)
./start.sh
# With web IDE server
./start.sh --web
# In foreground
./start.sh --foreground
# With a specific agent
AGENT_CMD=codex ./start.sh./start.sh --stop./start.sh --shell./start.sh --build# Locally
./start.sh --attach
# Via SSH
ssh -p 2222 opencode@localhost
tmux attach -t agent
# Via docker exec
docker exec -it containedcode tmux attachDetach from tmux: Ctrl+b then d
| Variable | Default | Description |
|---|---|---|
AGENT_CMD |
pi |
Agent command (pi, codex, amp, etc.) |
AGENT_ARGS |
— | Extra arguments for the agent |
WEB_SERVER_PASSWORD |
— | Web IDE password (enables the server) |
WEB_SERVER_ENABLED |
auto |
Force enable/disable web server |
PORT |
8888 |
Web server port |
SSH_PORT |
2222 |
SSH host port |
AGENT_CONFIG_DIR |
~/.pi |
Agent config directory |
WEB_CONFIG_DIR |
~/.config/opencode |
Web IDE config directory |
SSH_AUTHORIZED_KEYS |
~/.ssh/authorized_keys |
SSH public keys file |
AUTO_UPDATE |
true |
Auto-update opencode on start |
Legacy OPENCODE_SERVER_* and PI_* variables are also supported.
Copy .env.example to .env and configure:
# Minimal setup for remote access
WEB_SERVER_PASSWORD=your-password
SSH_AUTHORIZED_KEYS=~/.ssh/authorized_keysThe web IDE (OpenCode) expects a config file at ~/.config/opencode/opencode.json:
{
"$schema": "https://opencode.ai/config.json",
"model": "anthropic/claude-sonnet-4-5"
}A minimal config is auto-created if missing.
# Copy a project into workspace (isolated copy)
./project.sh copy ~/projects/my-app
# Mount a project (live sync)
./project.sh mount ~/projects/my-app
./project.sh apply # Generate docker-compose.override.yml./project.sh list # List all projects
./project.sh create new-project # Create new project
./project.sh shell my-app # Open shell in project
./project.sh remove my-app # Remove project| Category | Tools |
|---|---|
| Languages | Node.js 22, Python 3.12, Go 1.24, Rust, Bun |
| Databases | PostgreSQL client, Redis CLI, MongoDB tools, SQLite |
| Build | Make, CMake, GCC, pkg-config |
| Version Control | Git, GitHub CLI |
| Network | curl, wget, jq, yq |
| Editors | nano, vim |
| System | htop, tmux, procps, coreutils |
| Package Manager | Nix (80,000+ packages), bun (Node.js), uv (Python) |
| LSP Servers | TypeScript, Pyright, gopls, rust-analyzer, lua-language-server, nixd, yaml-language-server, bash-language-server, dockerfile-language-server-nodejs, biome, vscode-langservers-extracted |
-
Add your public key to
~/.ssh/authorized_keyson the host:echo 'ssh-ed25519 AAAA...' >> ~/.ssh/authorized_keys
-
Connect from another machine:
ssh -p 2222 opencode@your-server-ip
-
Attach to the agent:
tmux attach -t agent
Inside the container (or via the agent), install any of 80,000+ Nix packages:
nix profile install nixpkgs#ripgrep
nix profile install nixpkgs#terraform
nix profile install nixpkgs#awscli2Or use bun for Node.js tools:
bun install -g <package>Container (containedcode)
├── tmux session "agent"
│ └── Agent process (pi, codex, amp, ...)
├── SSH daemon (port 2222)
├── Web IDE server (port 8888, optional)
├── Nix package manager
└── Pre-installed dev tools
All processes run as non-root user opencode (UID 1000). The container persists Nix packages, tool caches, and agent data across restarts via named Docker volumes.
- No host access — only the workspace directory is mounted.
- Read-only config —
opencode.jsonis mounted read-only. - Non-root user — all processes run as UID 1000.
- Password required — web IDE requires authentication.
- Key-based SSH only — no password authentication.
- No new privileges — container cannot gain additional capabilities.
# Using Docker compose (Alpine-based)
docker compose build
# Using Nix
nix build .#default
docker load < resultMIT License — See LICENSE for details.