Skip to main content
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
VariablePurpose
GH_TOKENGitHub personal access token — skips interactive OAuth
ADMIN_TOKENRequired to access the Admin UI and API from non-localhost addresses
COPILOT_API_KEYRequires 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:
docker compose up -d
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 imageoven/bun:1.3.11-alpine is pinned by version for reproducible builds