Docker and CCR sessions
Run each task in its own container, with model access through a Claude Code Router (CCR) gateway. Use this when you want isolation from the host or a provider CCR supports. For regular Claude Code on your existing server, use Getting started instead.
Containers get only a CCR client key and, optionally, a GitHub token. Your provider keys stay in the gateway, and the host's SSH keys and Claude login are never mounted. See How it works.
#What you need
- A Linux server with Docker: a cloud VM (AWS EC2, Alicloud ECS, …), a home server or a spare machine. 2 CPUs and 4 GB of memory per concurrent session is a good starting point.
- Node.js 22.18 or newer.
- CCR with at least one provider configured:
npm install -g @musistudio/claude-code-router, thenccr uito set it up. - For phone access: an HTTPS address. See Access from your phone.
- Optional: a GitHub token if sessions should clone private repos or push branches.
#1. Prepare CCR
- In the CCR UI, create a client API key for ccr-cloud. Sessions use it to call the gateway.
Make sure the gateway is reachable from Docker containers. Containers cannot reach
127.0.0.1on the host, so the gateway must listen on the Docker bridge address (usually172.17.0.1) or on all interfaces. Check from a container:SHELLdocker run --rm --add-host host.docker.internal:host-gateway curlimages/curl \ -s -o /dev/null -w '%{http_code}\n' http://host.docker.internal:3456/Any HTTP status code means it is reachable;
000means it is not. If the gateway listens on all interfaces, block port 3456 from the internet with your firewall or cloud security group.
#2. Install ccr-cloud
git clone https://github.com/thinkinginmath/ccr-cloud.git
cd ccr-cloud
npm ci
npm run image # builds the session image (Claude Code, git, gh); takes a few minutes#3. Configure and start it
Create an environment file, for example /etc/ccr-cloud.env, readable only by the user that runs ccr-cloud:
# Owner token: the password for the web app and API. Generate a long random one:
# openssl rand -hex 24
CCR_CLOUD_DRIVER=docker
CCR_CLOUD_TOKEN=...
# The CCR client key from step 1
CCR_GATEWAY_KEY=...
# Contact address for push services (yours, not localhost)
CCR_CLOUD_PUSH_SUBJECT=mailto:you@example.com
# Optional: lets sessions clone private repos and push branches (see "GitHub repositories")
# GH_TOKEN=github_pat_...
# Where sessions, logs and notification keys are stored
CCR_CLOUD_DATA=/var/lib/ccr-cloudStart it in the foreground to check that it works:
set -a; . /etc/ccr-cloud.env; set +a
npm start
# ccr-cloud API on http://127.0.0.1:8787
# runner endpoint on ws://172.17.0.1:8788To keep it running, use systemd. Save as /etc/systemd/system/ccr-cloud.service, adjusting the user and paths. ExecStart needs the full path of node; which node prints it (with nvm it is under ~/.nvm):
[Unit]
Description=ccr-cloud
After=docker.service network-online.target
Requires=docker.service
[Service]
User=ubuntu
WorkingDirectory=/home/ubuntu/ccr-cloud
EnvironmentFile=/etc/ccr-cloud.env
ExecStart=/usr/bin/node src/server/main.ts
Restart=on-failure
[Install]
WantedBy=multi-user.target
Then sudo systemctl enable --now ccr-cloud. The user needs permission to use Docker (the docker group).
#Docker settings
These are the settings Docker mode uses. See Configuration for every setting.
| Variable | Default | What it does |
|---|---|---|
CCR_CLOUD_TOKEN | required | Owner token for the web app and API |
CCR_GATEWAY_KEY | required | CCR client key given to sessions |
CCR_GATEWAY_URL | http://host.docker.internal:3456 | CCR gateway address as seen from a container |
CCR_CLOUD_PUSH_SUBJECT | the project URL | Your contact address for push services |
GH_TOKEN | unset | GitHub token passed to sessions |
CCR_CLOUD_DATA | .data | Sessions, event logs, notification keys and devices |
CCR_CLOUD_IMAGE | ccr-cloud-session:dev | Session image |
CCR_CLOUD_HOST / CCR_CLOUD_PORT | 127.0.0.1 / 8787 | Where the web app and API listen |
CCR_CLOUD_RUNNER_HOST / CCR_CLOUD_RUNNER_PORT | 172.17.0.1 / 8788 | Where sessions connect back (Docker bridge only) |
CCR_CLOUD_RUNNER_URL | ws://host.docker.internal:8788 | That address as seen from a container |
#Credentials and isolation
The server user must have Docker access. Host SSH keys and Claude logins are not mounted into containers. Configure Git identity in the session image and provide GH_TOKEN only if tasks need it; the agent can use the token from its shell. CCR keeps provider keys on the gateway; containers receive its client key. Keep the API on loopback and the runner endpoint on the Docker bridge. Container limits reduce interference but do not establish a multi-tenant service.
#Next steps
After the service starts, connect and run a scratch task as in Getting started, then add a repository by URL (Work with repositories). Rebuild the image with npm run image after each update.