diff --git a/README.md b/README.md index bdcab50..f87d6d2 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # 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. +Runs [Claude Code](https://claude.ai/code) inside an isolated Docker environment with a proxy sidecar for controlled egress. Claude cannot access the host filesystem or network directly. ## Architecture @@ -14,15 +14,13 @@ Runs [Claude Code](https://claude.ai/code) inside an isolated Docker environment │ ┌──────────────────────────────────────────────────┐ │ │ │ Docker: claude-secure │ │ │ │ │ │ -│ │ ┌─────────────┐ │ │ -│ │ │ claude │──┐ claude-internal │ │ -│ │ │ (UID 1000) │ │ (internal: true) │ │ -│ │ └─────────────┘ ├──────────────► ┌──────────┐ │ │ -│ │ ┌─────────────┐ │ │ proxy │ │ │ -│ │ │ webui │──┘ │ (UID 13) │ │ │ -│ │ │ (UID 1000) │ └────┬─────┘ │ │ -│ │ │ port 7681 │ proxy-external │ │ -│ │ └─────────────┘ │ │ │ +│ │ ┌─────────────┐ claude-internal │ │ +│ │ │ claude │ (internal: true) │ │ +│ │ │ (UID 1000) │──────────────► ┌──────────┐ │ │ +│ │ └─────────────┘ │ proxy │ │ │ +│ │ │ (UID 13) │ │ │ +│ │ └────┬─────┘ │ │ +│ │ proxy-external │ │ │ └──────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ @@ -31,7 +29,6 @@ Runs [Claude Code](https://claude.ai/code) inside an isolated Docker environment ``` - **`claude`** — Claude Code CLI (`node:20-alpine`), runs as the built-in `node` user (UID 1000), on `claude-internal` only -- **`webui`** — Claude Code in a browser terminal via ttyd (`node:20-alpine`), `node` user (UID 1000), on `claude-internal` only, port 7681 - **`proxy`** — Squid forward proxy (`alpine:3.21`), 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 @@ -84,40 +81,15 @@ Port 54545 must be reachable from your browser for the OAuth callback: sbx ports --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. +Then run `./claude.sh start` and follow the prompt. Credentials are stored in +`~/.claude` on the host and reused on every subsequent run. ## Usage -### CLI mode - ```bash -# Start proxy, launch Claude Code in the current directory -# (pulls images from registry.zeidler.dev on first run) +# Start proxy, pull latest images, launch Claude Code in the current directory cd ~/myproject ./claude.sh start - -# Start proxy if needed, launch Claude Code -./claude.sh run -``` - -### Web interface - -Serves Claude Code as a browser terminal via [ttyd](https://github.com/tsl0922/ttyd), protected by HTTP basic auth. - -```bash -# 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 --publish 7681:7681/tcp - -# Stop web interface (keeps proxy running) -./claude.sh web-stop ``` ### Other commands @@ -126,27 +98,19 @@ sbx ports --publish 7681:7681/tcp ./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 logs webui # Tail web interface logs ./claude.sh status # Show container status ./claude.sh shell # Debug bash shell in the Claude container ``` ### Building locally -`build.sh` builds both images from source using the local Dockerfiles: +`build.sh` builds images from source using the local Dockerfiles: ```bash ./build.sh # build with layer cache ./build.sh --no-cache # force full rebuild ``` -### 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: @@ -161,18 +125,16 @@ acl allowed_sites dstdomain statsig.anthropic.com Rebuild after changes: ```bash -./claude.sh update ./claude.sh stop && ./claude.sh start ``` ## Security controls -| Control | claude / webui | proxy | +| 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` (CLI only) | none | +| Host filesystem | CWD mounted as `/workspace` | none | | Docker socket | not mounted | not mounted | -| Web auth | basic auth (ttyd `--credential`) | n/a |