From e78a302cb9f705946f1def5f29f0521148fec15e Mon Sep 17 00:00:00 2001 From: docker-claude Date: Wed, 15 Apr 2026 21:59:08 +0200 Subject: [PATCH] feat: remove webui --- .env.example | 6 ----- CLAUDE.md | 13 +++------- claude.sh | 30 +++------------------- claude/Dockerfile | 6 +---- claude/webui-entrypoint.sh | 14 ---------- docker-compose.yml | 52 +------------------------------------- 6 files changed, 9 insertions(+), 112 deletions(-) delete mode 100644 claude/webui-entrypoint.sh diff --git a/.env.example b/.env.example index 9b353cd..ad79c7b 100644 --- a/.env.example +++ b/.env.example @@ -19,12 +19,6 @@ # Port 54545 must be reachable from your browser for the OAuth callback. # Run: sbx ports --publish 54545:54545/tcp -# ─── Web interface ──────────────────────────────────────────────────────────── - -# Required for ./claude.sh web -# WEBUI_USER=claude -# WEBUI_PASSWORD=changeme - # ─── MCP servers (all optional) ─────────────────────────────────────────────── # GitHub — PAT with repo scope diff --git a/CLAUDE.md b/CLAUDE.md index 876db89..687a431 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -8,16 +8,13 @@ This file provides context and guidance for working with this project. ## Architecture -Three containers managed by Docker Compose: +Two containers managed by Docker Compose: - **`claude`** — Claude Code CLI (`node:20-alpine`), runs as the built-in `node` user (UID 1000), isolated to an internal-only Docker network -- **`webui`** — Claude Code as a browser terminal via ttyd (`node:20-alpine`), `node` user (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 `claude/Dockerfile`. Its entrypoint (`claude/webui-entrypoint.sh`) starts `ttyd --credential user:pass claude` instead of `claude` directly. - Auth supports three modes (checked at startup by `claude.sh`): - `ANTHROPIC_API_KEY` — API key - `CLAUDE_CODE_OAUTH_TOKEN` — 1-year token from `claude setup-token` (headless-friendly) @@ -27,11 +24,10 @@ Auth supports three modes (checked at startup by `claude.sh`): ``` docker-claude/ -├── claude.sh # Control script: start/stop/run/web/web-stop/update/logs/status/shell +├── claude.sh # Control script: start/stop/run/update/logs/status/shell ├── docker-compose.yml # Service definitions and network topology ├── claude/ -│ ├── Dockerfile # Claude Code + ttyd (node:20-alpine, UID 1000) -│ └── webui-entrypoint.sh # Entrypoint for webui: starts ttyd wrapping claude +│ └── Dockerfile # Claude Code (node:20-alpine, UID 1000) ├── proxy/ │ ├── Dockerfile # Squid proxy sidecar (alpine:3.21, squid user) │ └── squid.conf # Squid ACL config — egress allowlist lives here @@ -45,9 +41,8 @@ docker-claude/ ```bash chmod +x claude.sh build.sh -cp .env.example .env # set ANTHROPIC_API_KEY (and WEBUI_PASSWORD for web mode) +cp .env.example .env # set ANTHROPIC_API_KEY cd /path/to/project && ./claude.sh start # start proxy + launch Claude (pulls images, mounts CWD) -./claude.sh web # start proxy + webui (browser terminal on :7681) ./claude.sh update # pull latest images from registry ./build.sh # build images locally (development) ``` diff --git a/claude.sh b/claude.sh index 62dcaa6..a78dc25 100755 --- a/claude.sh +++ b/claude.sh @@ -37,6 +37,7 @@ load_env() { fi } +# Wrapper so every docker compose call uses the right file and project name. dc() { docker compose -f "$COMPOSE_FILE" -p "$PROJECT" "$@"; } # ─── Volume args ────────────────────────────────────────────────────────────── @@ -121,32 +122,12 @@ cmd_shell() { dc run --rm --service-ports --entrypoint /bin/bash "${VOLUME_ARGS[@]}" claude } -cmd_web() { - check_deps; load_env - [[ -n "${WEBUI_PASSWORD:-}" ]] \ - || { error "WEBUI_PASSWORD is not set. Add it to .env before starting the web interface."; exit 1; } - info "Pulling latest images..." - dc pull - info "Starting proxy and web interface..." - dc up -d webui - info "Web interface is up → http://0.0.0.0:7681" - info "Credentials: ${WEBUI_USER:-claude} / [WEBUI_PASSWORD]" -} - -cmd_web_stop() { - check_deps - info "Stopping web interface..." - dc stop webui && dc rm -f webui -} - cmd_help() { cat < [args] Commands: start [args] Start proxy, launch Claude Code (CLI) - web Start proxy + web interface (browser terminal on :7681) - web-stop Stop the web interface (keeps proxy running) stop Stop and remove all containers update Pull latest images from the registry logs [svc] Tail logs (default: proxy) @@ -158,16 +139,13 @@ Flags (before the subcommand): --kube Mount \$HOME/.kube read-only at /home/node/.kube (kubectl access) Environment variables (set in .env): - ANTHROPIC_API_KEY API key auth + ANTHROPIC_API_KEY API key auth CLAUDE_CODE_OAUTH_TOKEN OAuth token auth (from 'claude setup-token') - IMAGE_TAG Image tag to use (default: latest) - WEBUI_USER Web interface username (default: claude) - WEBUI_PASSWORD Required for web mode + IMAGE_TAG Image tag to use (default: latest) Examples: cd ~/myproject && ./claude.sh start cd ~/myproject && ./claude.sh --kube start - ./claude.sh web ./claude.sh logs proxy ./claude.sh shell EOF @@ -184,8 +162,6 @@ done case "${1:-help}" in start|run) shift; cmd_start "$@" ;; stop) cmd_stop ;; - web) cmd_web ;; - web-stop) cmd_web_stop ;; update) cmd_update ;; logs) shift; cmd_logs "${1:-}" ;; status) cmd_status ;; diff --git a/claude/Dockerfile b/claude/Dockerfile index 9c6e086..ccede4c 100644 --- a/claude/Dockerfile +++ b/claude/Dockerfile @@ -5,8 +5,7 @@ RUN apk add --no-cache \ git \ curl \ ca-certificates \ - bash \ - ttyd + bash # Install kubectl — architecture-aware, checksum-verified RUN KUBECTL_VERSION=$(curl -fsSL https://dl.k8s.io/release/stable.txt) \ @@ -19,9 +18,6 @@ RUN KUBECTL_VERSION=$(curl -fsSL https://dl.k8s.io/release/stable.txt) \ && rm /tmp/kubectl.sha256 \ && chmod +x /usr/local/bin/kubectl -# Entrypoint used by the webui service (ttyd wrapping claude) -COPY --chmod=755 webui-entrypoint.sh /usr/local/bin/webui-entrypoint.sh - # System-level Claude Code policy — owned by root, not writable by the node user. # Restricts available models; cannot be bypassed via CLI flags or env vars. COPY settings.json /etc/claude-code/managed-settings.json diff --git a/claude/webui-entrypoint.sh b/claude/webui-entrypoint.sh deleted file mode 100644 index 4cf31cd..0000000 --- a/claude/webui-entrypoint.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash -# Entrypoint for the webui service. -# Wraps Claude Code in ttyd (terminal-over-WebSocket) with basic auth. -set -euo pipefail - -: "${WEBUI_PASSWORD:?WEBUI_PASSWORD must be set in .env}" -WEBUI_USER="${WEBUI_USER:-claude}" -WEBUI_PORT="${WEBUI_PORT:-7681}" - -exec ttyd \ - --port "${WEBUI_PORT}" \ - --writable \ - --credential "${WEBUI_USER}:${WEBUI_PASSWORD}" \ - claude diff --git a/docker-compose.yml b/docker-compose.yml index 411b00e..4148250 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,7 +5,7 @@ services: proxy: image: registry.zeidler.dev/docker-public/playground/docker-claude-proxy:${IMAGE_TAG:-latest} networks: - - claude-internal # reachable by claude and webui containers + - claude-internal # reachable by claude container - proxy-external # has outbound internet access restart: unless-stopped security_opt: @@ -55,50 +55,6 @@ services: stdin_open: true tty: true - # ─── Claude Code web interface ───────────────────────────────────────────── - # Serves Claude Code as a browser terminal via ttyd (port 7681). - # Protected by HTTP basic auth — set WEBUI_USER / WEBUI_PASSWORD in .env. - # Network isolation is identical to the CLI container. - webui: - image: registry.zeidler.dev/docker-public/playground/docker-claude-claude:${IMAGE_TAG:-latest} - entrypoint: ["/usr/local/bin/webui-entrypoint.sh"] - 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 - # MCP server credentials — all optional; servers are skipped if unset - - GITHUB_TOKEN=${GITHUB_TOKEN:-} - - GITLAB_TOKEN=${GITLAB_TOKEN:-} - - GITLAB_URL=${GITLAB_URL:-https://gitlab.com} - - ATLASSIAN_SITE_NAME=${ATLASSIAN_SITE_NAME:-} - - ATLASSIAN_USER_EMAIL=${ATLASSIAN_USER_EMAIL:-} - - ATLASSIAN_API_TOKEN=${ATLASSIAN_API_TOKEN:-} - - WEBUI_USER=${WEBUI_USER:-claude} - - WEBUI_PASSWORD=${WEBUI_PASSWORD:-} - - WEBUI_PORT=7681 - ports: - - "0.0.0.0:7681:7681" - # OAuth callback — required for browser-based login (claude login) - - "0.0.0.0:54545:54545" - volumes: - - claude-config:/home/node/.claude - - claude-web-workspace:/workspace - security_opt: - - no-new-privileges:true - cap_drop: - - ALL - stdin_open: true - tty: true - restart: unless-stopped - networks: # Internal-only: Docker adds no default gateway → no direct internet route claude-internal: @@ -109,9 +65,3 @@ networks: proxy-external: driver: bridge -volumes: - # Persists Claude Code auth credentials (~/.claude/) across container runs. - # Shared between the CLI and web interface so login carries over. - claude-config: - # Persistent workspace for the web interface - claude-web-workspace: