services: # ─── Proxy sidecar ───────────────────────────────────────────────────────── # Bridges the isolated internal network to the internet. # Enforces an egress allowlist — see proxy/squid.conf. proxy: image: registry.zeidler.dev/docker-public/playground/docker-claude-proxy:${IMAGE_TAG:-latest} networks: - claude-internal # reachable by claude container - proxy-external # has outbound internet access restart: unless-stopped security_opt: - no-new-privileges:true cap_drop: - ALL read_only: true tmpfs: - /tmp - /var/cache/squid - /var/log/squid # ─── Claude Code CLI container ───────────────────────────────────────────── # No direct internet access. All egress routes through the proxy sidecar. # Run via "docker compose run --rm --service-ports claude" (managed by claude.sh). claude: image: registry.zeidler.dev/docker-public/playground/docker-claude-claude:${IMAGE_TAG:-latest} depends_on: proxy: condition: service_healthy networks: - claude-internal # only — no route to the internet environment: - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-} - CLAUDE_CODE_OAUTH_TOKEN=${CLAUDE_CODE_OAUTH_TOKEN:-} - HTTP_PROXY=http://proxy:3128 - HTTPS_PROXY=http://proxy:3128 - ALL_PROXY=http://proxy:3128 - NO_PROXY=localhost,127.0.0.1 ports: # OAuth callback — required for browser-based login (claude login) - "0.0.0.0:54545:54545" volumes: - ${HOME}/.claude:/home/node/.claude # Workspace is injected by claude.sh via --volume flag at run time (current directory). security_opt: - no-new-privileges:true cap_drop: - ALL stdin_open: true tty: true networks: # Internal-only: Docker adds no default gateway → no direct internet route claude-internal: driver: bridge internal: true # External: standard bridge with internet access (proxy only) proxy-external: driver: bridge