Production Deployment
Breeze ships as pre-built Docker images on GitHub Container Registry. A single docker compose up -d brings up a fully working production stack with automatic TLS.
What Gets Deployed
Section titled “What Gets Deployed”The core stack (docker-compose.yml) includes:
| Service | Image | Purpose |
|---|---|---|
| Binaries Init | ghcr.io/lanternops/breeze/binaries |
Copies agent/viewer binaries to a shared volume, then exits |
| Caddy | caddy:2.8-alpine |
Reverse proxy, auto-TLS, security headers |
| API | ghcr.io/lanternops/breeze/api |
Hono API server |
| Web | ghcr.io/lanternops/breeze/web |
Astro SSR dashboard |
| Portal | ghcr.io/lanternops/breeze/portal |
Astro SSR customer portal, served under /portal (see Customer Portal) |
| PostgreSQL | pgvector/pgvector:pg16 |
Primary database |
| Redis | redis:7-alpine |
Job queue, caching, rate limiting |
| Coturn | coturn/coturn:4-alpine |
TURN relay server for WebRTC remote desktop (opt-in via --profile turn) |
The pgvector extension is required only if you enable the Workspace built-in (BREEZE_WORKSPACE_ENABLED=true), which uses it for content embeddings. Workspace ships inside the API image but is off by default: with the flag unset, no Workspace migrations run and any Postgres 16 image works. The bundled POSTGRES_IMAGE_REF default is pgvector-capable regardless, so enabling Workspace later needs no database swap — supply your own Postgres image and you must provide pgvector yourself before setting the flag, or the API will fail to start with extension "vector" is not available.
An optional monitoring stack (Prometheus, Grafana, Alertmanager, Loki, Promtail, exporters) is available as a separate overlay — see Monitoring.
An optional m365-graph-read-executor sidecar (published as ghcr.io/lanternops/breeze/m365-graph-read-executor) isolates the Microsoft 365 customer Graph-read certificate and Key Vault access away from the API. It is only exercised when Customer Graph-read consent is enabled (M365_CUSTOMER_GRAPH_READ_ONBOARDING_ENABLED=true); otherwise it sits idle and can be left undeployed. It is not part of the bundled compose files by default — see Customer Microsoft 365 Graph-read consent for the full variable contract, including the private base URL and read-only signing-key mount it depends on.
Deploy Steps
Section titled “Deploy Steps”-
Prepare the server
You need Docker and Docker Compose on a Linux VPS. See Prerequisites.
-
Clone and configure
Terminal window git clone https://github.com/LanternOps/breeze.gitcd breezecp .env.example .env -
Set your domain and secrets
Edit
.envand set these required values:Terminal window BREEZE_DOMAIN=breeze.yourdomain.comACME_EMAIL=admin@yourdomain.comGenerate all secrets at once:
Terminal window for key in JWT_SECRET APP_ENCRYPTION_KEY MFA_ENCRYPTION_KEY \ENROLLMENT_KEY_PEPPER MFA_RECOVERY_CODE_PEPPER \METRICS_SCRAPE_TOKEN SESSION_SECRET TURN_SECRET; doecho "${key}=$(openssl rand -hex 32)"doneecho "AGENT_ENROLLMENT_SECRET=$(openssl rand -hex 32)"echo "POSTGRES_PASSWORD=$(openssl rand -base64 24 | tr -d '/+=')"echo "REDIS_PASSWORD=$(openssl rand -hex 32)"Paste the output into
.env.Then set these required deployment-mode flags. Without them the API refuses to boot in production:
Terminal window # Self-hosted by default. Set to "true" only if you're running the hosted SaaS edition.IS_HOSTED=false# Trust anchor (raw base64 Ed25519 public key) for the official Breeze GitHub# releases. This is a public key — also embedded in the agent and CI — so it is# safe to commit. Leave the default below unless you build and sign your own binaries.RELEASE_ARTIFACT_MANIFEST_PUBLIC_KEYS=yzx8ftmcls6uBetFC5SYnZhBo+cbur3IX50TbBthTso=If Breeze is behind a reverse proxy, also set
TRUST_PROXY_HEADERS=trueand list the proxy’s CIDRs inTRUSTED_PROXY_CIDRS. See Environment Variables for details. -
Configure TURN server
The TURN server enables remote desktop connectivity across NATs and firewalls. Set the server’s public IP address:
Terminal window # Set to this server's public IP address (required for remote desktop)TURN_HOST=203.0.113.10# Optional: TURN realm (defaults to breeze.local)TURN_REALM=breeze.localCoturn is behind a Docker Compose profile and does not start by default. To enable it:
Terminal window docker compose --profile turn up -dOr add
COMPOSE_PROFILES=turnto your.envfile for persistent activation. -
Start the stack
Terminal window docker compose up -dThat’s it. On first start, the API container automatically runs database migrations and seeds the initial admin user. Caddy obtains a TLS certificate from Let’s Encrypt.
-
Verify the deployment
Terminal window # Check healthcurl https://breeze.yourdomain.com/health# Check running containersdocker compose ps# View API logsdocker compose logs -f api
Adding Monitoring
Section titled “Adding Monitoring”The monitoring stack lives in a separate compose overlay file (docker-compose.monitoring.yml) and includes Prometheus, Grafana, Alertmanager, Loki, Promtail, and database exporters.
To deploy with monitoring:
docker compose -f docker-compose.yml -f docker-compose.monitoring.yml up -dAdd a Grafana password to .env:
GRAFANA_ADMIN_PASSWORD=$(openssl rand -base64 16 | tr -d '/+=')Grafana is available at http://127.0.0.1:3000 (localhost only by default).
Pinning a Version
Section titled “Pinning a Version”By default, images pull the latest tag. To pin to a specific release:
# In .envBREEZE_VERSION=0.67.1Then pull and restart:
docker compose pull && docker compose up -dResource Tuning
Section titled “Resource Tuning”Override default resource limits via environment variables:
# Redis memory limit (default: 256mb)REDIS_MAXMEMORY=512mbRedis Authentication
Section titled “Redis Authentication”Redis password authentication is required in production. The API will refuse to start if REDIS_URL doesn’t carry a password. The secret-generation loop above already produces REDIS_PASSWORD; pair it with a REDIS_URL that uses it:
REDIS_PASSWORD=$(openssl rand -hex 32)REDIS_URL=redis://:${REDIS_PASSWORD}@redis:6379The docker-compose.yml passes REDIS_PASSWORD to the Redis container automatically. See Environment Variables for details.
Updating
Section titled “Updating”cd breezegit pull origin maindocker compose pulldocker compose up -dPre-built images are pulled from GHCR. Database migrations run automatically on startup.