PilotDeck Docker

July 9, 2026 · View on GitHub

简体中文版本:README_DOCKER.zh.md

PilotDeck runs as two cooperating Node.js processes in the container:

  • Gateway: agent runtime on PILOTDECK_GATEWAY_PORT (default 18789)
  • UI Server: web frontend + REST/WebSocket adapter on SERVER_PORT (default 3001)

The Docker Compose setup persists the full PILOT_HOME directory, including generated config, auth DB, permissions, sessions/projects, memory, skills/plugins, and router stats.

Quick Start with Docker Compose

Prerequisites

Make sure the Docker daemon is running before starting PilotDeck. On macOS/Windows, start Docker Desktop first and wait until the engine is ready:

docker info

The first build pulls base images such as node:22-bookworm and node:22-bookworm-slim from Docker Hub. If pulling images is slow or fails with context deadline exceeded, configure a Docker registry mirror or Docker Desktop proxy, then retry docker compose up -d --build. On Docker Desktop, registry mirrors can be configured in Settings → Docker Engine. On Linux, add mirrors to /etc/docker/daemon.json, then restart Docker.

The container installs dependencies with Node.js 22 and the committed pnpm-lock.yaml inside the image, so it does not use the host Node.js runtime or host CPU architecture for native Node modules. The legacy sqlite/sqlite3 packages are not required by PilotDeck and are not part of the source install path.

As a one-off workaround, you can pre-pull the required Node images from a reachable mirror and tag them with the names used by the Dockerfile:

docker pull mirror.gcr.io/library/node:22-bookworm
docker pull mirror.gcr.io/library/node:22-bookworm-slim
docker tag mirror.gcr.io/library/node:22-bookworm node:22-bookworm
docker tag mirror.gcr.io/library/node:22-bookworm-slim node:22-bookworm-slim

The Docker build also downloads Debian and npm packages inside the image, so slow package registries may still require a stable network proxy.

Option A: Configure via environment variables

Set the model provider variables in docker-compose.yml or an .env file:

PILOTDECK_MODEL=openai/gpt-4.1
PILOTDECK_API_KEY=sk-your-api-key
PILOTDECK_API_URL=https://api.openai.com/v1

Then start:

docker compose up -d --build

If /root/.pilotdeck/pilotdeck.yaml does not exist in the pilotdeck-home volume, the entrypoint generates it from the PILOTDECK_* environment variables on first start.

Option B: Configure via YAML file

Create the host config file first:

mkdir -p ~/.pilotdeck
cat > ~/.pilotdeck/pilotdeck.yaml <<'YAML'
schemaVersion: 1
agent:
  model: openai/gpt-4.1
model:
  providers:
    openai:
      protocol: openai
      url: https://api.openai.com/v1
      apiKey: sk-your-api-key
      models:
        gpt-4.1: {}
YAML

Then uncomment the config bind mount in docker-compose.yml:

volumes:
  - pilotdeck-home:/root/.pilotdeck
  - ${PILOTDECK_CONFIG:-${HOME}/.pilotdeck/pilotdeck.yaml}:/root/.pilotdeck/pilotdeck.yaml:ro

Start the service:

docker compose up -d --build

The UI is available at http://localhost:3001.

Workspace Mounts

Agents run inside the container. To let them access a host project, mount it into /workspace by uncommenting the workspace bind mount:

volumes:
  - pilotdeck-home:/root/.pilotdeck
  - ${PILOTDECK_WORKSPACE:-${PWD}}:/workspace

You can set PILOTDECK_WORKSPACE=/path/to/project before running docker compose up.

Manual Docker Build & Run

Build the image

docker build -t pilotdeck:latest .

Run with environment variables

docker run -d --name pilotdeck \
  -p 3001:3001 \
  -v pilotdeck-home:/root/.pilotdeck \
  -e PILOTDECK_MODEL=openai/gpt-4.1 \
  -e PILOTDECK_API_KEY=sk-your-api-key \
  -e PILOTDECK_API_URL=https://api.openai.com/v1 \
  pilotdeck:latest

Run with a config file

docker run -d --name pilotdeck \
  -p 3001:3001 \
  -v pilotdeck-home:/root/.pilotdeck \
  -v ~/.pilotdeck/pilotdeck.yaml:/root/.pilotdeck/pilotdeck.yaml:ro \
  pilotdeck:latest

Run with a workspace mount

docker run -d --name pilotdeck \
  -p 3001:3001 \
  -v pilotdeck-home:/root/.pilotdeck \
  -v "$PWD":/workspace \
  -e PILOTDECK_MODEL=openai/gpt-4.1 \
  -e PILOTDECK_API_KEY=sk-your-api-key \
  -e PILOTDECK_API_URL=https://api.openai.com/v1 \
  pilotdeck:latest

Run with a proxy

docker run -d --name pilotdeck \
  -p 3001:3001 \
  -v pilotdeck-home:/root/.pilotdeck \
  -e PILOTDECK_MODEL=openai/gpt-4.1 \
  -e PILOTDECK_API_KEY=sk-your-api-key \
  -e PILOTDECK_API_URL=https://api.openai.com/v1 \
  -e PILOTDECK_PROXY=http://host.docker.internal:7890 \
  pilotdeck:latest

Environment Variables

VariableDescriptionDefault
PILOT_HOMEPilotDeck state directory inside the container/root/.pilotdeck
PILOTDECK_MODELMain model identifier, formatted as provider/modelopenrouter/deepseek/deepseek-v4-flash
PILOTDECK_LIGHT_MODELLightweight routing/judge model identifieropenrouter/qwen/qwen3-8b
PILOTDECK_API_KEYAPI key for the main model providerPLACEHOLDER_RUN_ONBOARDING_TO_REPLACE
PILOTDECK_API_URLBase URL for the main model provider APIhttps://openrouter.ai/api/v1
PILOTDECK_LIGHT_API_KEYAPI key for a different light-model providerFalls back to PILOTDECK_API_KEY
PILOTDECK_LIGHT_API_URLBase URL for a different light-model providerFalls back to PILOTDECK_API_URL
PILOTDECK_PROXYHTTP/HTTPS proxy URL
SERVER_PORTUI server port3001
PILOTDECK_GATEWAY_PORTGateway port used by the UI bridge18789

Architecture

Browser (localhost:3001) ──► UI Server (port 3001) ──► Gateway (port 18789)

Both processes are managed by concurrently inside the Docker container.

Development

npm install
npm run dev

This starts the Gateway and UI dev server with hot reload.