v1 - basic functionality
This commit is contained in:
25
Dockerfile
Normal file
25
Dockerfile
Normal file
@ -0,0 +1,25 @@
|
||||
FROM node:22-slim
|
||||
|
||||
# Install runtime dependencies
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
curl \
|
||||
ca-certificates \
|
||||
git \
|
||||
ripgrep \
|
||||
bash \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Create a non-root user with a real home directory
|
||||
RUN useradd -m -s /bin/bash -u 1001 coder
|
||||
|
||||
# Ensure ~/.local/bin is on PATH (where the native installer puts the binary)
|
||||
ENV PATH="/home/coder/.local/bin:/home/coder/.claude/bin:${PATH}"
|
||||
|
||||
# Copy entrypoint (as root, then lock down)
|
||||
COPY --chmod=755 entrypoint.sh /usr/local/bin/entrypoint.sh
|
||||
|
||||
USER coder
|
||||
WORKDIR /code
|
||||
|
||||
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
|
||||
CMD ["bash"]
|
||||
76
README.md
Normal file
76
README.md
Normal file
@ -0,0 +1,76 @@
|
||||
# Claude Code — Dockerized
|
||||
|
||||
A minimal, guardrailed container for running Claude Code. The home
|
||||
directory and project folder are volumes, keeping your Claude install
|
||||
and credentials separate from any specific project.
|
||||
|
||||
## Setup
|
||||
|
||||
```bash
|
||||
# 1. Build the image
|
||||
docker compose build
|
||||
|
||||
# 2. Export your API key (or put it in a .env file)
|
||||
export ANTHROPIC_API_KEY=sk-ant-...
|
||||
|
||||
# 3. First run — installs Claude Code into the home volume, then drops you
|
||||
# into an interactive shell inside the default ./code directory
|
||||
docker compose run --rm claude-code
|
||||
```
|
||||
|
||||
On first start the entrypoint runs the native installer and places the
|
||||
binary in the `claude-home` named volume (under `/home/coder/.local/bin`).
|
||||
Subsequent starts skip the install and launch immediately.
|
||||
|
||||
## Switching projects
|
||||
|
||||
Point `PROJECT_DIR` at any directory on your host:
|
||||
|
||||
```bash
|
||||
PROJECT_DIR=/path/to/myproject docker compose run --rm claude-code
|
||||
```
|
||||
|
||||
Or set it in a `.env` file:
|
||||
|
||||
```
|
||||
ANTHROPIC_API_KEY=sk-ant-...
|
||||
PROJECT_DIR=/Users/me/projects/my-app
|
||||
```
|
||||
|
||||
Then just:
|
||||
|
||||
```bash
|
||||
docker compose run --rm claude-code
|
||||
```
|
||||
|
||||
## Starting Claude Code
|
||||
|
||||
Once inside the container shell:
|
||||
|
||||
```bash
|
||||
claude # start an interactive session in the current directory
|
||||
claude --help # show available options
|
||||
claude doctor # diagnose installation issues
|
||||
```
|
||||
|
||||
## Volumes
|
||||
|
||||
| Volume | Purpose |
|
||||
|---|---|
|
||||
| `claude-home` (named) | Persists Claude Code binary, config, and auth credentials |
|
||||
| `$PROJECT_DIR` (bind) | Your project code — swap freely between sessions |
|
||||
|
||||
To wipe the Claude install and start fresh:
|
||||
|
||||
```bash
|
||||
docker compose down -v # removes the claude-home volume
|
||||
```
|
||||
|
||||
## Security notes
|
||||
|
||||
- Runs as a non-root user (`coder`, uid 1000)
|
||||
- All Linux capabilities are dropped (`cap_drop: ALL`)
|
||||
- Privilege escalation is disabled (`no-new-privileges`)
|
||||
- The container has no network restrictions beyond what Docker provides —
|
||||
add a custom network or `--network none` with `--add-host` if you want
|
||||
to lock that down further
|
||||
37
docker-compose.yml
Normal file
37
docker-compose.yml
Normal file
@ -0,0 +1,37 @@
|
||||
services:
|
||||
claude-code:
|
||||
build: .
|
||||
image: claude-code:local
|
||||
container_name: claude-code
|
||||
|
||||
# Pass your Anthropic API key in from the host environment,
|
||||
# or drop it into a .env file alongside this compose file.
|
||||
# environment:
|
||||
# - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:?Set ANTHROPIC_API_KEY in your environment or .env file}
|
||||
|
||||
volumes:
|
||||
# Fixed home volume — persists Claude Code install, config, and credentials
|
||||
# across container restarts and image rebuilds.
|
||||
- claude-home:/home/coder
|
||||
|
||||
# Swappable project folder — override PROJECT_DIR to point at any directory:
|
||||
# PROJECT_DIR=/path/to/myproject docker compose run --rm claude-code
|
||||
- ${PROJECT_DIR:-./code}:/code
|
||||
|
||||
# Drop all Linux capabilities and disable privilege escalation —
|
||||
# Claude Code doesn't need any of them.
|
||||
cap_drop:
|
||||
- ALL
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
|
||||
# Interactive terminal so `claude` works properly
|
||||
stdin_open: true
|
||||
tty: true
|
||||
|
||||
working_dir: /code
|
||||
|
||||
volumes:
|
||||
claude-home:
|
||||
# Named volume — Docker manages it; survives `docker compose down`
|
||||
# (use `docker compose down -v` to wipe it along with the install)
|
||||
15
entrypoint.sh
Normal file
15
entrypoint.sh
Normal file
@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Install Claude Code if not already present in the home volume.
|
||||
# Because the home directory is a volume, this install persists across
|
||||
# container restarts and rebuilds.
|
||||
if ! command -v claude &>/dev/null; then
|
||||
echo "Claude Code not found — running installer..."
|
||||
curl -fsSL https://claude.ai/install.sh | bash
|
||||
echo "Claude Code installed successfully."
|
||||
else
|
||||
echo "Claude Code $(claude --version 2>/dev/null || echo '(version unknown)') ready."
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
13
safeclaude
Executable file
13
safeclaude
Executable file
@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if [[ $# -lt 1 ]]; then
|
||||
echo "Usage: $(basename "$0") <path-to-project>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PROJECT_DIR="$(cd "$1" && pwd)" # resolve to absolute path
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$(readlink -f "$0")")" && pwd)"
|
||||
|
||||
PROJECT_DIR="$PROJECT_DIR" docker compose -f "$SCRIPT_DIR/docker-compose.yml" run -w /code --rm claude-code claude
|
||||
Reference in New Issue
Block a user