Run from the project directory you want to work on; claude.sh mounts it automatically. Removes WORKSPACE_DIR env var support and the named claude-secure-workspace Docker volume. |
||
|---|---|---|
| claude | ||
| proxy | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| CLAUDE.md | ||
| claude.sh | ||
| docker-compose.yml | ||
| README.md | ||
docker-claude
Runs Claude Code inside an isolated Docker environment with a proxy sidecar for controlled egress. Claude cannot reach the host filesystem or network directly.
Architecture
┌──────────────────────────────────────────────────────────┐
│ Host machine │
│ │
│ claude.sh (control script) │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Docker: claude-secure │ │
│ │ │ │
│ │ ┌─────────────┐ │ │
│ │ │ claude │──┐ claude-internal │ │
│ │ │ (UID 1000) │ │ (internal: true) │ │
│ │ └─────────────┘ ├──────────────► ┌──────────┐ │ │
│ │ ┌─────────────┐ │ │ proxy │ │ │
│ │ │ webui │──┘ │ (UID 13) │ │ │
│ │ │ (UID 1000) │ └────┬─────┘ │ │
│ │ │ port 7681 │ proxy-external │ │
│ │ └─────────────┘ │ │ │
│ └──────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ internet (allowlisted) │
└──────────────────────────────────────────────────────────┘
claude— Claude Code CLI (node:20-alpine), runs as the built-innodeuser (UID 1000), onclaude-internalonlywebui— Claude Code in a browser terminal via ttyd (node:20-alpine),nodeuser (UID 1000), onclaude-internalonly, port 7681proxy— Squid forward proxy (alpine:3.21), bridgesclaude-internal↔ internet with egress allowlistclaude-internal—internal: true; no default gateway, containers cannot reach the internet directlyproxy-external— Standard bridge; proxy sidecar only
Prerequisites
- Docker Engine 24+
- Docker Compose v2 plugin (
docker compose version)
Setup
# 1. Clone / copy this repo
git clone <repo> docker-claude && cd docker-claude
# 2. Configure credentials (see Authentication below)
cp .env.example .env
$EDITOR .env
# 3. Make the control script executable
chmod +x claude.sh
Authentication
Three options — pick one and set it in .env:
Option 1 — API key
ANTHROPIC_API_KEY=sk-ant-...
Option 2 — OAuth token (subscription, headless-friendly)
Run this on your host (not inside the container) to generate a 1-year token:
claude setup-token
Then set the printed token in .env:
CLAUDE_CODE_OAUTH_TOKEN=...
Option 3 — Browser OAuth (interactive)
Leave both keys unset. On first run, Claude Code will print a login URL. Port 54545 must be reachable from your browser for the OAuth callback:
sbx ports <sandbox-name> --publish 54545:54545/tcp
Then run ./claude.sh run and follow the prompt. Credentials are stored in the
claude-config Docker volume and reused on every subsequent run.
Usage
CLI mode
# Build images, start proxy, launch Claude Code in the current directory
cd ~/myproject
./claude.sh start
# Start proxy if needed, launch Claude Code (faster on subsequent runs)
./claude.sh run
Web interface
Serves Claude Code as a browser terminal via ttyd, protected by HTTP basic auth.
# Add to .env first:
# WEBUI_PASSWORD=your-strong-password
# WEBUI_USER=claude # optional, defaults to "claude"
./claude.sh web
# → Web interface running at http://0.0.0.0:7681
# To reach it from outside the sandbox host:
sbx ports <sandbox-name> --publish 7681:7681/tcp
# Stop web interface (keeps proxy running)
./claude.sh web-stop
Other commands
./claude.sh stop # Stop and remove all containers
./claude.sh update # Rebuild images without cache
./claude.sh logs # Tail proxy logs
./claude.sh logs webui # Tail web interface logs
./claude.sh status # Show container status
./claude.sh shell # Debug bash shell in the Claude container
Workspace
| Mode | Workspace |
|---|---|
CLI (run/start) |
Current working directory (mounted as /workspace) |
Web (web) |
Named Docker volume (claude-web-workspace) |
Egress allowlist
Edit proxy/squid.conf and add domains to the allowed_sites ACL:
acl allowed_sites dstdomain api.anthropic.com
acl allowed_sites dstdomain statsig.anthropic.com
# acl allowed_sites dstdomain api.github.com
# acl allowed_sites dstdomain registry.npmjs.org
Rebuild after changes:
./claude.sh update
./claude.sh stop && ./claude.sh start
Security controls
| Control | claude / webui | proxy |
|---|---|---|
| Non-root user | UID 1000 (node, built into base image) |
squid user |
no-new-privileges |
yes | yes |
| All capabilities dropped | yes | yes |
| Direct internet access | no (internal network only) |
allowlisted only |
| Host filesystem | CWD mounted as /workspace (CLI only) |
none |
| Docker socket | not mounted | not mounted |
| Web auth | basic auth (ttyd --credential) |
n/a |