Skip to content

Docker setup and updates

Docker runs the proxy and its existing provider clients in one isolated container. Claude Code runs on the host, and provider authorization opens in your host browser. No host application installation or credential mount is required. Docker Desktop on macOS and Docker Engine with Compose on Linux use the same setup.

  • A macOS or Linux host with a running Docker engine. The supported container architectures are linux/arm64 and linux/amd64; Apple Silicon uses ARM64 Linux containers.
  • A terminal with docker; the Compose recipes also require Compose v2. Check docker version and, when using Compose, docker compose version. Source builds need Buildx/BuildKit. The Compose recipes use a source checkout, which also needs Git and authenticated repository access; the standalone image recipe below does not need a checkout. The commands below use Bash or Zsh.
  • Network access to your chosen registry and your provider’s authorization and inference endpoints. Docker Hub and Quay.io images are public. GHCR and the source repository remain private; using those resources requires GitHub access. Source builds also need repository access, pinned base images, Debian packages, Rust crates, and several GiB of working memory and disk.
  • A supported provider account with model access and available quota. Guided login runs in your host browser. OpenCode Go requires its subscription key. Listing a model does not establish inference access; use Verify.
  • Claude Code installed separately on the host, with claude --version working. Your projects, tools, and Claude Code session stay on that host.
  • An available host loopback port, normally 18765, and permission to create a private Docker volume for credentials.

The container includes the proxy’s provider clients. It does not require host Rust, Bun, Python, Cursor, Codex, or Kimi CLI installations. It does not import their logins. Sign in once through the setup UI; credentials persist in the profile volume.

docker.io/c0mpiler/claude-code-proxy:0.2.0 contains the proxy and setup UI for both Apple Silicon (linux/arm64) and AMD64 (linux/amd64). Docker selects the architecture for your engine. macOS hosts run the Linux image inside their Docker VM.

Registry Access Image
Docker Hub Public docker.io/c0mpiler/claude-code-proxy:0.2.0
Quay.io Public quay.io/c0mpiler/claude-code-proxy:0.2.0
GHCR Private ghcr.io/fydo-dev/claude-code-proxy:0.2.0

Docker Hub and Quay.io need no registry login. Use either public image in CCP_IMAGE, or as the final argument to docker run. Provider sign in happens separately in the setup UI, and credentials remain in the private profile volume.

From a source checkout:

Terminal window
export CCP_IMAGE=docker.io/c0mpiler/claude-code-proxy:0.2.0
docker compose pull
docker compose up -d --no-build --wait
docker compose exec proxy claude-code-proxy ui --print-url

Open the private setup link, connect a provider, verify your models, save the four roles, and copy the command for Claude Code on your host. No host Rust toolchain or provider CLI is needed. Keep CCP_IMAGE exported or save it in your private .env for subsequent Compose commands.

Pull and start a public image directly; no source checkout or registry login is needed:

Terminal window
docker pull docker.io/c0mpiler/claude-code-proxy:0.2.0
docker run -d --name claude-code-proxy \
--init --restart unless-stopped \
-p 127.0.0.1:18765:18765 \
--mount type=volume,source=claude-code-proxy-profile,target=/var/lib/claude-code-proxy \
--read-only --tmpfs /tmp:size=64m,mode=1777 \
--cap-drop ALL --security-opt no-new-privileges:true \
docker.io/c0mpiler/claude-code-proxy:0.2.0
docker inspect --format '{{.State.Health.Status}}' claude-code-proxy
# Once healthy, print the private setup link.
docker exec claude-code-proxy claude-code-proxy ui --print-url

The setup page is at http://127.0.0.1:18765/ui/; use the private link from the final command to unlock it. The standalone recipe stores credentials and selections in claude-code-proxy-profile. Compose uses its project’s profile volume. Retain the volume name for the recipe you use when recreating or updating the container.

This section applies only to the private GHCR image. The public Docker Hub and Quay.io recipes need no registry login. The GHCR package and source repository remain private. Create a personal access token classic with read:packages, using a GitHub account with access to the package. If your organization requires SSO, authorize that token for the organization. A GitHub CLI login alone does not establish registry access. GitHub documents the required token and package permissions.

