2026-04-14 20:11:24 +02:00
# docker-claude
Runs [Claude Code ](https://claude.ai/code ) inside an isolated Docker environment with a proxy sidecar for controlled egress. Claude cannot reach the host filesystem or network directly.
## Architecture
```
2026-04-14 22:25:38 +02:00
┌──────────────────────────────────────────────────────────┐
│ 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) │
└──────────────────────────────────────────────────────────┘
2026-04-14 20:11:24 +02:00
```
2026-04-14 22:25:38 +02:00
- **`claude` ** — Claude Code CLI, UID 1000, on `claude-internal` only
- **`webui` ** — Claude Code in a browser terminal (ttyd), UID 1000, on `claude-internal` only, port 7681
- **`proxy` ** — Squid forward proxy, UID 13, bridges `claude-internal` ↔ internet with egress allowlist
- **`claude-internal` ** — `internal: true` ; no default gateway, containers cannot reach the internet directly
- **`proxy-external` ** — Standard bridge; proxy sidecar only
2026-04-14 20:11:24 +02:00
## Prerequisites
- Docker Engine 24+
- Docker Compose v2 plugin (`docker compose version` )
## Setup
```bash
# 1. Clone / copy this repo
git clone < repo > docker-claude & & cd docker-claude
2026-04-14 22:25:38 +02:00
# 2. Configure credentials
2026-04-14 20:11:24 +02:00
cp .env.example .env
2026-04-14 22:25:38 +02:00
$EDITOR .env # set ANTHROPIC_API_KEY (and WEBUI_PASSWORD if using web mode)
2026-04-14 20:11:24 +02:00
# 3. Make the control script executable
chmod +x claude.sh
```
## Usage
2026-04-14 22:25:38 +02:00
### CLI mode
2026-04-14 20:11:24 +02:00
```bash
# Build images, start proxy, launch Claude Code interactively
./claude.sh start
2026-04-14 22:25:38 +02:00
# Start proxy if needed, launch Claude Code (faster on subsequent runs)
2026-04-14 20:11:24 +02:00
./claude.sh run
2026-04-14 22:25:38 +02:00
# Mount a host directory as the workspace
WORKSPACE_DIR=$HOME/myproject ./claude.sh run
```
2026-04-14 20:11:24 +02:00
2026-04-14 22:25:38 +02:00
### Web interface
2026-04-14 20:11:24 +02:00
2026-04-14 22:25:38 +02:00
Serves Claude Code as a browser terminal via [ttyd ](https://github.com/tsl0922/ttyd ), protected by HTTP basic auth.
2026-04-14 20:11:24 +02:00
2026-04-14 22:25:38 +02:00
```bash
# Add to .env first:
# WEBUI_PASSWORD=your-strong-password
# WEBUI_USER=claude # optional, defaults to "claude"
2026-04-14 20:11:24 +02:00
2026-04-14 22:25:38 +02:00
./claude.sh web
# → Web interface running at http://0.0.0.0:7681
2026-04-14 20:11:24 +02:00
2026-04-14 22:25:38 +02:00
# To reach it from outside the sandbox host:
sbx ports < sandbox-name > --publish 7681:7681/tcp
2026-04-14 20:11:24 +02:00
2026-04-14 22:25:38 +02:00
# Stop web interface (keeps proxy running)
./claude.sh web-stop
```
2026-04-14 20:11:24 +02:00
2026-04-14 22:25:38 +02:00
### Other commands
2026-04-14 20:11:24 +02:00
```bash
2026-04-14 22:25:38 +02:00
./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
2026-04-14 20:11:24 +02:00
```
2026-04-14 22:25:38 +02:00
### Workspace
| Mode | Default | Override |
|---|---|---|
| CLI (`run` /`start` ) | Named Docker volume (isolated) | `WORKSPACE_DIR=/path ./claude.sh run` |
| Web (`web` ) | Named Docker volume (`claude-web-workspace` ) | Edit `docker-compose.yml` volumes |
2026-04-14 20:11:24 +02:00
## Egress allowlist
Edit `proxy/squid.conf` and add domains to the `allowed_sites` ACL:
2026-04-14 22:25:38 +02:00
```
2026-04-14 20:11:24 +02:00
acl allowed_sites dstdomain api.anthropic.com
acl allowed_sites dstdomain statsig.anthropic.com
2026-04-14 22:25:38 +02:00
# acl allowed_sites dstdomain api.github.com
2026-04-14 20:11:24 +02:00
# acl allowed_sites dstdomain registry.npmjs.org
```
2026-04-14 22:25:38 +02:00
Rebuild after changes:
2026-04-14 20:11:24 +02:00
```bash
2026-04-14 22:25:38 +02:00
./claude.sh update
2026-04-14 20:11:24 +02:00
./claude.sh stop & & ./claude.sh start
```
## Security controls
2026-04-14 22:25:38 +02:00
| Control | claude / webui | proxy |
2026-04-14 20:11:24 +02:00
|---|---|---|
| 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 |
2026-04-14 22:25:38 +02:00
| Web auth | basic auth (ttyd `--credential` ) | n/a |