-
Notifications
You must be signed in to change notification settings - Fork 44
Add docker #21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add docker #21
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,103 @@ | ||||||||||
| FROM ubuntu:24.04 | ||||||||||
|
|
||||||||||
| ENV DEBIAN_FRONTEND=noninteractive | ||||||||||
|
|
||||||||||
| RUN apt-get update && apt-get install -y \ | ||||||||||
| bash \ | ||||||||||
| ca-certificates \ | ||||||||||
| curl \ | ||||||||||
| git \ | ||||||||||
| jq \ | ||||||||||
| python3 \ | ||||||||||
| python3-pip \ | ||||||||||
| python3-venv \ | ||||||||||
| sudo \ | ||||||||||
| && rm -rf /var/lib/apt/lists/* | ||||||||||
|
|
||||||||||
| # Create non-root user | ||||||||||
| RUN useradd -m -s /bin/bash claudeuser && \ | ||||||||||
| echo "claudeuser ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers | ||||||||||
|
Comment on lines
+18
to
+19
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Passwordless sudo grants excessive privileges. Granting 🔒 Proposed restrictionIf sudo isn't actually required at runtime, remove it entirely: RUN useradd -m -s /bin/bash claudeuser && \
- echo "claudeuser ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
+ trueOr if specific commands need elevated privileges, restrict to those: - echo "claudeuser ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
+ echo "claudeuser ALL=(ALL) NOPASSWD: /usr/bin/apt-get" >> /etc/sudoers📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||
|
|
||||||||||
| # Set up application directory | ||||||||||
| WORKDIR /home/claudeuser/app | ||||||||||
| COPY . /home/claudeuser/app | ||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The To improve this:
|
||||||||||
| RUN chown -R claudeuser:claudeuser /home/claudeuser/app | ||||||||||
|
|
||||||||||
| USER claudeuser | ||||||||||
|
|
||||||||||
| # Install Claude CLI using the official installer (no npm required) | ||||||||||
| RUN curl -fsSL https://claude.ai/install.sh | bash | ||||||||||
|
Comment on lines
+28
to
+29
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚨 suggestion (security): Tighten security around running remote install script via curl | bash Piping a remote script directly into Suggested implementation: To fully leverage this change:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Piping the output of |
||||||||||
|
|
||||||||||
| # Create virtualenv and install dependencies | ||||||||||
| RUN python3 -m venv /home/claudeuser/venv && \ | ||||||||||
| /home/claudeuser/venv/bin/pip install --upgrade pip setuptools wheel && \ | ||||||||||
| /home/claudeuser/venv/bin/pip install -e . --use-pep517 || \ | ||||||||||
| /home/claudeuser/venv/bin/pip install -e . | ||||||||||
|
|
||||||||||
| ENV PATH="/home/claudeuser/venv/bin:/home/claudeuser/.local/bin:/home/claudeuser/.bun/bin:${PATH}" | ||||||||||
|
|
||||||||||
| # Create Claude config and workspace directories | ||||||||||
| RUN mkdir -p /home/claudeuser/.config/claude /home/claudeuser/app/workspace | ||||||||||
|
|
||||||||||
| EXPOSE 8000 | ||||||||||
|
|
||||||||||
| ENV HOST=0.0.0.0 | ||||||||||
| ENV PORT=8000 | ||||||||||
|
|
||||||||||
| HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ | ||||||||||
| CMD curl -f http://localhost:8000/health || exit 1 | ||||||||||
|
|
||||||||||
| RUN cat <<'EOF' > /home/claudeuser/entrypoint.sh | ||||||||||
| #!/usr/bin/env bash | ||||||||||
| set -euo pipefail | ||||||||||
|
|
||||||||||
| auth_ready=false | ||||||||||
|
|
||||||||||
| # Prefer host-mounted Claude auth (Claude Max / Claude Code) | ||||||||||
| if [ -d "$HOME/.claude" ] && [ -n "$(ls -A "$HOME/.claude" 2>/dev/null)" ]; then | ||||||||||
| echo "Using Claude auth from $HOME/.claude" | ||||||||||
| auth_ready=true | ||||||||||
| fi | ||||||||||
|
|
||||||||||
| # Fallback to Claude config file if present | ||||||||||
| if [ "$auth_ready" != "true" ] && [ -f "$HOME/.config/claude/config.json" ]; then | ||||||||||
| echo "Using Claude config from $HOME/.config/claude/config.json" | ||||||||||
| auth_ready=true | ||||||||||
| fi | ||||||||||
|
|
||||||||||
| # Optionally write config from API key (only when explicitly requested) | ||||||||||
| if [ "$auth_ready" != "true" ] && [ -n "${ANTHROPIC_API_KEY:-}" ] && [ "${USE_CLAUDE_MAX:-}" != "true" ]; then | ||||||||||
| if [ "${WRITE_CLAUDE_CONFIG:-}" = "true" ]; then | ||||||||||
| echo "Configuring Claude Code with API key..." | ||||||||||
| python3 - <<'PY' | ||||||||||
| import json | ||||||||||
| import os | ||||||||||
| from pathlib import Path | ||||||||||
|
|
||||||||||
| config_dir = Path.home() / ".config" / "claude" | ||||||||||
| config_dir.mkdir(parents=True, exist_ok=True) | ||||||||||
| with (config_dir / "config.json").open("w", encoding="utf-8") as handle: | ||||||||||
| json.dump({"apiKey": os.environ["ANTHROPIC_API_KEY"], "autoUpdate": False}, handle) | ||||||||||
| PY | ||||||||||
| echo "Claude Code configured with API key" | ||||||||||
| auth_ready=true | ||||||||||
| else | ||||||||||
| echo "ANTHROPIC_API_KEY is set but WRITE_CLAUDE_CONFIG is not true." | ||||||||||
| echo "For security, no config file was written. Mount ~/.claude or ~/.config/claude or set WRITE_CLAUDE_CONFIG=true." | ||||||||||
| fi | ||||||||||
| fi | ||||||||||
|
|
||||||||||
| if [ "$auth_ready" != "true" ] && [ "${USE_CLAUDE_MAX:-}" = "true" ]; then | ||||||||||
| echo "Using Claude Max subscription - please run: docker exec -it claude-code-api claude" | ||||||||||
| echo "Then authenticate via browser when prompted" | ||||||||||
| elif [ "$auth_ready" != "true" ]; then | ||||||||||
| echo "No authentication configured. Mount ~/.claude or ~/.config/claude, or set ANTHROPIC_API_KEY + WRITE_CLAUDE_CONFIG=true." | ||||||||||
| fi | ||||||||||
|
|
||||||||||
| echo "Starting API server..." | ||||||||||
| cd /home/claudeuser/app | ||||||||||
| exec python3 -m claude_code_api.main | ||||||||||
| EOF | ||||||||||
| RUN chmod +x /home/claudeuser/entrypoint.sh | ||||||||||
|
|
||||||||||
| ENTRYPOINT ["/home/claudeuser/entrypoint.sh"] | ||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| services: | ||
| claude-code-api: | ||
| build: | ||
| context: .. | ||
| dockerfile: docker/Dockerfile | ||
| container_name: claude-code-api | ||
| ports: | ||
| - "127.0.0.1:8000:8000" # API server port | ||
| - "127.0.0.1:8888:8888" # OAuth callback proxy port | ||
|
Comment on lines
+7
to
+9
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. question: Re-evaluate exposing port 8888 on the container for the OAuth proxy Given the proxy runs as a separate host-side process ( |
||
| environment: | ||
| # Use Claude Max subscription instead of API key | ||
| - USE_CLAUDE_MAX=true | ||
| - HOST=0.0.0.0 | ||
| - PORT=8000 | ||
| # Optional: Project root for Claude Code workspace | ||
| - CLAUDE_PROJECT_ROOT=/home/claudeuser/app/workspace | ||
| # OAuth proxy configuration | ||
| - OAUTH_PROXY_HOST=host.docker.internal | ||
| - OAUTH_PROXY_PORT=8888 | ||
|
Comment on lines
+18
to
+19
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
🔧 Proposed fix for Linux compatibility environment:
# Use Claude Max subscription instead of API key
- USE_CLAUDE_MAX=true
- HOST=0.0.0.0
- PORT=8000
# Optional: Project root for Claude Code workspace
- CLAUDE_PROJECT_ROOT=/home/claudeuser/app/workspace
# OAuth proxy configuration
- OAUTH_PROXY_HOST=host.docker.internal
- OAUTH_PROXY_PORT=8888
+ extra_hosts:
+ - "host.docker.internal:host-gateway"🤖 Prompt for AI Agents |
||
| volumes: | ||
| # Mount workspace for persistent projects | ||
| - ../workspace:/home/claudeuser/app/workspace | ||
| # Mount local Claude auth (Claude Max / Claude Code) | ||
| - ${HOME}/.claude:/home/claudeuser/.claude | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When running from CI pipelines, systemd services, or cron jobs, 🤖 Prompt for AI Agents |
||
| # Mount Claude config to persist authentication | ||
| - ../claude-config:/home/claudeuser/.config/claude | ||
| # Optional: Mount custom config | ||
| - ../config:/home/claudeuser/app/config | ||
| restart: unless-stopped | ||
| healthcheck: | ||
| test: ["CMD", "curl", "-f", "http://localhost:8000/health"] | ||
| interval: 30s | ||
| timeout: 10s | ||
| retries: 3 | ||
| start_period: 10s | ||
|
Comment on lines
+30
to
+35
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Granting unrestricted
NOPASSWDsudo privileges to theclaudeuserin theDockerfileallows any process in the container to escalate to root, significantly increasing the impact of a compromise and negating the security benefits of running as a non-root user. The application should be designed to run without requiring root privileges. Ifsudois essential for a specific setup command, it should be used restrictively and then removed.