feat: remove webui
This commit is contained in:
parent
1dee611fb3
commit
e78a302cb9
6 changed files with 9 additions and 112 deletions
|
|
@ -19,12 +19,6 @@
|
||||||
# Port 54545 must be reachable from your browser for the OAuth callback.
|
# Port 54545 must be reachable from your browser for the OAuth callback.
|
||||||
# Run: sbx ports <sandbox-name> --publish 54545:54545/tcp
|
# Run: sbx ports <sandbox-name> --publish 54545:54545/tcp
|
||||||
|
|
||||||
# ─── Web interface ────────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
# Required for ./claude.sh web
|
|
||||||
# WEBUI_USER=claude
|
|
||||||
# WEBUI_PASSWORD=changeme
|
|
||||||
|
|
||||||
# ─── MCP servers (all optional) ───────────────────────────────────────────────
|
# ─── MCP servers (all optional) ───────────────────────────────────────────────
|
||||||
|
|
||||||
# GitHub — PAT with repo scope
|
# GitHub — PAT with repo scope
|
||||||
|
|
|
||||||
13
CLAUDE.md
13
CLAUDE.md
|
|
@ -8,16 +8,13 @@ This file provides context and guidance for working with this project.
|
||||||
|
|
||||||
## Architecture
|
## 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
|
- **`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
|
- **`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.
|
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`):
|
Auth supports three modes (checked at startup by `claude.sh`):
|
||||||
- `ANTHROPIC_API_KEY` — API key
|
- `ANTHROPIC_API_KEY` — API key
|
||||||
- `CLAUDE_CODE_OAUTH_TOKEN` — 1-year token from `claude setup-token` (headless-friendly)
|
- `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/
|
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
|
├── docker-compose.yml # Service definitions and network topology
|
||||||
├── claude/
|
├── claude/
|
||||||
│ ├── Dockerfile # Claude Code + ttyd (node:20-alpine, UID 1000)
|
│ └── Dockerfile # Claude Code (node:20-alpine, UID 1000)
|
||||||
│ └── webui-entrypoint.sh # Entrypoint for webui: starts ttyd wrapping claude
|
|
||||||
├── proxy/
|
├── proxy/
|
||||||
│ ├── Dockerfile # Squid proxy sidecar (alpine:3.21, squid user)
|
│ ├── Dockerfile # Squid proxy sidecar (alpine:3.21, squid user)
|
||||||
│ └── squid.conf # Squid ACL config — egress allowlist lives here
|
│ └── squid.conf # Squid ACL config — egress allowlist lives here
|
||||||
|
|
@ -45,9 +41,8 @@ docker-claude/
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
chmod +x claude.sh build.sh
|
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)
|
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
|
./claude.sh update # pull latest images from registry
|
||||||
./build.sh # build images locally (development)
|
./build.sh # build images locally (development)
|
||||||
```
|
```
|
||||||
|
|
|
||||||
30
claude.sh
30
claude.sh
|
|
@ -37,6 +37,7 @@ load_env() {
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Wrapper so every docker compose call uses the right file and project name.
|
||||||
dc() { docker compose -f "$COMPOSE_FILE" -p "$PROJECT" "$@"; }
|
dc() { docker compose -f "$COMPOSE_FILE" -p "$PROJECT" "$@"; }
|
||||||
|
|
||||||
# ─── Volume args ──────────────────────────────────────────────────────────────
|
# ─── Volume args ──────────────────────────────────────────────────────────────
|
||||||
|
|
@ -121,32 +122,12 @@ cmd_shell() {
|
||||||
dc run --rm --service-ports --entrypoint /bin/bash "${VOLUME_ARGS[@]}" claude
|
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() {
|
cmd_help() {
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
Usage: $(basename "$0") [--kube] <command> [args]
|
Usage: $(basename "$0") [--kube] <command> [args]
|
||||||
|
|
||||||
Commands:
|
Commands:
|
||||||
start [args] Start proxy, launch Claude Code (CLI)
|
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
|
stop Stop and remove all containers
|
||||||
update Pull latest images from the registry
|
update Pull latest images from the registry
|
||||||
logs [svc] Tail logs (default: proxy)
|
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)
|
--kube Mount \$HOME/.kube read-only at /home/node/.kube (kubectl access)
|
||||||
|
|
||||||
Environment variables (set in .env):
|
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')
|
CLAUDE_CODE_OAUTH_TOKEN OAuth token auth (from 'claude setup-token')
|
||||||
IMAGE_TAG Image tag to use (default: latest)
|
IMAGE_TAG Image tag to use (default: latest)
|
||||||
WEBUI_USER Web interface username (default: claude)
|
|
||||||
WEBUI_PASSWORD Required for web mode
|
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
cd ~/myproject && ./claude.sh start
|
cd ~/myproject && ./claude.sh start
|
||||||
cd ~/myproject && ./claude.sh --kube start
|
cd ~/myproject && ./claude.sh --kube start
|
||||||
./claude.sh web
|
|
||||||
./claude.sh logs proxy
|
./claude.sh logs proxy
|
||||||
./claude.sh shell
|
./claude.sh shell
|
||||||
EOF
|
EOF
|
||||||
|
|
@ -184,8 +162,6 @@ done
|
||||||
case "${1:-help}" in
|
case "${1:-help}" in
|
||||||
start|run) shift; cmd_start "$@" ;;
|
start|run) shift; cmd_start "$@" ;;
|
||||||
stop) cmd_stop ;;
|
stop) cmd_stop ;;
|
||||||
web) cmd_web ;;
|
|
||||||
web-stop) cmd_web_stop ;;
|
|
||||||
update) cmd_update ;;
|
update) cmd_update ;;
|
||||||
logs) shift; cmd_logs "${1:-}" ;;
|
logs) shift; cmd_logs "${1:-}" ;;
|
||||||
status) cmd_status ;;
|
status) cmd_status ;;
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,7 @@ RUN apk add --no-cache \
|
||||||
git \
|
git \
|
||||||
curl \
|
curl \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
bash \
|
bash
|
||||||
ttyd
|
|
||||||
|
|
||||||
# Install kubectl — architecture-aware, checksum-verified
|
# Install kubectl — architecture-aware, checksum-verified
|
||||||
RUN KUBECTL_VERSION=$(curl -fsSL https://dl.k8s.io/release/stable.txt) \
|
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 \
|
&& rm /tmp/kubectl.sha256 \
|
||||||
&& chmod +x /usr/local/bin/kubectl
|
&& 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.
|
# 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.
|
# Restricts available models; cannot be bypassed via CLI flags or env vars.
|
||||||
COPY settings.json /etc/claude-code/managed-settings.json
|
COPY settings.json /etc/claude-code/managed-settings.json
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -5,7 +5,7 @@ services:
|
||||||
proxy:
|
proxy:
|
||||||
image: registry.zeidler.dev/docker-public/playground/docker-claude-proxy:${IMAGE_TAG:-latest}
|
image: registry.zeidler.dev/docker-public/playground/docker-claude-proxy:${IMAGE_TAG:-latest}
|
||||||
networks:
|
networks:
|
||||||
- claude-internal # reachable by claude and webui containers
|
- claude-internal # reachable by claude container
|
||||||
- proxy-external # has outbound internet access
|
- proxy-external # has outbound internet access
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
security_opt:
|
security_opt:
|
||||||
|
|
@ -55,50 +55,6 @@ services:
|
||||||
stdin_open: true
|
stdin_open: true
|
||||||
tty: 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:
|
networks:
|
||||||
# Internal-only: Docker adds no default gateway → no direct internet route
|
# Internal-only: Docker adds no default gateway → no direct internet route
|
||||||
claude-internal:
|
claude-internal:
|
||||||
|
|
@ -109,9 +65,3 @@ networks:
|
||||||
proxy-external:
|
proxy-external:
|
||||||
driver: bridge
|
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:
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue