Docker/Web runs the CCPG daemon and browser panel inside a container. It is the same gateway backend used by the desktop app, but state is stored in SQLite and the panel is served over HTTP.
Use this guide when you want to run CCPG without the desktop app, expose it through Docker Compose, change ports, persist state, or place it behind a reverse proxy.
From the repository root:
docker compose up -d --buildOpen:
| Service | URL |
|---|---|
| Panel UI and panel API | http://localhost:6767 |
| Anthropic/OpenAI-compatible gateway | http://localhost:49250/v1 |
Check status:
docker compose ps
docker compose logs -f ccpg
curl -s http://127.0.0.1:6767/api/statusStop the container:
docker compose downRemove the persisted Docker/Web state as well:
docker compose down -vThe Compose service runs one Node process that starts two HTTP servers:
| Server | Internal port | Purpose |
|---|---|---|
| Panel | 6767 |
Browser UI and /api/* management routes |
| Gateway proxy | 49250 |
Claude Code Anthropic-compatible API and OpenAI-compatible /v1 API |
Docker/Web differs from the desktop app in three important ways:
- The daemon runs inside the container, not on the host.
- The host reaches the daemon through Docker port publishing.
- Config, encrypted secrets, and sessions are stored in SQLite at
/data/ccpg.sqlite.
Because the daemon is containerized, automatic Terminal Integration cannot edit your host shell files. The dashboard shows manual shell snippets for your host terminal instead.
The default docker-compose.yml:
services:
ccpg:
build:
context: .
image: cc-provider-gtw:local
environment:
NODE_ENV: production
CCPG_RUNTIME_MODE: docker
CCPG_STORAGE_BACKEND: sqlite
CCPG_SQLITE_PATH: /data/ccpg.sqlite
CCPG_CONFIG_DIR: /data
CCPG_PANEL_PORT: "6767"
CCPG_PROXY_PORT: "49250"
CC_GATEWAY_BIND_HOST: 0.0.0.0
ports:
- "6767:6767"
- "49250:49250"
volumes:
- ccpg_data:/data
restart: unless-stoppedThe left side of each ports: entry is the host port. The right side is the
container port:
ports:
- "HOST_PANEL_PORT:CONTAINER_PANEL_PORT"
- "HOST_PROXY_PORT:CONTAINER_PROXY_PORT"For the simple case, keep host and container ports identical.
| Variable | Default in Compose | Required | Description |
|---|---|---|---|
NODE_ENV |
production |
Yes | Makes the daemon serve the built panel directly and use production panel-origin checks. |
CCPG_RUNTIME_MODE |
docker |
Yes | Enables Docker/Web behavior in the panel and session tracking. Terminal Integration is treated as host-manual only. |
CCPG_STORAGE_BACKEND |
sqlite |
Yes | Selects SQLite storage for config, encrypted secrets, current sessions, and session history. |
CCPG_SQLITE_PATH |
/data/ccpg.sqlite |
Yes | Path to the SQLite database inside the container. Keep this under the persisted /data volume. |
CCPG_CONFIG_DIR |
/data |
Yes | Directory for support files such as the master key, logs, uploaded provider logos, and PID files. |
CCPG_PANEL_PORT |
6767 |
Yes | Internal panel port the daemon listens on. Must match the container side of the panel ports: mapping. |
CCPG_PROXY_PORT |
49250 |
Yes | Internal gateway proxy port the daemon listens on. Must match the container side of the proxy ports: mapping. |
CC_GATEWAY_BIND_HOST |
0.0.0.0 |
Yes | Bind address for both daemon servers. Docker needs 0.0.0.0 so published ports can reach the process. |
| Variable | Default | Description |
|---|---|---|
CCPG_AUTH_TOKEN |
Auto-generated and encrypted | Fixed gateway auth token. Usually leave unset so CCPG generates and persists one. Set only if you intentionally need a stable externally managed token. |
CCPG_PANEL_ORIGINS |
Empty | Comma-separated extra browser origins allowed to call the panel API, for example https://ccpg.example.com. http://localhost:<panelPort> and http://127.0.0.1:<panelPort> are allowed automatically. |
CC_GATEWAY_SECRET_KEY |
/data/secret.key or generated |
32-byte hex AES-256-GCM master key. In Docker, prefer the persisted /data/secret.key unless you manage secrets externally. |
NO_PROXY |
Localhost entries are ensured | Hosts that bypass the outbound proxy. CCPG always includes localhost, 127.0.0.1, and ::1. |
CCPG_DISABLE_HOST_SHELL_SETUP |
unset | Disables automatic shell setup in host runtimes. Docker mode already disables automatic host shell setup. |
These are not needed for the Docker/Web production path:
| Variable | Used by | Description |
|---|---|---|
CC_GATEWAY_EXTERNAL_DAEMON |
Desktop/source dev | Tells the desktop app that a dev daemon is managed externally. |
VITE_CC_GATEWAY_EXTERNAL_DAEMON |
Panel/source dev | Tells the Vite dev panel how to reach an external daemon. |
In Docker/Web, the Settings page does not control published Docker ports. Change ports in Compose before the container starts.
Example: run the panel on 7777 and the gateway on 49300.
services:
ccpg:
environment:
CCPG_PANEL_PORT: "7777"
CCPG_PROXY_PORT: "49300"
ports:
- "7777:7777"
- "49300:49300"Then recreate:
docker compose up -d --buildOpen:
| Service | URL |
|---|---|
| Panel | http://localhost:7777 |
| Gateway | http://localhost:49300/v1 |
You can keep the internal container ports unchanged and publish different host ports:
services:
ccpg:
environment:
CCPG_PANEL_PORT: "6767"
CCPG_PROXY_PORT: "49250"
ports:
- "7777:6767"
- "49300:49250"Use this when you want the container to keep defaults but avoid host port conflicts. The dashboard and generated launch commands are based on the daemon config, so same host/container ports are simpler for local Claude Code usage.
The default Compose file persists /data in a named volume:
volumes:
- ccpg_data:/dataFiles stored under /data include:
| Path | Purpose |
|---|---|
/data/ccpg.sqlite |
Config document, encrypted secrets, current sessions, and session archive |
/data/secret.key |
Master key used to encrypt secret values when CC_GATEWAY_SECRET_KEY is not set |
/data/daemon.log |
Daemon log file |
/data/provider-logos/ |
Uploaded custom provider logos and support files |
Do not delete /data/secret.key unless you also intend to reset encrypted
secrets. If the key is lost, existing encrypted provider keys and OAuth tokens
cannot be decrypted.
Stop the container before taking a consistent backup:
docker compose down
docker run --rm -v cc-provider-gtw_ccpg_data:/data -v "$PWD":/backup alpine \
tar czf /backup/ccpg-data-backup.tgz -C /data .
docker compose up -dIf your Compose project name differs, the volume name may not be
cc-provider-gtw_ccpg_data. Check it with:
docker volume ls | grep ccpg_datadocker compose down
docker run --rm -v cc-provider-gtw_ccpg_data:/data -v "$PWD":/backup alpine \
sh -c "rm -rf /data/* && tar xzf /backup/ccpg-data-backup.tgz -C /data"
docker compose up -dDocker/Web cannot auto-install the ccpg shell function into your host shell.
The container sees its own filesystem, not your host ~/.zshrc, ~/.bashrc,
Fish config, or PowerShell profile.
Use the dashboard:
- Open
http://localhost:6767. - Go to Dashboard -> Terminal Integration.
- Copy the manual command for your shell.
- Paste it into a terminal on the host system.
- Relaunch the terminal.
Then launch Claude Code from the host:
ccpg --OpenRouter
ccpg --CommandCode
ccpg --ModelChain
ccpg --allThe shell function asks the panel API to prepare a session, exports the required
Claude Code environment variables, starts claude on the host, and sends
session heartbeats back to the container.
Configure providers from the browser panel exactly as in the desktop app:
- Open Providers.
- Enable a built-in provider or add a custom OpenAI/Anthropic-compatible provider.
- Add the API key or complete OAuth where supported.
- Click Test.
- Launch through Quick Launch or the host shell
ccpgfunction.
Secrets are encrypted before persistence. In Docker/Web, encrypted secret
entries live in SQLite and are protected by /data/secret.key or
CC_GATEWAY_SECRET_KEY.
The Settings -> Outbound Proxy section is still useful in Docker/Web. It routes provider API calls, model catalog fetches, and OAuth token exchanges through an HTTP/HTTPS proxy.
Use it when:
- Your network requires an outbound corporate proxy.
- A provider blocks direct traffic from your current region.
- OAuth token exchange succeeds only through a supported network.
The URL must start with http:// or https:// and must not contain embedded
credentials.
Example:
http://proxy.internal:8080
Proxy changes require a container restart because outbound network setup is configured during daemon startup:
docker compose restart ccpgIf the proxy itself runs on the Docker host, avoid 127.0.0.1 inside the
container because that points at the container. Use a host-reachable address,
for example host.docker.internal where supported, a LAN IP, or a proxy
container on the same Docker network.
You can put the panel behind a reverse proxy such as Caddy, Nginx, Traefik, or Cloudflare Tunnel. In that case:
- Keep
CC_GATEWAY_BIND_HOST=0.0.0.0inside the container. - Publish or proxy the panel port.
- Add the public panel origin to
CCPG_PANEL_ORIGINS. - Restart the container.
Example:
services:
ccpg:
environment:
CCPG_PANEL_ORIGINS: "https://ccpg.example.com"
ports:
- "127.0.0.1:6767:6767"
- "127.0.0.1:49250:49250"Keep the gateway proxy private unless you intentionally need remote OpenAI-compatible access. The proxy requires an auth token, but it is designed for local/private use.
External OpenAI-compatible tools can use the gateway:
| Field | Value |
|---|---|
| Base URL | http://127.0.0.1:49250/v1 |
| API key | Gateway auth token from the panel's OpenAI Gateway view |
| Models endpoint | GET /v1/models |
| Chat endpoint | POST /v1/chat/completions |
If you changed the host proxy port, update the base URL accordingly.
Rebuild and restart:
git pull
docker compose up -d --buildThe SQLite database and master key remain in the ccpg_data volume. If a future
release changes the storage schema, migrations are applied by the daemon on
startup.
The image and Compose file use a healthcheck against the panel API:
fetch('http://127.0.0.1:'+(process.env.CCPG_PANEL_PORT||6767)+'/api/status')Useful commands:
docker compose ps
docker inspect --format '{{json .State.Health}}' cc-provider-gtw-ccpg-1
docker compose logs -f ccpgThe exact container name depends on the Compose project name.
- Do not publish the panel or gateway to the public internet without an authenticated reverse proxy or private network boundary.
- Keep
/data/secret.keyprivate. It protects encrypted provider keys, OAuth tokens, and the gateway auth token. - Prefer loopback-only host publishing when a reverse proxy runs on the same host:
ports:
- "127.0.0.1:6767:6767"
- "127.0.0.1:49250:49250"- Leave
CCPG_AUTH_TOKENunset unless you deliberately manage the gateway token outside CCPG.
Check the container and logs:
docker compose ps
docker compose logs -f ccpg
curl -s http://127.0.0.1:6767/api/statusConfirm:
CC_GATEWAY_BIND_HOST=0.0.0.0CCPG_PANEL_PORTmatches the container side of the panelports:mapping- No other process is already using the host panel port
If you access the panel through a custom hostname or reverse proxy, set
CCPG_PANEL_ORIGINS to that exact origin:
environment:
CCPG_PANEL_ORIGINS: "https://ccpg.example.com"Then restart:
docker compose restart ccpgThis usually means Claude Code on the host is not reaching the container proxy or is not using the generated gateway environment variables.
Check from the host:
curl -s http://127.0.0.1:49250/Then reinstall or refresh the manual Terminal Integration snippet from the dashboard and launch through:
ccpg --CommandCodeIn Docker/Web, automatic install is intentionally disabled because it would edit the container shell. Use the manual snippet in a host terminal.
Configure Settings -> Outbound Proxy, save, and restart the container:
docker compose restart ccpgIf your proxy is on the host, use a host-reachable address instead of
127.0.0.1.
Changing the Settings page is not enough in Docker/Web. Update
docker-compose.yml, then recreate:
docker compose up -d --buildIf you changed host ports only, update your browser URL, OpenAI-compatible client base URL, and any manually copied launch commands.