Implement claude auth login + repo cleanup

- 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
This commit is contained in:
Zac Gaetano 2026-04-04 15:09:25 -04:00
parent e77b7f6d74
commit 32cdaed467

View file

@ -1,55 +1,64 @@
# ============================================================================
# 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 bun
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 . || true
RUN git clone --depth 1 https://github.com/Ngxba/claude-code-agents-ui.git .
# Install dependencies using bun or npm
# Install dependencies (prefer bun if lockfile present, fallback to npm)
RUN if [ -f bun.lockb ]; then \
bun install --frozen-lockfile; \
else \
npm install; \
fi
npm install -g bun && bun install --frozen-lockfile; \
else \
npm install; \
fi
# Build the Nuxt application
RUN npm run build || bun run build
RUN npm run build 2>/dev/null || npx nuxt build
# Production stage
# --- Production Stage ---
FROM node:20-alpine
WORKDIR /app
# Install runtime dependencies including Claude Code and utilities
# Install runtime dependencies
RUN apk add --no-cache \
python3 py3-pip \
git git-lfs \
curl wget \
bash zsh \
vim nano \
python3 \
py3-pip \
git \
curl \
wget \
bash \
vim \
nano \
build-base \
openssh-client \
ca-certificates \
tini
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 \
RUN pip3 install --no-cache-dir --break-system-packages \
requests \
python-dotenv \
pydantic \
fastapi \
uvicorn
# Copy built application from builder
# Copy built Nuxt application from builder
COPY --from=builder /app/.output /app/.output
COPY --from=builder /app/package.json /app/package.json
COPY --from=builder /app/node_modules /app/node_modules
# Create non-root user for security
RUN addgroup -g 1000 claude && \
@ -57,36 +66,76 @@ RUN addgroup -g 1000 claude && \
# Create necessary directories
RUN mkdir -p /workspace /root/.claude && \
chown -R claude:claude /workspace /root/.claude
chown -R claude:claude /workspace && \
chown -R root:root /root/.claude
# Set permissions
# Set app ownership
RUN chown -R claude:claude /app
# Create entrypoint script that starts both services
RUN cat > /entrypoint.sh << 'EOF'
# ----------------------------------------------------------------------------
# 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
# Start Claude Code in the background if specified
if [ "$RUN_CLAUDE_CODE" = "true" ]; then
echo "Starting Claude Code daemon..."
claude serve &
CLAUDE_PID=$!
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
# Start the Nuxt application
echo "Starting Claude Code Agents UI..."
# --- 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
EOF
ENTRYPOINT_EOF
RUN chmod +x /entrypoint.sh
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
CMD curl -f http://localhost:3000/api/health || exit 1
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
CMD curl -f http://localhost:3000 || exit 1
EXPOSE 3000
# Use tini to handle signals properly
# Use tini for proper signal handling
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["/entrypoint.sh"]