4.5 KiB
4.5 KiB
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-internal │ │
│ │ │ claude │◄─────(internal only)───► │ │
│ │ │ (UID 1000) │ │ │ │
│ │ └─────────────┘ ┌──────┴──────┐ │ │
│ │ │ proxy │ │ │
│ │ │ (UID 13) │ │ │
│ │ └──────┬──────┘ │ │
│ │ proxy-external │ │
│ └─────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ internet (allowlisted) │
└─────────────────────────────────────────────────────┘
claudecontainer — Claude Code, runs as UID 1000, onclaude-internalonly (no internet route)proxycontainer — Squid forward proxy, runs as UID 13, bridgesclaude-internal↔ internet, enforces egress allowlistclaude-internal— Docker bridge withinternal: true; Docker adds no default gateway, so containers on this network cannot reach the internet directlyproxy-external— Standard bridge; the proxy sidecar uses this for controlled outbound access
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 your API key
cp .env.example .env
$EDITOR .env # set ANTHROPIC_API_KEY
# 3. Make the control script executable
chmod +x claude.sh
Usage
# Build images, start proxy, launch Claude Code interactively
./claude.sh start
# Same as start but skips image rebuild (faster on subsequent runs)
./claude.sh run
# Stop and remove all containers (proxy + any running sessions)
./claude.sh stop
# Rebuild images without cache (e.g. after Claude Code updates)
./claude.sh update
# Tail proxy access logs
./claude.sh logs
# Show container status
./claude.sh status
# Open a debug bash shell inside the Claude container
./claude.sh shell
Working with host files
By default, Claude's workspace is a named Docker volume (claude-secure-workspace) — fully isolated from the host.
To mount a specific host directory:
WORKSPACE_DIR=$HOME/myproject ./claude.sh run
The directory is mounted at /workspace inside the container.
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 # uncomment if needed
# acl allowed_sites dstdomain registry.npmjs.org
Rebuild the proxy after changes:
docker compose -p claude-secure build proxy
./claude.sh stop && ./claude.sh start
Security controls
| Control | Claude container | Proxy container |
|---|---|---|
| Non-root user | UID 1000 (claude) |
UID 13 (proxy) |
no-new-privileges |
yes | yes |
| All capabilities dropped | yes | yes |
| Direct internet access | no (internal network only) |
allowlisted only |
| Host filesystem | no mounts by default | none |
| Docker socket | not mounted | not mounted |