mission-control/docs/deployment.md

4.6 KiB

Deployment Guide

Prerequisites

  • Node.js >= 20 (LTS recommended)
  • pnpm (installed via corepack: corepack enable && corepack prepare pnpm@latest --activate)

Ubuntu / Debian

better-sqlite3 requires native compilation tools:

sudo apt-get update
sudo apt-get install -y python3 make g++

macOS

Xcode command line tools are required:

xcode-select --install

Quick Start (Development)

cp .env.example .env.local
pnpm install
pnpm dev

Open http://localhost:3000. Login with AUTH_USER / AUTH_PASS from your .env.local.

Production (Direct)

pnpm install --frozen-lockfile
pnpm build
pnpm start

The pnpm start script binds to 0.0.0.0:3005. Override with:

PORT=3000 pnpm start

Important: The production build bundles platform-specific native binaries. You must run pnpm install and pnpm build on the same OS and architecture as the target server. A build created on macOS will not work on Linux.

Production (Standalone)

Use this for bare-metal deployments that run Next's standalone server directly. This path is preferred over ad hoc node .next/standalone/server.js because it syncs .next/static and public/ into the standalone bundle before launch.

pnpm install --frozen-lockfile
pnpm build
pnpm start:standalone

For a full in-place update on the target host:

BRANCH=fix/refactor PORT=3000 pnpm deploy:standalone

What deploy:standalone does:

  • fetches and fast-forwards the requested branch
  • reinstalls dependencies with the lockfile
  • rebuilds from a clean .next/
  • stops the old process bound to the target port
  • starts the standalone server through scripts/start-standalone.sh
  • verifies that the rendered login page references a CSS asset and that the CSS is served as text/css

Production (Docker)

docker build -t mission-control .
docker run -p 3000:3000 \
  -v mission-control-data:/app/.data \
  -e AUTH_USER=admin \
  -e AUTH_PASS=your-secure-password \
  -e API_KEY=your-api-key \
  mission-control

The Docker image:

  • Builds from node:20-slim with multi-stage build
  • Compiles better-sqlite3 natively inside the container (Linux x64)
  • Uses Next.js standalone output for minimal image size
  • Runs as non-root user nextjs
  • Exposes port 3000 (override with -e PORT=8080)

Persistent Data

SQLite database is stored in /app/.data/ inside the container. Mount a volume to persist data across restarts:

docker run -v /path/to/data:/app/.data ...

Environment Variables

See .env.example for the full list. Key variables:

Variable Required Default Description
AUTH_USER Yes admin Admin username (seeded on first run)
AUTH_PASS Yes - Admin password
AUTH_PASS_B64 No - Base64-encoded admin password (overrides AUTH_PASS if set)
API_KEY Yes - API key for headless access
PORT No 3005 (direct) / 3000 (Docker) Server port
OPENCLAW_HOME No - Path to OpenClaw installation
MC_ALLOWED_HOSTS No localhost,127.0.0.1 Allowed hosts in production

Troubleshooting

"Module not found: better-sqlite3"

Native compilation failed. On Ubuntu/Debian:

sudo apt-get install -y python3 make g++
rm -rf node_modules
pnpm install

AUTH_PASS with "#" is not working

In dotenv files, # starts a comment unless the value is quoted.

Use one of these:

  • AUTH_PASS="my#password"
  • AUTH_PASS_B64=$(echo -n 'my#password' | base64)

"pnpm-lock.yaml not found" during Docker build

If your deployment context omits pnpm-lock.yaml, Docker build now falls back to pnpm install --no-frozen-lockfile.

For reproducible builds, include pnpm-lock.yaml in the build context.

"Invalid ELF header" or "Mach-O" errors

The native binary was compiled on a different platform. Rebuild:

rm -rf node_modules .next
pnpm install
pnpm build

Database locked errors

Ensure only one instance is running against the same .data/ directory. SQLite uses WAL mode but does not support multiple writers.

"Gateway error: origin not allowed"

Your gateway is rejecting the Mission Control browser origin. Add the Control UI origin to your gateway config allowlist, for example:

{
  "gateway": {
    "controlUi": {
      "allowedOrigins": ["http://YOUR_HOST:3000"]
    }
  }
}

Then restart the gateway and reconnect from Mission Control.

"Gateway error: device identity required"

Device identity signing uses WebCrypto and requires a secure browser context. Open Mission Control over HTTPS (or localhost), then reconnect.