claude-code-stack/claude-agents-ui-Dockerfile

142 lines
4.3 KiB
Text
Raw Permalink Normal View History

# ============================================================================
# Claude Code Agents UI - Dockerfile
# Combines Ngxba/claude-code-agents-ui frontend with Claude Code CLI runtime
# ============================================================================
# --- Build Stage ---
2026-04-04 14:32:22 -04:00
FROM node:20-alpine AS builder
WORKDIR /app
# Install build dependencies
RUN apk add --no-cache git
2026-04-04 14:32:22 -04:00
# Clone the Claude Code Agents UI repository
RUN git clone --depth 1 https://github.com/Ngxba/claude-code-agents-ui.git .
2026-04-04 14:32:22 -04:00
# Install dependencies (prefer bun if lockfile present, fallback to npm)
2026-04-04 14:32:22 -04:00
RUN if [ -f bun.lockb ]; then \
npm install -g bun && bun install --frozen-lockfile; \
else \
npm install; \
fi
2026-04-04 14:32:22 -04:00
# Build the Nuxt application
RUN npm run build 2>/dev/null || npx nuxt build
2026-04-04 14:32:22 -04:00
# --- Production Stage ---
2026-04-04 14:32:22 -04:00
FROM node:20-alpine
WORKDIR /app
# Install runtime dependencies
2026-04-04 14:32:22 -04:00
RUN apk add --no-cache \
python3 \
py3-pip \
git \
curl \
wget \
bash \
vim \
nano \
2026-04-04 14:32:22 -04:00
build-base \
openssh-client \
ca-certificates \
tini \
jq
2026-04-04 14:32:22 -04:00
# 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 \
2026-04-04 14:32:22 -04:00
requests \
python-dotenv \
pydantic \
fastapi \
uvicorn
# Copy built Nuxt application from builder
2026-04-04 14:32:22 -04:00
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
2026-04-04 14:32:22 -04:00
# Set app ownership
2026-04-04 14:32:22 -04:00
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'
2026-04-04 14:32:22 -04:00
#!/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)"
2026-04-04 14:32:22 -04:00
fi
# --- Start the Nuxt application ---
echo "[entrypoint] Starting Claude Code Agents UI on port 3000..."
2026-04-04 14:32:22 -04:00
exec node /app/.output/server/index.mjs
ENTRYPOINT_EOF
2026-04-04 14:32:22 -04:00
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
2026-04-04 14:32:22 -04:00
EXPOSE 3000
# Use tini for proper signal handling
2026-04-04 14:32:22 -04:00
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["/entrypoint.sh"]