Terminal window
docker login ghcr.io -u YOUR_GITHUB_USERNAME

Enter the token at Docker’s password prompt. Keep it out of source files and launch commands. Registry authentication downloads the application; provider sign in happens separately in the proxy’s setup UI.

To use GHCR with Compose, set CCP_IMAGE=ghcr.io/fydo-dev/claude-code-proxy:0.2.0 after signing in.

Use a versioned tag for controlled updates. latest follows the most recently verified publication. The release’s container-image-dockerhub.txt, container-image-quay.txt, and private GHCR container-image.txt record each registry’s verified digest; for example, use docker.io/c0mpiler/claude-code-proxy@sha256:… in CCP_IMAGE for an immutable image.

For Compose, set CCP_IMAGE to the new version or digest, then run docker compose pull and docker compose up -d --no-build --wait. For the standalone recipe, pull the new version, stop and remove only the old container, then repeat docker run with the new image and the same named volume. Keep the previous image tag or digest to roll back the application.

For private GHCR, an unauthorized or denied pull means registry authentication or package access needs attention. Check the token’s read:packages scope, its SSO authorization if required, and the account’s package access. It does not establish a provider login problem.

Clone the source repository, then run these commands from its root:

Terminal window
docker compose up --build -d --wait
docker compose ps
# Print the private setup link, then open it in your browser.
docker compose exec proxy claude-code-proxy ui --print-url

Docker compiles the application inside the build stage; later builds reuse its cache. --wait waits for the container health check. If it fails, inspect docker compose logs --tail=100 proxy before changing credentials. Startup health establishes that the listener runs, rather than that a provider can answer.

Run a downloaded container without compiling

Section titled “Run a downloaded container without compiling”

The v0.2.0 release also provides Docker-loadable image archives with SHA-256 files. These are an alternative to a registry pull and use your existing repository access.

From the same checkout, download the archive and checksum for your Docker engine’s architecture into the repository root using your authenticated GitHub CLI account. For example, GH_HOST=github.com gh release download v0.2.0 --repo fydo-dev/claude-code-proxy --pattern 'claude-code-proxy-container-linux-arm64.*'. For Apple Silicon use arm64; for an Intel or AMD Linux engine use amd64. Verify the archive before loading it:

Terminal window
# Apple Silicon example. Replace arm64 with amd64 for an AMD64 engine.
shasum -a 256 -c claude-code-proxy-container-linux-arm64.sha256
docker load -i claude-code-proxy-container-linux-arm64.tar.gz
export CCP_IMAGE=claude-code-proxy:0.2.0-arm64
docker compose up -d --no-build --pull never --wait
docker compose exec proxy claude-code-proxy ui --print-url

Linux can use sha256sum -c instead of shasum -a 256 -c. The matching checksum file names the archive it verifies; keep both in the same directory. Compare docker image inspect --format '{{.Architecture}}' "$CCP_IMAGE" with the downloaded architecture, then check docker run --rm "$CCP_IMAGE" --version.

Keep CCP_IMAGE exported or put it in your private .env for subsequent commands. Compose otherwise uses the local source image. For an update, verify and load the new archive, change CCP_IMAGE, and recreate with the same command and project directory. Retain the previous image tag for rollback.

With Git, Python 3.11 or newer, and Docker Buildx installed, run:

Terminal window
bash scripts/release-linux.sh dist

This builds both architectures, runs their container lifecycle checks, and writes native executable archives, Docker-loadable image archives, and SHA-256 files to dist/. Docker Desktop supplies emulation on macOS. Linux needs working ARM64 and AMD64 emulation to execute a nonnative image. The helper reads its version from Cargo.toml; use that version in CCP_IMAGE after loading an archive. No registry account or host Rust installation is required for this helper.

After either installation path, the default URL is http://127.0.0.1:18765/ui/. Follow Local setup UI to sign in, verify models, and save the four roles. Copy its command into a host terminal to launch Claude Code. The image does not contain Claude Code or your projects.

