- Dockerfile: entrypoint bootstraps ~/.claude/.credentials.json from ANTHROPIC_API_KEY (non-interactive auth, no manual claude auth login needed); fix build stage; add jq - docker-compose.yml: fix build context; update model to claude-sonnet-4-6; pass ANTHROPIC_MODEL env; fix backend healthcheck - claude-code-stack.env: update models to claude-sonnet-4-6; add CLAUDE_CONFIG_DIR; document auth strategy - deploy-ssh.sh: add verify_auth step; fix file aliasing on remote; auto-generate secrets; better output - README.md: document full auth flow end-to-end; add useful commands table
141 lines
4.3 KiB
Text
141 lines
4.3 KiB
Text
# ============================================================================
|
|
# Claude Code Agents UI - Dockerfile
|
|
# Combines Ngxba/claude-code-agents-ui frontend with Claude Code CLI runtime
|
|
# ============================================================================
|
|
|
|
# --- Build Stage ---
|
|
FROM node:20-alpine AS builder
|
|
|
|
WORKDIR /app
|
|
|
|
# Install build dependencies
|
|
RUN apk add --no-cache git
|
|
|
|
# Clone the Claude Code Agents UI repository
|
|
RUN git clone --depth 1 https://github.com/Ngxba/claude-code-agents-ui.git .
|
|
|
|
# Install dependencies (prefer bun if lockfile present, fallback to npm)
|
|
RUN if [ -f bun.lockb ]; then \
|
|
npm install -g bun && bun install --frozen-lockfile; \
|
|
else \
|
|
npm install; \
|
|
fi
|
|
|
|
# Build the Nuxt application
|
|
RUN npm run build 2>/dev/null || npx nuxt build
|
|
|
|
# --- Production Stage ---
|
|
FROM node:20-alpine
|
|
|
|
WORKDIR /app
|
|
|
|
# Install runtime dependencies
|
|
RUN apk add --no-cache \
|
|
python3 \
|
|
py3-pip \
|
|
git \
|
|
curl \
|
|
wget \
|
|
bash \
|
|
vim \
|
|
nano \
|
|
build-base \
|
|
openssh-client \
|
|
ca-certificates \
|
|
tini \
|
|
jq
|
|
|
|
# Install Claude Code CLI
|
|
RUN npm install -g @anthropic-ai/claude-code
|
|
|
|
# Install Python tools for agent execution
|
|
RUN pip3 install --no-cache-dir --break-system-packages \
|
|
requests \
|
|
python-dotenv \
|
|
pydantic \
|
|
fastapi \
|
|
uvicorn
|
|
|
|
# Copy built Nuxt application from builder
|
|
COPY --from=builder /app/.output /app/.output
|
|
COPY --from=builder /app/package.json /app/package.json
|
|
|
|
# Create non-root user for security
|
|
RUN addgroup -g 1000 claude && \
|
|
adduser -D -u 1000 -G claude claude
|
|
|
|
# Create necessary directories
|
|
RUN mkdir -p /workspace /root/.claude && \
|
|
chown -R claude:claude /workspace && \
|
|
chown -R root:root /root/.claude
|
|
|
|
# Set app ownership
|
|
RUN chown -R claude:claude /app
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# Entrypoint: bootstraps Claude auth then starts the UI
|
|
# ----------------------------------------------------------------------------
|
|
# Auth strategy (in priority order):
|
|
# 1. If ANTHROPIC_API_KEY is set → write a minimal credentials file so the
|
|
# Claude Code CLI recognises the key without needing an interactive login.
|
|
# 2. If a credentials file was volume-mounted at /root/.claude/.credentials.json
|
|
# already (e.g. from a docker volume) → use it as-is.
|
|
# 3. Fall through to the UI which will surface an auth error to the user.
|
|
# ----------------------------------------------------------------------------
|
|
RUN cat > /entrypoint.sh << 'ENTRYPOINT_EOF'
|
|
#!/bin/sh
|
|
set -e
|
|
|
|
CLAUDE_DIR="${CLAUDE_CONFIG_DIR:-/root/.claude}"
|
|
CREDS_FILE="${CLAUDE_DIR}/.credentials.json"
|
|
|
|
echo "[entrypoint] Claude config dir: ${CLAUDE_DIR}"
|
|
mkdir -p "${CLAUDE_DIR}"
|
|
|
|
# --- Bootstrap auth from ANTHROPIC_API_KEY ---
|
|
if [ -n "${ANTHROPIC_API_KEY}" ]; then
|
|
if [ ! -f "${CREDS_FILE}" ]; then
|
|
echo "[entrypoint] Writing credentials from ANTHROPIC_API_KEY..."
|
|
# Claude Code CLI accepts a credentials file with an apiKey field as
|
|
# an alternative to OAuth. This is the non-interactive equivalent of
|
|
# running `claude auth login` with an API key.
|
|
cat > "${CREDS_FILE}" << CREDS_EOF
|
|
{
|
|
"claudeAiOauth": null,
|
|
"apiKey": "${ANTHROPIC_API_KEY}"
|
|
}
|
|
CREDS_EOF
|
|
chmod 600 "${CREDS_FILE}"
|
|
echo "[entrypoint] Credentials written successfully."
|
|
else
|
|
echo "[entrypoint] Credentials file already exists, skipping write."
|
|
fi
|
|
else
|
|
echo "[entrypoint] WARNING: ANTHROPIC_API_KEY not set."
|
|
echo "[entrypoint] Set it in your .env file or via 'docker run -e ANTHROPIC_API_KEY=...'."
|
|
echo "[entrypoint] The UI will load but Claude Code execution will fail without auth."
|
|
fi
|
|
|
|
# --- Verify Claude CLI can see the key ---
|
|
if claude auth status 2>/dev/null | grep -q "Logged in\|api key"; then
|
|
echo "[entrypoint] Claude CLI auth: OK"
|
|
else
|
|
echo "[entrypoint] Claude CLI auth: not authenticated (will use ANTHROPIC_API_KEY at runtime)"
|
|
fi
|
|
|
|
# --- Start the Nuxt application ---
|
|
echo "[entrypoint] Starting Claude Code Agents UI on port 3000..."
|
|
exec node /app/.output/server/index.mjs
|
|
ENTRYPOINT_EOF
|
|
|
|
RUN chmod +x /entrypoint.sh
|
|
|
|
# Health check
|
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
|
|
CMD curl -f http://localhost:3000 || exit 1
|
|
|
|
EXPOSE 3000
|
|
|
|
# Use tini for proper signal handling
|
|
ENTRYPOINT ["/sbin/tini", "--"]
|
|
CMD ["/entrypoint.sh"]
|