# Deployment Guide ## Docker Single-Instance ```bash docker pull ghcr.io/switchboard-core/switchboard-core:latest docker run -p 8080:80 \ -e SWITCHBOARD_ADMIN_USERNAME=admin \ -e SWITCHBOARD_ADMIN_PASSWORD=changeme \ -e JWT_SECRET="$(openssl rand -hex 32)" \ -e ENCRYPTION_KEY="$(openssl rand -hex 32)" \ -v switchboard-data:/data \ ghcr.io/switchboard-core/switchboard-core:latest ``` This runs with SQLite and PVC storage. Suitable for evaluation and small teams. ## Docker Compose with PostgreSQL ```yaml services: postgres: image: postgres:16 environment: POSTGRES_DB: switchboard POSTGRES_USER: switchboard POSTGRES_PASSWORD: secretpassword volumes: - pg_data:/var/lib/postgresql/data switchboard: image: ghcr.io/switchboard-core/switchboard-core:latest ports: - "8080:80" environment: DATABASE_URL: "postgres://switchboard:secretpassword@postgres:5432/switchboard?sslmode=disable" JWT_SECRET: "change-me-in-production" ENCRYPTION_KEY: "change-me-in-production" SWITCHBOARD_ADMIN_USERNAME: admin SWITCHBOARD_ADMIN_PASSWORD: changeme STORAGE_BACKEND: pvc STORAGE_PATH: /data/storage volumes: - sb_storage:/data/storage depends_on: - postgres volumes: pg_data: sb_storage: ``` ## Kubernetes See the `k8s/` directory for example manifests. Key considerations: - Set `POSTGRES_HOST`, `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_DB` env vars (assembled into DSN automatically). - Liveness probe: `/healthz/live`. Readiness probe: `/healthz/ready`. - Mount a PVC at `/data/storage` or configure S3. - Store `JWT_SECRET` and `ENCRYPTION_KEY` in Kubernetes Secrets. - Registry: `registry.gobha.me:5000/xcaliber/switchboard-core`. ## Environment Variables | Variable | Default | Description | |----------|---------|-------------| | `PORT` | `8080` | Backend API port | | `DB_DRIVER` | auto | `postgres` or `sqlite` | | `DATABASE_URL` | | PostgreSQL DSN or SQLite path | | `JWT_SECRET` | `dev-secret-change-me` | Token signing key -- **must change** | | `ENCRYPTION_KEY` | | AES-256 key for credential vault | | `AUTH_MODE` | `builtin` | `builtin`, `mtls`, `oidc` | | `STORAGE_BACKEND` | auto | `pvc` or `s3` | | `STORAGE_PATH` | `/data/storage` | PVC mount point | | `BASE_PATH` | | URL prefix (e.g., `/switchboard`) | | `LOG_FORMAT` | `text` | `text` or `json` | | `LOG_LEVEL` | `info` | `debug`, `info`, `warn`, `error` | | `CORS_ALLOWED_ORIGINS` | | Comma-separated allowed origins | | `BUNDLED_PACKAGES` | (empty) | `""` defaults, `"*"` all, or comma-separated | | `SKIP_BUNDLED_PACKAGES` | `false` | Disable bundled package install | | `BUNDLED_PACKAGES_DIR` | `/app/bundled-packages` | Custom bundle directory | | `SWITCHBOARD_ADMIN_USERNAME` | | Bootstrap admin username | | `SWITCHBOARD_ADMIN_PASSWORD` | | Bootstrap admin password | | `SEED_USERS` | | Dev seed users (ignored in production) | ### S3 Storage Variables | Variable | Description | |----------|-------------| | `S3_BUCKET` | Bucket name | | `S3_ENDPOINT` | Endpoint URL (for MinIO, Ceph, etc.) | | `S3_ACCESS_KEY` | Access key | | `S3_SECRET_KEY` | Secret key | | `S3_FORCE_PATH_STYLE` | `true` for MinIO/Ceph | ### Cluster Variables (Multi-Replica) | Variable | Default | Description | |----------|---------|-------------| | `CLUSTER_NODE_ID` | hostname-PID | Override for deterministic node identity | | `CLUSTER_HEARTBEAT_INTERVAL` | `10s` | Heartbeat tick frequency | | `CLUSTER_STALE_THRESHOLD` | `30s` | 3x heartbeat = stale node | | `CLUSTER_ENDPOINT` | auto-detect | Advertised address for peer mesh | ## Database Configuration **PostgreSQL** (recommended for production): ```bash DATABASE_URL="postgres://user:pass@host:5432/switchboard?sslmode=require" ``` **SQLite** (dev, test, edge deployments): ```bash DB_DRIVER=sqlite DATABASE_URL=/data/switchboard.db ``` Both databases are first-class -- every query compiles and passes tests on both. The driver is auto-detected from `DATABASE_URL` if `DB_DRIVER` is not set. ## Cluster Mode Multi-replica HA requires PostgreSQL. The kernel uses PG-backed WebSocket tickets and rate limit counters to coordinate across replicas. A cluster registry with heartbeat and stale sweep tracks active nodes. View cluster status in Admin > Cluster or via `GET /api/v1/admin/cluster`. ## Storage Backends **PVC**: Auto-detected if the storage path is writable. Mount a volume at `/data/storage`. **S3-compatible**: Set `STORAGE_BACKEND=s3` and provide S3 variables. Works with AWS S3, MinIO, and Ceph. ## Backup and Restore Available via Admin UI or API: ``` POST /api/v1/admin/backup # Create backup GET /api/v1/admin/backups # List backups GET /api/v1/admin/backups/:name # Download backup POST /api/v1/admin/restore # Restore from backup DELETE /api/v1/admin/backups/:name # Delete backup ``` ## Monitoring | Endpoint | Purpose | |----------|---------| | `/health` | Basic health check | | `/healthz/live` | Kubernetes liveness probe | | `/healthz/ready` | Kubernetes readiness probe | | `/metrics` | Prometheus metrics |