Running Copilot API in Docker lets you keep the proxy running as a long-lived container without needing Node.js or Bun installed on your host. Tokens and request history are stored in a mounted volume so they survive container restarts. This page covers building the image, running with persistent storage, passing credentials via environment variables, using Docker Compose, and managing multiple accounts.
Build the image
Clone the Copilot API repository and build the Docker image from source:
git clone https://github.com/nick3/copilot-api.git
cd copilot-api
docker build -t copilot-api .
The image uses a multi-stage build to keep the final image small, runs as a non-root user for security, and includes a health check at http://localhost:4141/.
Run with persistent storage
Create a directory on your host to store tokens and request history, then mount it into the container:
mkdir -p ./copilot-data
docker run -p 4141:4141 \
-v $(pwd)/copilot-data:/root/.local/share/copilot-api \
copilot-api
The container stores two important items in the mounted directory:
- Authentication tokens — GitHub and Copilot tokens acquired during the OAuth flow
admin.sqlite — Request history database used by the Admin UI at /admin
Without the volume mount, both are lost when the container stops.
Run with a GitHub token
If you already have a GitHub token, pass it directly as an environment variable to skip the interactive OAuth flow:
docker run -p 4141:4141 \
-e GH_TOKEN=your_github_token_here \
copilot-api
Additional environment variables
You can combine environment variables to configure authentication and access control:
# Enable remote Admin UI access
docker run -p 4141:4141 \
-e GH_TOKEN=your_github_token_here \
-e ADMIN_TOKEN=your_admin_token_here \
copilot-api
# Enable request authentication (clients must send an API key)
docker run -p 4141:4141 \
-e GH_TOKEN=your_github_token_here \
-e COPILOT_API_KEY=your_api_key_here \
copilot-api
| Variable | Purpose |
|---|
GH_TOKEN | GitHub personal access token — skips interactive OAuth |
ADMIN_TOKEN | Required to access the Admin UI and API from non-localhost addresses |
COPILOT_API_KEY | Requires all proxy requests to include this key; use auth.apiKeys in config.json for multi-key support |
COPILOT_API_KEY is a legacy fallback. For new setups, configure auth.apiKeys in config.json and mount it into the container, or use the Admin API to update the configuration.
Docker Compose
Use Docker Compose for a more reproducible setup:
version: "3.8"
services:
copilot-api:
build: .
ports:
- "4141:4141"
environment:
- GH_TOKEN=your_github_token_here
- ADMIN_TOKEN=your_admin_token_here
- COPILOT_API_KEY=your_api_key_here
restart: unless-stopped
Save this as docker-compose.yml in the repository root, then run:
Add a volume to the Compose file to persist tokens and request history across deployments:services:
copilot-api:
# ...
volumes:
- ./copilot-data:/root/.local/share/copilot-api
Add multiple accounts
The Docker image’s entrypoint runs the start command by default. To run auth subcommands inside the container, prefix them with --auth.
Add accounts one at a time. Each run opens an interactive OAuth flow:
docker run -it \
-v $(pwd)/copilot-data:/root/.local/share/copilot-api \
copilot-api --auth add
# Repeat to add a second account
docker run -it \
-v $(pwd)/copilot-data:/root/.local/share/copilot-api \
copilot-api --auth add
List all registered accounts and their quota status:
docker run -it \
-v $(pwd)/copilot-data:/root/.local/share/copilot-api \
copilot-api --auth ls -q
All account data — tokens and the account registry — is stored in the mounted copilot-data directory. When the proxy runs with multiple accounts, premium-model requests use accounts in order and automatically switch when one account’s premium quota is exhausted. Free-model requests are distributed round-robin across accounts by default.
Docker image features
The included Dockerfile provides:
- Multi-stage build — builder stage installs dependencies and compiles; runner stage copies only production artifacts, keeping the final image small
- Non-root user — the container runs as a non-root user to reduce the attack surface
- Health check — Docker monitors
http://localhost:4141/ every 30 seconds and marks the container unhealthy after 3 failed attempts
- Pinned base image —
oven/bun:1.3.11-alpine is pinned by version for reproducible builds