Run OpenCode inside a Docker container so it can only touch your project files — not your SSH keys, not your home directory, not your system. Supports 75+ AI providers including Claude, GPT, Gemini, Groq, and local models via Ollama.
- Why This Matters
- Quick Start
- Authentication
- Sessions & Memory
- Configure Providers
- Configuration Reference
- Security
- Tips & Recipes
- Cleanup
- Project Structure
Running AI coding agents with full permissions on your host system poses risks:
- Accidental access to sensitive files (SSH keys, credentials, personal data)
- Unintended system modifications
- Lack of reproducible development environments
This Docker setup provides:
- File system isolation — agent only sees the mounted workspace directory
- No host file access — SSH keys, home directory, and system files are protected
- Persistent memory — auth tokens and session history survive container restarts
- Easy reset — destroy and rebuild anytime without affecting your system
- Reproducible environment — same setup across different machines
- Non-root execution — runs as unprivileged user inside container
- Docker Engine 20.10+ and Docker Compose 2.0+
- At least one of: Anthropic, OpenAI, Gemini, Groq, OpenRouter API key/subscription, or local Ollama
git clone <repository-url>
cd opencode-docker
./scripts/setup.sh./scripts/run.shThis drops you into a shell inside the container. Your project files are at /workspace.
Option A — OAuth (recommended for Claude Pro/Max subscribers):
# Inside the container:
opencode auth loginA URL is printed. Open it in your browser, log in, and you're done. Your token is saved to ./data/share/auth.json on the host and persists across container restarts — you only need to do this once.
Option B — API key:
# On the host, edit .env and add your key:
ANTHROPIC_API_KEY=sk-ant-...Restart the container and the key is automatically available inside.
# Inside the container:
opencodeOpenCode opens its TUI. Select a model and start chatting.
OAuth lets you use your subscription credits instead of per-token API billing.
# Inside the container:
opencode auth loginThe token is stored in ./data/share/auth.json (bind-mounted to /home/opencode/.local/share/opencode/auth.json inside the container). It survives docker stop / docker start and container recreation.
To check your current auth status:
# Inside the container:
opencode authTo log out:
opencode auth logoutSet one or more keys in .env on the host (copy from .env.example):
ANTHROPIC_API_KEY=sk-ant-...
OPENAI_API_KEY=sk-...
GEMINI_API_KEY=...
GROQ_API_KEY=gsk_...
OPENROUTER_API_KEY=sk-or-...
GITHUB_TOKEN=ghp_...Keys are injected as environment variables every time the container starts. No rebuild needed.
OpenCode stores all conversation history, sessions, and state in a SQLite database. In this Docker setup everything lives under ./data/share/ on the host (outside the container), so it is fully persistent across restarts.
Important distinction: The container has two separate bind mounts:
./workspace/→/workspace— your project files (what the agent edits)./data/share/→/home/opencode/.local/share/opencode/— opencode's persistent data (auth, sessions, logs)Even though the container's working directory is
/workspace, opencode writes all its own state to the second mount. The two are completely independent. Stopping or recreating the container affects neither.
data/ ← lives on the HOST, never inside the container image
└── share/ ← mounted to ~/.local/share/opencode/ inside container
├── auth.json ← OAuth tokens (survives restarts)
├── opencode.db ← all sessions, messages, and project state
├── opencode.db-shm ← SQLite WAL shared memory (auto-managed)
├── opencode.db-wal ← SQLite write-ahead log (auto-managed)
├── log/ ← timestamped log files (one per run, survive restarts)
│ └── 2026-03-14T160557.log
└── storage/
├── session/ ← per-session metadata
├── message/ ← message history
└── part/ ← message parts / tool outputs
Nothing is lost when you stop, restart, or recreate the container, as long as you do not run ./scripts/cleanup.sh --full (which deletes data/).
When you launch opencode in the TUI, recent sessions are listed on the left-hand sidebar. Select any session to continue the conversation exactly where you left off.
View recent log files to see what happened in past sessions:
# List all run logs, newest first:
ls -lt data/share/log/
# Tail the most recent log:
tail -f data/share/log/$(ls -t data/share/log/ | head -1)Query the database directly with SQLite (if you have it installed on the host):
sqlite3 data/share/opencode.db \
"SELECT id, title, created_at FROM session ORDER BY created_at DESC LIMIT 10;"Or from inside the container (SQLite is available via the opencode binary's bun runtime):
# Inside the container — list sessions:
ls ~/.local/share/opencode/storage/session/# On the host — delete only the database, keep auth:
rm data/share/opencode.db data/share/opencode.db-shm data/share/opencode.db-walOpenCode will create a fresh database on next startup.
OpenCode detects providers automatically from environment variables set in .env.
| Provider | Environment Variable |
|---|---|
| Anthropic (Claude) | ANTHROPIC_API_KEY or opencode auth login |
| OpenAI (GPT) | OPENAI_API_KEY |
| Google Gemini | GEMINI_API_KEY |
| Groq | GROQ_API_KEY |
| OpenRouter (75+ models) | OPENROUTER_API_KEY |
| GitHub Copilot | GITHUB_TOKEN |
| Local (Ollama) | OLLAMA_HOST or LOCAL_ENDPOINT |
| Azure OpenAI | AZURE_OPENAI_ENDPOINT + AZURE_OPENAI_API_KEY |
| AWS Bedrock | AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY + AWS_REGION |
The container uses network_mode: host, so it can reach Ollama running on your machine directly.
- Install and run Ollama on your host
- Pull a model:
ollama pull qwen2.5-coder:7b - In
.env, set:OLLAMA_HOST=http://localhost:11434 - Local models are pre-configured in
data/config/opencode.json
opencode-docker/
├── .env ← your API keys and settings (gitignored)
├── .env.example ← template — copy to .env
├── Dockerfile ← container image definition
├── docker-compose.yml ← compose config
├── entrypoint.sh ← container startup script
├── workspace/ ← YOUR PROJECT FILES (mounted at /workspace)
├── data/
│ ├── config/ ← opencode config (opencode.json, plugins)
│ │ └── opencode.json ← provider/model configuration
│ └── share/ ← persistent state (auth, db, logs)
│ ├── auth.json ← OAuth tokens
│ ├── opencode.db ← session & message history
│ └── log/ ← run logs
└── scripts/
├── setup.sh ← build the Docker image
├── run.sh ← run the container interactively
├── clipboard.sh ← clipboard helpers
└── cleanup.sh ← stop / full teardown
# API Keys
ANTHROPIC_API_KEY=sk-ant-...
OPENAI_API_KEY=sk-...
GEMINI_API_KEY=...
GROQ_API_KEY=gsk_...
OPENROUTER_API_KEY=sk-or-...
GITHUB_TOKEN=ghp_...
# Local Ollama (container uses host network, so localhost works)
OLLAMA_HOST=http://localhost:11434
# Azure OpenAI
AZURE_OPENAI_ENDPOINT=https://myresource.openai.azure.com
AZURE_OPENAI_API_KEY=...
AZURE_OPENAI_API_VERSION=2024-02-15-preview
# AWS Bedrock
AWS_ACCESS_KEY_ID=...
AWS_SECRET_ACCESS_KEY=...
AWS_REGION=us-east-1
# Use a different project directory (default: ./workspace)
WORKSPACE_PATH=./workspaceEdit this file to add custom providers or tune model options. It is mounted into the container at /home/opencode/.config/opencode/opencode.json. Changes take effect on the next container start — no rebuild needed.
| Flag | Description |
|---|---|
--workspace PATH |
Mount a different directory as /workspace |
--run |
Launch the OpenCode TUI immediately on startup |
--network-host |
Enable host networking (required for Ollama) |
--no-clipboard |
Skip X11 clipboard mounting |
~/.ssh, home directory, and all host files outside/workspaceare not accessible to the agent- Runs as non-root user (UID 1001)
- no-new-privileges security option enabled
network_mode: host— container can reach localhost services (Ollama, etc.)- Files in
/workspaceare read-write by the agent ./data/is bind-mounted read-write (persists auth + sessions)
# In docker-compose.yml, replace network_mode:
network_mode: "none"./scripts/run.sh --workspace ~/my-other-projectSessions are stored per-project in the database, so history for each project is kept separately.
./scripts/run.sh --rundocker compose up -d # start in background
docker compose exec opencode bash # open a shell
docker compose down # stopEdit Dockerfile and rebuild:
RUN apt-get update && apt-get install -y your-tool./scripts/setup.sh # rebuilds the image
./scripts/run.sh# On the host:
ls -lt data/share/log/ # all runs, newest first
cat data/share/log/<timestamp>.logLog lines include the service name, timing, and the opencode version used.
# Stop the running container (data is preserved):
docker compose down
# Full teardown — removes image, stops containers.
# WARNING: also deletes data/ (auth tokens + all session history):
./scripts/cleanup.sh --fullIf you want to reset sessions but keep your auth token:
rm data/share/opencode.db data/share/opencode.db-shm data/share/opencode.db-walopencode-docker/
├── Dockerfile # Ubuntu 24.04 + opencode-ai npm package
├── entrypoint.sh # Startup: terminal fix + welcome banner
├── docker-compose.yml # Two profiles: default (host network) + isolated
├── .env.example # All supported config variables
├── workspace/ # Your project files (git-tracked separately)
├── data/
│ ├── config/ # opencode.json — provider/model config
│ └── share/ # auth.json, opencode.db, logs (gitignored)
└── scripts/
├── setup.sh # Build image
├── run.sh # Run container (docker run wrapper)
├── clipboard.sh # X11 clipboard helpers
└── cleanup.sh # Stop / full teardown