refactor(docker): migrate both images to Alpine

Replace node:20-slim/ubuntu:22.04 with node:20-alpine/alpine:3.21.
Switch package management from apt to apk (--no-cache, no cleanup layer).
Use Alpine addgroup/adduser in claude/Dockerfile. Update proxy to use
squid user (Alpine convention) and /var/cache/squid cache path.
Fix proxy/Dockerfile COPY path now that context is proxy/. Move
webui-entrypoint.sh into claude/ to match its build context. Fix
docker-compose.yml webui context to claude/, update proxy tmpfs path.
This commit is contained in:
docker-claude 2026-04-14 22:40:57 +02:00
parent 782370e014
commit 88805a3c24
9 changed files with 53 additions and 57 deletions

View file

@ -10,13 +10,13 @@ This file provides context and guidance for working with this project.
Three containers managed by Docker Compose:
- **`claude`** — Claude Code CLI, non-root (UID 1000), isolated to an internal-only Docker network
- **`webui`** — Claude Code as a browser terminal (ttyd on port 7681), same image as `claude`, non-root (UID 1000), same network isolation, basic auth required
- **`proxy`** — Squid forward proxy, non-root (UID 13), bridges the internal network to the internet with an egress allowlist
- **`claude`** — Claude Code CLI (`node:20-alpine`), non-root (UID 1000), isolated to an internal-only Docker network
- **`webui`** — Claude Code as a browser terminal via ttyd (`node:20-alpine`), non-root (UID 1000), same network isolation, basic auth required
- **`proxy`** — Squid forward proxy (`alpine:3.21`), `squid` user, bridges the internal network to the internet with an egress allowlist
Key Docker network property: `claude-internal` has `internal: true`, meaning Docker adds no default gateway. The `claude` and `webui` containers physically cannot reach the internet without going through the `proxy` container.
The `webui` service reuses `Dockerfile.claude`. Its entrypoint (`webui-entrypoint.sh`) starts `ttyd --credential user:pass claude` instead of `claude` directly.
The `webui` service reuses `claude/Dockerfile`. Its entrypoint (`claude/webui-entrypoint.sh`) starts `ttyd --credential user:pass claude` instead of `claude` directly.
## File Structure
@ -24,10 +24,11 @@ The `webui` service reuses `Dockerfile.claude`. Its entrypoint (`webui-entrypoin
docker-claude/
├── claude.sh # Control script: start/stop/run/web/web-stop/update/logs/status/shell
├── docker-compose.yml # Service definitions and network topology
├── Dockerfile.claude # Claude Code + ttyd container (node:20-slim, UID 1000)
├── Dockerfile.proxy # Squid proxy sidecar (ubuntu:22.04, UID 13)
├── webui-entrypoint.sh # Entrypoint for webui service: starts ttyd wrapping claude
├── claude/
│ ├── Dockerfile # Claude Code + ttyd (node:20-alpine, UID 1000)
│ └── webui-entrypoint.sh # Entrypoint for webui: starts ttyd wrapping claude
├── proxy/
│ ├── Dockerfile # Squid proxy sidecar (alpine:3.21, squid user)
│ └── squid.conf # Squid ACL config — egress allowlist lives here
├── .env.example # Template for ANTHROPIC_API_KEY, WEBUI_PASSWORD, etc.
├── .gitignore # Excludes .env and logs
@ -48,7 +49,8 @@ cp .env.example .env # set ANTHROPIC_API_KEY (and WEBUI_PASSWORD for web mo
## Coding Standards
- Shell scripts use `set -euo pipefail`
- Dockerfiles use `--no-install-recommends` and clean apt caches in the same layer
- Dockerfiles use Alpine (`node:20-alpine`, `alpine:3.21`) for minimal attack surface
- Alpine packages use `apk add --no-cache`; no apt cache cleanup layer needed
- No capabilities granted; `no-new-privileges` on all containers
- `.env` is never committed (enforced by `.gitignore` and `.dockerignore`)
- Commit messages follow **Angular format**: `type(scope): summary`