docker-claude/README.md
docker-claude f4cf8056e9 docs(readme): sync with current state after webui removal
Remove webui from architecture, commands, and security table.
Update auth option 3 to reference ~/.claude instead of claude-config volume.
Drop stale registry path comment and web interface section.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 22:41:28 +02:00

5.1 KiB

docker-claude

Runs Claude Code inside an isolated Docker environment with a proxy sidecar for controlled egress. Claude cannot access the host filesystem or network directly.

Architecture

┌──────────────────────────────────────────────────────────┐
│  Host machine                                            │
│                                                          │
│  claude.sh (control script)                              │
│       │                                                  │
│       ▼                                                  │
│  ┌──────────────────────────────────────────────────┐   │
│  │  Docker: claude-secure                           │   │
│  │                                                  │   │
│  │  ┌─────────────┐    claude-internal              │   │
│  │  │  claude     │    (internal: true)             │   │
│  │  │  (UID 1000) │──────────────► ┌──────────┐    │   │
│  │  └─────────────┘                │  proxy   │    │   │
│  │                                 │ (UID 13) │    │   │
│  │                                 └────┬─────┘    │   │
│  │                             proxy-external       │   │
│  └──────────────────────────────────────────────────┘   │
│                                            │             │
│                                            ▼             │
│                                 internet (allowlisted)   │
└──────────────────────────────────────────────────────────┘
  • claude — Claude Code CLI (node:20-alpine), runs as the built-in node user (UID 1000), on claude-internal only
  • proxy — Squid forward proxy (alpine:3.21), bridges claude-internal ↔ internet with egress allowlist
  • claude-internalinternal: true; no default gateway, containers cannot reach the internet directly
  • proxy-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 start and follow the prompt. Credentials are stored in ~/.claude on the host and reused on every subsequent run.

Usage

# Start proxy, pull latest images, launch Claude Code in the current directory
cd ~/myproject
./claude.sh start

Other commands

./claude.sh stop          # Stop and remove all containers
./claude.sh update        # Pull latest images from the registry
./claude.sh logs          # Tail proxy logs
./claude.sh status        # Show container status
./claude.sh shell         # Debug bash shell in the Claude container

Building locally

build.sh builds images from source using the local Dockerfiles:

./build.sh              # build with layer cache
./build.sh --no-cache   # force full rebuild

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 stop && ./claude.sh start

Security controls

Control claude 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 none
Docker socket not mounted not mounted