mission-control/docs/deployment.md

178 lines
4.6 KiB
Markdown

# 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:
```bash
sudo apt-get update
sudo apt-get install -y python3 make g++
```
### macOS
Xcode command line tools are required:
```bash
xcode-select --install
```
## Quick Start (Development)
```bash
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)
```bash
pnpm install --frozen-lockfile
pnpm build
pnpm start
```
The `pnpm start` script binds to `0.0.0.0:3005`. Override with:
```bash
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.
```bash
pnpm install --frozen-lockfile
pnpm build
pnpm start:standalone
```
For a full in-place update on the target host:
```bash
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)
```bash
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:
```bash
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:
```bash
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:
```bash
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:
```json
{
"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.