The named profile volume holds provider logins, refreshed credentials, the management key, saved role selections, and application state. The container runs as UID 10001, with a read only root filesystem, writable private volume and temporary memory filesystem, dropped capabilities, and no privilege escalation. Compose publishes the service only on host loopback. Inference keeps the proxy’s existing local trust model; this is not a shared or publicly exposed service.

After pulling the released image and setting CCP_IMAGE, use a different host port if another proxy owns 18765:

Terminal window
export CCP_HOST_PORT=18766
docker compose up -d --no-build --wait
# The container knows its internal port; override the public origin for the link.
docker compose exec proxy claude-code-proxy ui --print-url --url http://127.0.0.1:18766

For a source build, use --build in place of --no-build. For the standalone recipe, publish 127.0.0.1:18766:18765 and pass --url http://127.0.0.1:18766 to its ui command.

Open the link before selecting models so the initial endpoint matches the host port. Update an existing saved endpoint in Connection and session preferences when changing ports. Use the same CCP_HOST_PORT for subsequent Compose operations or set it in the private .env file at the repository root. .env.example documents the default. An existing .env can select a different port, so use docker compose ps to confirm the published address.

Replace the application, retain the profile

Section titled “Replace the application, retain the profile”

For a source build, update the checkout to a reviewed revision and rebuild. Select the local image explicitly when switching back from a downloaded image:

Terminal window
export CCP_IMAGE=claude-code-proxy:local
docker compose build --pull
docker compose up -d --force-recreate --wait
# Check service readiness and print the same profile's setup link.
docker compose ps
docker compose exec proxy claude-code-proxy ui --print-url

Rust and UI dependencies are locked; base image versions and digests live in the Dockerfile. Runtime OS packages receive the repository updates available at build time. Updating a running container in place is intentionally unsupported. Pulling does not override a pinned base digest; maintainers update the pins with lifecycle verification. Keep the previous source revision or image tag to roll back the application. Back up the stopped profile volume before changes to persisted formats; volume contents are sensitive and backups need equivalent access protection.

docker compose down preserves the profile. docker compose down --volumes deletes logins, the management key, and saved model choices. Removing or recreating a container alone does not delete them. Changing the Compose project name selects a different volume and therefore a different profile.

Developer verification also requires a current stable Rust toolchain, Bun, and Python 3.11 or newer on the host. Running the proxy container itself does not require them.

The repository includes provider protocol fixtures using synthetic credentials only:

Terminal window
bun install --cwd ui --frozen-lockfile
bun run --cwd ui check
cargo test --locked --all-targets
cargo build --locked
python3 scripts/setup_e2e.py --binary target/debug/claude-code-proxy
docker build -t claude-code-proxy:e2e .
python3 scripts/setup_e2e.py --image claude-code-proxy:e2e

The Docker test creates its own isolated volume and loopback port, checks guided device authorization, cancelled client connections during Kimi and Cursor refresh, cancellation during sign in, expired and malformed login responses, persistent device identity, independent roles, exports, streaming, and inference after recreation and replacement by a distinct image. It deletes only its own test resources. Replacement uses the same application build with a distinct image configuration; this proves volume retention across image replacement, not compatibility with an unknown future schema. Fixtures do not establish live account authorization. Sign in through your provider and verify your selected models before relying on a real account.

For release verification of both architectures, run bash scripts/release-linux.sh. The helper cross compiles using the build host’s native Rust toolchain, checks the selected image architecture and version, exercises the full container lifecycle on each image, extracts the same tested binaries into release archives, and exports the tested Docker images with checksums. It retains the versioned local image tags for reuse. A nonnative architecture requires Docker’s emulation support; Linux CI installs QEMU for that runtime check. These checks prove execution under emulation when a native host is unavailable.

Only release tags and explicit publication runs publish images. Ordinary pushes run checks without changing released images. The same checksummed container bundles feed all three registries. GHCR remains private; Docker Hub and Quay.io are public. An existing version is reused only when its image configuration matches the release bundle, and conflicting images fail instead of being overwritten.

Each registry verifies both architectures and its expected access policy before promoting its latest. Registry jobs run independently, and complete release records update after all three pass. See Registry publishing setup for credentials, visibility, retrying a partial publication, and publishing an existing release without rebuilding it.