Remote Claude Code instance with remote control support. Run Claude Code 24/7 on your server and connect from the Claude mobile/web app.
-
Copy
.env.exampleto.env.productionand fill in your values. -
For git access (optional): Generate an SSH deploy key, add it to your repo, and set
DEPLOY_KEY_B64in your env file. See Git Repository below.
# Deploy
bc claude-code up
# View logs
bc claude-code logs -f
# Stop
bc claude-code down# Deploy directly from GHCR
docker compose -f oci://ghcr.io/beevelop/claude-code:latest --env-file .env up -d
# View logs
docker compose -f oci://ghcr.io/beevelop/claude-code:latest --env-file .env logs -f
# Stop
docker compose -f oci://ghcr.io/beevelop/claude-code:latest --env-file .env downcd services/claude-code
# Deploy locally
docker compose --env-file .env.example up -d
# View logs
docker compose logs -f
# Stop
docker compose downRemote control mode requires an OAuth login (API keys are not supported). On first launch, you must attach to the container and complete the login flow:
-
Start the container (see Quick Start above).
-
Attach to the running container:
docker attach claude-code
-
Complete the OAuth login -- the entrypoint will automatically run
claude login. Follow the URL printed in the terminal to authenticate in your browser. -
After login succeeds, press
Ctrl+Cto continue. The entrypoint will then launchclaude remote-control. -
Detach from the container with
Ctrl+PthenCtrl+Q(Docker's detach sequence). The container continues running in the background.
Subsequent container restarts will use the persisted credentials and skip the login step entirely.
Claude Code stores its credentials in these locations inside the container:
| Path | Purpose |
|---|---|
/home/developer/.claude/.credentials.json |
OAuth tokens (access + refresh) |
/home/developer/.claude.json |
Account metadata and onboarding state |
/home/developer/.claude/ |
Full config directory (credentials, settings, history) |
To persist credentials across container restarts, a volume is mounted at /home/developer/.claude (the claude_config volume in docker-compose.yml).
The image pre-seeds /home/developer/.claude.json with onboarding state so Claude Code does not prompt for initial setup.
To let Claude Code clone a repo and push changes, set up SSH deploy key authentication:
-
Generate a deploy key:
ssh-keygen -t ed25519 -f deploy_key -N "" -
Add
deploy_key.pubas a Deploy key to your GitHub repo (Settings > Deploy keys > Add deploy key). Enable Allow write access. -
Base64-encode the private key and add it to your
.env.claude-code:# Encode (works on both macOS and Linux): base64 < deploy_key | tr -d '\n'
DEPLOY_KEY_B64=LS0tLS1CRUdJTi... # paste the base64 output here GIT_REPO=git@github.com:your-org/your-repo.git GIT_USER_NAME=Claude Code GIT_USER_EMAIL=claude@example.com
| Variable | Default | Description |
|---|---|---|
GIT_REPO |
(empty) | SSH clone URL (e.g., git@github.com:your-org/your-repo.git) |
GIT_BRANCH |
(repo default) | Branch to clone |
GIT_USER_NAME |
(empty) | Git commit author name |
GIT_USER_EMAIL |
(empty) | Git commit author email |
DEPLOY_KEY_B64 |
(empty) | Base64-encoded SSH private key (ed25519) |
The deploy key is base64-encoded so it fits on a single line in the .env file. The entrypoint decodes it and writes it to ~/.ssh/id_ed25519 with restricted permissions at startup.
On first start, if GIT_REPO is set and /workspace is empty, the entrypoint clones the repository. On subsequent restarts the existing clone is reused.
Without a deploy key, the service still works for general Claude Code usage -- git features are simply unavailable.
| Variable | Default | Description |
|---|---|---|
ANTHROPIC_MODEL |
(Claude default) | Override the default model |
CLAUDE_PERMISSION_MODE |
acceptEdits |
Permission mode for remote-control (see below) |
CLAUDE_SESSION_NAME |
(empty) | Custom session title visible in claude.ai/code |
INIT_COMMAND |
(empty) | One-time setup command (runs once on first launch, tracked via stamp file) |
CLAUDE_EXTRA_ARGS |
(empty) | Extra flags for claude remote-control |
Controls what Claude Code can do without asking for confirmation:
| Mode | Behavior |
|---|---|
default |
Prompts for all file edits and commands |
acceptEdits |
Auto-approves file edits, prompts for shell commands (default) |
bypassPermissions |
Full autonomous / YOLO mode -- no prompts at all |
dontAsk |
Don't ask, fail instead of prompting |
plan |
Read-only planning mode -- no edits or commands |
To run fully autonomous:
CLAUDE_PERMISSION_MODE=bypassPermissionsThe INIT_COMMAND variable lets you install additional tools into the container on first boot. It runs once and is tracked via a stamp file in the Claude config volume, so it won't re-run on subsequent container restarts.
# Example: Install additional Python packages
INIT_COMMAND=pip3 install poetry| Volume | Container Path | Purpose |
|---|---|---|
claude_config |
/home/developer/.claude |
Claude credentials, config, and history (persists login across restarts) |
claude_workspace |
/workspace |
Project files (auto-cloned from GIT_REPO) |
Once the container is running, open Claude on iOS/Android or the web app, navigate to Remote Control, and attach to the running session. All code edits and tool executions happen inside the container on your server.
This service uses the beevelop/claude Docker image, which is based on ubuntu:24.04 with a full developer toolchain (Node.js 22, Python 3, build-essential, ripgrep, fzf, etc.) and Claude Code CLI pre-installed.