Environment Variables
All configuration is done through environment variables, defined in your .env.prod file. This page documents every variable.
Database
Section titled “Database”| Variable | Default | Required | Description |
|---|---|---|---|
| POSTGRES_USER | breeze | | PostgreSQL username |
| POSTGRES_PASSWORD | — | Yes | PostgreSQL password |
| POSTGRES_DB | breeze | | Database name |
| POSTGRES_PORT | 5432 | | PostgreSQL port |
| DATABASE_URL | — | Auto | Full connection string (constructed from above in Docker) |
| Variable | Default | Required | Description |
|---|---|---|---|
| REDIS_URL | redis://localhost:6379 | Yes (prod) | Redis connection URL. Must carry a password in production (e.g., redis://:password@localhost:6379) — the API refuses to boot if it doesn’t. |
| REDIS_PORT | 6379 | | Redis port |
| REDIS_PASSWORD | — | Yes (prod) | Password for Redis authentication. Set in docker-compose and include in REDIS_URL. |
| REDIS_PASSWORD_FILE | — | | Path to a file containing the Redis password (Docker secret style). Used in place of REDIS_PASSWORD when secrets are mounted as files. |
Authentication & Security
Section titled “Authentication & Security”| Variable | Default | Required | Description |
|---|---|---|---|
| JWT_SECRET | — | Yes | JWT signing key (min 32 chars). Generate: openssl rand -base64 64 |
| JWT_EXPIRES_IN | 15m | | Access token lifetime |
| REFRESH_TOKEN_EXPIRES_IN | 7d | | Refresh token lifetime |
| AGENT_ENROLLMENT_SECRET | — | Yes | Shared secret for agent enrollment. Generate: openssl rand -hex 32 |
| APP_ENCRYPTION_KEY | — | Yes | AES encryption key for sensitive data at rest |
| MFA_ENCRYPTION_KEY | — | Yes | Encryption key for MFA secrets |
| ENROLLMENT_KEY_PEPPER | — | Yes | HMAC pepper for enrollment key hashing |
| MFA_RECOVERY_CODE_PEPPER | — | Yes | HMAC pepper for recovery code hashing |
| ENROLLMENT_KEY_DEFAULT_TTL_MINUTES | 60 | | Default enrollment key expiry |
| SESSION_SECRET | — | Yes | Express session signing secret |
| SESSION_MAX_AGE | 86400000 | | Session max age in ms (24h) |
Server
Section titled “Server”| Variable | Default | Required | Description |
|---|---|---|---|
| NODE_ENV | production | | Environment mode |
| API_PORT | 3001 | | API server port |
| WEB_PORT | 4321 | | Web dashboard port |
| PUBLIC_API_URL | https://${BREEZE_DOMAIN} (bundled compose only) | | Public API URL used for generated agent installers and shareable links. The bundled docker-compose.yml derives this from BREEZE_DOMAIN. If you use a custom compose file, you must set PUBLIC_API_URL in .env and map it into the api service environment: block, or Generate Link / Download Installer will fail with Server URL not configured. |
| API_URL | — | | Legacy fallback for PUBLIC_API_URL, honored only by enrollment, installer, and MCP-invite code paths. Auto-update, dev-push, and a few other routes read PUBLIC_API_URL only — prefer setting PUBLIC_API_URL. |
| BREEZE_DOMAIN | — | Yes (prod) | Domain for Caddy TLS provisioning |
| ACME_EMAIL | — | Yes (prod) | Email for Let’s Encrypt certificate notifications |
| CORS_ALLOWED_ORIGINS | — | | Comma-separated allowed CORS origins |
| IS_HOSTED | — | Yes (prod) | true for hosted SaaS edition, false for self-hosted. Must be set explicitly — the API refuses to boot otherwise. Controls signup gating, billing, and email-verification policy. |
| TRUST_PROXY_HEADERS | — | Yes (prod) | true when behind a reverse proxy (Caddy, Cloudflare). Must be set explicitly in production. |
| TRUSTED_PROXY_CIDRS | — | When TRUST_PROXY_HEADERS=true | Comma-separated CIDRs of trusted reverse proxies (e.g., 10.0.0.0/8,172.16.0.0/12). Required when proxy headers are trusted. |
| IP_ALLOWLIST_ENFORCEMENT_MODE | enforce | | Partner dashboard IP allowlist mode. Use off only as a break-glass switch if an allowlist locks everyone out. The allowlist only enforces when a partner has entries configured and proxy trust is working through TRUST_PROXY_HEADERS plus TRUSTED_PROXY_CIDRS. |
| DASHBOARD_URL | — | | URL for links in emails |
| PUBLIC_APP_URL | — | | Public-facing app URL |
| Variable | Default | Description |
|---|---|---|
| EMAIL_PROVIDER | auto | Provider: auto, resend, smtp, or mailgun |
| RESEND_API_KEY | — | Resend API key |
| EMAIL_FROM | noreply@breeze.local | Sender address |
| SMTP_HOST | — | SMTP server hostname |
| SMTP_PORT | 587 | SMTP port |
| SMTP_USER | — | SMTP username |
| SMTP_PASS | — | SMTP password |
| SMTP_FROM | noreply@breeze.local | SMTP-specific sender address |
| SMTP_SECURE | false | Use TLS for SMTP |
| MAILGUN_API_KEY | — | Mailgun API key |
| MAILGUN_DOMAIN | — | Mailgun sending domain |
| MAILGUN_BASE_URL | https://api.mailgun.net | Mailgun API base URL |
| MAILGUN_FROM | noreply@breeze.local | Mailgun-specific sender address |
SMS (Twilio)
Section titled “SMS (Twilio)”| Variable | Default | Description |
|---|---|---|
| TWILIO_ACCOUNT_SID | — | Twilio Account SID |
| TWILIO_AUTH_TOKEN | — | Twilio Auth Token |
| TWILIO_VERIFY_SERVICE_SID | — | Twilio Verify service SID (for SMS MFA) |
| TWILIO_MESSAGING_SERVICE_SID | — | Twilio Messaging Service SID (for alert SMS) |
| TWILIO_PHONE_NUMBER | — | Twilio phone number for outbound SMS |
Binary Distribution
Section titled “Binary Distribution”| Variable | Default | Required | Description |
|---|---|---|---|
| BINARY_SOURCE | local | | Download source: local (serve from disk, optional S3) or github (redirect to GitHub Releases) |
| AGENT_BINARY_DIR | ./agent/bin | | Local directory containing agent binaries |
| VIEWER_BINARY_DIR | ./viewer/bin | | Local directory containing viewer installers |
| HELPER_BINARY_DIR | /data/binaries/helper | | Local directory containing helper binaries |
| BINARY_VERSION_FILE | — | | Path to VERSION file for local mode DB registration (set automatically in Docker Compose) |
| BINARY_VERSION | — | | Release tag for GitHub redirect mode (falls back to BREEZE_VERSION, then latest) |
| RELEASE_ARTIFACT_MANIFEST_PUBLIC_KEYS | yzx8ftmcls6uBetFC5SYnZhBo+cbur3IX50TbBthTso= (official releases) | Yes (prod) | Comma-separated raw base64 Ed25519 public keys that sign release manifests. Use the published default for official Breeze releases (it is a public key, safe to commit); only change it if you sign your own binaries. The API refuses to start in production without it. BREEZE_RELEASE_ARTIFACT_MANIFEST_PUBLIC_KEYS is accepted as an alias. |
See Binary Distribution for details on local vs GitHub mode and S3 offloading.
Object Storage
Section titled “Object Storage”| Variable | Default | Description |
|---|---|---|
| S3_ENDPOINT | — | S3-compatible endpoint (MinIO, R2, AWS). Uses path-style addressing. |
| S3_ACCESS_KEY | — | Access key |
| S3_SECRET_KEY | — | Secret key |
| S3_BUCKET | — | Bucket name |
| S3_REGION | us-east-1 | Bucket region |
| S3_PRESIGN_TTL | 900 | Presigned URL expiration in seconds (15 min) |
| MINIO_API_PORT | 9000 | MinIO API port (Docker only) |
| MINIO_CONSOLE_PORT | 9001 | MinIO web console port (Docker only) |
WebRTC / TURN
Section titled “WebRTC / TURN”The Breeze stack includes a coturn TURN server for WebRTC relay. Without TURN, remote desktop connections fail when either peer is behind symmetric NAT or a restrictive firewall.
| Variable | Default | Required | Description |
|---|---|---|---|
| TURN_HOST | — | Yes (prod) | Public IP or hostname of the TURN server. Must be reachable by agents and viewers. |
| TURN_PORT | 3478 | | TURN listening port (UDP and TCP) |
| TURN_SECRET | — | Yes (prod) | Shared secret for TURN credential generation. Generate: openssl rand -hex 32 |
| TURN_REALM | breeze.local | | TURN authentication realm |
Monitoring
Section titled “Monitoring”| Variable | Default | Description |
|---|---|---|
| METRICS_SCRAPE_TOKEN | — | Bearer token for /metrics/scrape |
| METRICS_INCLUDE_ORG_ID | false | Include org IDs in Prometheus labels |
| METRICS_SCRAPE_IP_ALLOWLIST | — | Restrict metrics scraping by IP |
| LOG_LEVEL | info | Log verbosity: debug, info, warn, error |
| LOG_JSON | true | Structured JSON logging |
| GRAFANA_ADMIN_USER | admin | Grafana admin username |
| GRAFANA_ADMIN_PASSWORD | — | Grafana admin password |
| GRAFANA_PORT | 3000 | Grafana web UI port (monitoring stack) |
| GRAFANA_ROOT_URL | http://localhost:3000 | Grafana public root URL (monitoring stack) |
| PROMETHEUS_PORT | 9090 | Prometheus web UI port (monitoring stack) |
| ALERTMANAGER_PORT | 9093 | Alertmanager web UI port (monitoring stack) |
| LOKI_PORT | 3100 | Loki log aggregation API port (monitoring stack) |
Sentry
Section titled “Sentry”Both API and web Sentry integrations are off by default. Leave the DSN variables blank to disable. See Error Tracking & Privacy for what gets collected and how scrubbing works.
| Variable | Default | Description |
|---|---|---|
| SENTRY_DSN | — | API Sentry DSN. Leave blank to disable server-side error tracking. |
| SENTRY_ENVIRONMENT | production | Sentry environment tag |
| SENTRY_RELEASE | — | Sentry release tag (e.g. git SHA) |
| SENTRY_TRACES_SAMPLE_RATE | 0.1 | Sentry performance trace sample rate (0.0-1.0) |
| PUBLIC_SENTRY_DSN_WEB | — | Web Sentry DSN. Leave blank to disable browser error tracking and on-error session replay. Inlined into the web bundle at build time. |
| SENTRY_AUTH_TOKEN | — | Sentry auth token used during the web build to upload source maps. If unset, source map upload is skipped and the build still succeeds. |
Rate Limiting
Section titled “Rate Limiting”Two rate-limit tiers protect the API. The generic per-user limit covers logged-in dashboard usage; the per-org agent limit caps how much traffic a single tenant’s fleet can generate, even with thousands of agents.
| Variable | Default | Description |
|---|---|---|
| RATE_LIMIT_WINDOW_MS | 60000 | Sliding window duration (ms) |
| RATE_LIMIT_MAX_REQUESTS | 100 | Max requests per window |
| AGENT_ORG_RATE_LIMIT_PER_MIN | 600 | Per-organization sliding-window rate limit on agent-authenticated endpoints. Returns 429 with Retry-After: 60 when exceeded. Sized for ~5 active agents per org; raise for MSPs with very large fleets. |
Database
Section titled “Database”| Variable | Default | Description |
|---|---|---|
| DB_POOL_MAX | 30 | Maximum postgres-js connection pool size. Tune up if you see cascading 504s during heartbeat storms; confirm Postgres max_connections has headroom (default 100 is fine for a single API replica). |
File Transfer & Remote Sessions
Section titled “File Transfer & Remote Sessions”| Variable | Default | Description |
|---|---|---|
| TRANSFER_STORAGE_PATH | ./data/transfers | File transfer storage directory |
| MAX_TRANSFER_SIZE_MB | 100 | Max file transfer size |
| MAX_ACTIVE_TRANSFERS_PER_ORG | 20 | Concurrent transfer limit per org |
| MAX_ACTIVE_TRANSFERS_PER_USER | 10 | Concurrent transfer limit per user |
| MAX_ACTIVE_REMOTE_SESSIONS_PER_ORG | 10 | Concurrent remote sessions per org |
| MAX_ACTIVE_REMOTE_SESSIONS_PER_USER | 5 | Concurrent remote sessions per user |
| PATCH_REPORT_STORAGE_PATH | ./data/patch-reports | Patch compliance report storage |
Feature Flags
Section titled “Feature Flags”| Variable | Default | Description |
|---|---|---|
| ENABLE_REGISTRATION | true | Allow new user registration |
| ENABLE_2FA | true | Enable two-factor authentication |
| ENABLE_API_DOCS | false | Enable Swagger API documentation |
| ENABLE_API_DOCS_UI | false | Enable interactive Swagger UI (requires ENABLE_API_DOCS=true) |
| USE_AGENT_SDK | — | Use Claude Agent SDK for AI chat |
| PORTAL_STATE_BACKEND | memory | Portal state backend: memory or redis (auto redis in production) |
MCP Server
Section titled “MCP Server”| Variable | Default | Description |
|---|---|---|
| MCP_SSE_RATE_LIMIT_PER_MINUTE | 30 | SSE connection rate limit per API key |
| MCP_MESSAGE_RATE_LIMIT_PER_MINUTE | 120 | Message rate limit per API key |
| MCP_MAX_SSE_SESSIONS_PER_KEY | 5 | Max concurrent SSE sessions per API key |
| MCP_REQUIRE_EXECUTE_ADMIN | false | Require ai:execute_admin scope for Tier 3 tools |
| MCP_EXECUTE_TOOL_ALLOWLIST | — | Comma-separated allowed Tier 3 tools (empty = deny all) |
Cloudflare mTLS
Section titled “Cloudflare mTLS”| Variable | Default | Description |
|---|---|---|
| CLOUDFLARE_API_TOKEN | — | Cloudflare API token with Client Certificates permission |
| CLOUDFLARE_ZONE_ID | — | Cloudflare zone ID for your domain |
Cloudflare Access JWT trust
Section titled “Cloudflare Access JWT trust”| Variable | Default | Description |
|---|---|---|
| CF_ACCESS_TRUST_ENABLED | false | Set true to short-circuit POST /auth/login when a valid Cf-Access-Jwt-Assertion header is present. Off by default. See Cloudflare Access trust. |
| CF_ACCESS_TEAM_DOMAIN | — | Required when trust is enabled. Bare hostname of your Cloudflare team domain, e.g. example.cloudflareaccess.com. No scheme. |
| CF_ACCESS_AUD | — | Required when trust is enabled. AUD tag for the Cloudflare Access application protecting Breeze. |
| CF_ACCESS_TRUSTS_MFA | false | Treat a valid CF Access JWT as MFA-satisfied for the minted Breeze session. Only enable if your CF Access policy actually requires step-up MFA. |
Cloud-to-Cloud Backup (M365)
Section titled “Cloud-to-Cloud Backup (M365)”| Variable | Default | Description |
|---|---|---|
| C2C_M365_CLIENT_ID | — | Azure AD app (client) ID for multi-tenant M365 backup. When set with the secret below, enables one-click admin consent flow for connecting Microsoft 365 backups. |
| C2C_M365_CLIENT_SECRET | — | Azure AD app client secret for multi-tenant M365 backup |
Docker Deployment
Section titled “Docker Deployment”| Variable | Default | Description |
|---|---|---|
| BREEZE_VERSION | latest | Breeze release tag for Docker images (e.g. 0.50.0). Also used by GitHub redirect mode for agent binary downloads. |
| DOCKER_PLATFORM | linux/amd64 | Container platform. GHCR images are amd64 only. On Apple Silicon, use docker-compose.override.yml.local-build to build native arm64 images instead. |
| REDIS_MAXMEMORY | 256mb | Maximum memory Redis is allowed to use. Redis runs with noeviction policy so BullMQ jobs are never silently dropped. |
MSI Installer Signing
Section titled “MSI Installer Signing”| Variable | Default | Description |
|---|---|---|
| MSI_SIGNING_URL | — | URL of the remote Windows signing service. When set, pre-configured MSI installer downloads are code-signed before delivery. |
| MSI_SIGNING_CF_ACCESS_ID | — | Cloudflare Access service token Client ID for authenticating to the signing service |
| MSI_SIGNING_CF_ACCESS_SECRET | — | Cloudflare Access service token Client Secret for authenticating to the signing service |
Billing
Section titled “Billing”| Variable | Default | Description |
|---|---|---|
| BILLING_SERVICE_URL | — | URL of the billing service for AI credit checks and deductions. When unset, AI usage is unlimited. |
| BILLING_SERVICE_API_KEY | — | API key for authenticating to the billing service |
| Variable | Default | Description |
|---|---|---|
| ANTHROPIC_API_KEY | — | Anthropic API key for AI assistant (BYOK) |