Skip to content

Environment Variables

All configuration is done through environment variables, defined in your .env.prod file. This page documents every variable.

Variable Default Required Description
POSTGRES_USER breeze PostgreSQL username
POSTGRES_PASSWORD Yes PostgreSQL password. Also used to derive the unprivileged request-pool credential (see below) unless DATABASE_URL_APP or BREEZE_APP_DB_PASSWORD is set.
POSTGRES_DB breeze Database name
POSTGRES_PORT 5432 PostgreSQL port
DATABASE_URL Auto Full connection string (constructed from above in Docker)
DATABASE_URL_APP One of these three (prod) Explicit connection string for the unprivileged request role (breeze_app). Preferred, and required for multi-host / high-availability DATABASE_URL values, which cannot be derived automatically.
BREEZE_APP_DB_PASSWORD One of these three (prod) Password for the breeze_app role, used to derive its connection string from DATABASE_URL.

In production, Breeze runs request handlers as an unprivileged, row-level-security-enforced database role (breeze_app) rather than as the database owner. The API refuses to start unless it can configure that role — set one of DATABASE_URL_APP, BREEZE_APP_DB_PASSWORD, or POSTGRES_PASSWORD. This check runs whenever NODE_ENV=production, including when AUTO_MIGRATE=false. The API also refuses to start if it detects it is running as a SUPERUSER or BYPASSRLS role — if you were previously running as the postgres superuser, switch to a NOSUPERUSER/NOBYPASSRLS role. After doing so you may notice rows that were previously visible to a tenant “disappear”; that is row-level security working correctly, not data loss. See the request-database-role runbook.

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.
Variable Default Required Description
JWT_SECRET Yes JWT signing key (min 32 chars). Generate: openssl rand -base64 64
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
ENROLLMENT_KEY_CLEANUP_ENABLED true Set to false to disable the daily sweep that purges expired enrollment keys
ENROLLMENT_KEY_PURGE_AFTER_DAYS 7 Grace period (days past expiry) before an expired enrollment key is purged
SESSION_SECRET Yes Express session signing secret
SESSION_MAX_AGE 86400000 Session max age in ms (24h)

Access-token (15m) and refresh-token (7d) lifetimes are fixed in code (apps/api/src/services/jwt.ts) — short-lived access tokens backed by refresh-token rotation — and are intentionally not configurable via deployment env vars.

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.
TRUST_CF_CONNECTING_IP false Set to true only when Breeze is fronted by Cloudflare. Cloudflare overwrites the CF-Connecting-IP header at its edge, but a non-Cloudflare reverse proxy (including the bundled Caddy) does not strip it — so trusting it without a Cloudflare front would let a client spoof the header to defeat IP allowlists and per-IP rate limits. When off, client IPs are resolved from X-Forwarded-For instead. If you are behind Cloudflare and leave this unset, client-IP attribution (rate limits, audit logs, IP allowlists) falls back to X-Forwarded-For; the API logs a startup warning in that case.
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
PUBLIC_PORTAL_URL https://${BREEZE_DOMAIN}/portal (bundled compose only) Public origin for customer-portal links in outbound email (e.g. invoice emails). Falls back to PUBLIC_APP_URL if unset. The portal is served under /portal on the main domain.
PORTAL_BASE_PATH /portal Base path the customer portal is served under. Baked into the portal image at build time — changing it requires rebuilding the portal image and keeping the Caddy /portal route in sync.
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
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

Push notifications to the iOS app go directly through Apple’s push service (APNs). All four values are optional but all-or-none — setting any one makes the other three required, so a half-configured setup fails at startup rather than silently at first send. Leave them all unset to disable push.

Variable Default Description
APNS_AUTH_KEY Contents of the Apple .p8 push auth key
APNS_KEY_ID Apple push key ID
APNS_TEAM_ID Apple developer team ID
APNS_BUNDLE_ID iOS app bundle identifier
APNS_ENVIRONMENT production production or sandbox. An empty value is treated as unset.
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.
AGENT_AUTO_PROMOTE true Controls whether a newly registered/synced agent release immediately becomes the fleet upgrade target. true (default): publishing a release promotes it to the fleet at once. false: new binaries stay downloadable but the fleet only advances when you explicitly promote a version (platform admin + MFA) — see Controlled agent fleet rollout.

See Binary Distribution for details on local vs GitHub mode and S3 offloading.

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)

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
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)

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)
SENTRY_PROFILES_SAMPLE_RATE API performance-profiling sample rate (0.0-1.0). Leave blank to disable profiling.
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.

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.
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).
Variable Default Description
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
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)
PUBLIC_ENABLE_EDR_INTEGRATIONS false Surface the EDR UI: the /security/edr fleet page, the device Security-tab EDR panel, and the Security dashboard summary cards. Set true at web image build time to enable.
PUBLIC_ENABLE_NETWORK_DEVICES_IN_LIST false Surface network-discovered assets alongside agent endpoints in the Devices list view. Set true at web image build time to enable.
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)
Variable Default Description
CLOUDFLARE_API_TOKEN Cloudflare API token with Client Certificates permission
CLOUDFLARE_ZONE_ID Cloudflare zone ID for your domain
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.
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

These enable partners to connect a Microsoft 365 shared support mailbox so customer email becomes tickets and replies are sent from that mailbox. This is a separate Azure app registration from the Cloud-to-Cloud Backup app above.

Variable Default Description
TICKET_MAILBOX_M365_CLIENT_ID Azure AD app (client) ID for the Breeze Ticketing app. When set with the secret, the Microsoft 365 mailbox card appears under Settings → Ticketing → Inbound Email.
TICKET_MAILBOX_M365_CLIENT_SECRET Client secret for the Breeze Ticketing Azure app.
PUBLIC_TICKET_MAILBOX_APP_ID Build-time, browser-exposed app id shown in the Application Access Policy PowerShell snippet on the settings card. Safe to publish – it is the app’s public client id.
Section titled “Customer Microsoft 365 Graph-read consent (optional)”

This feature is off by default and safe to leave unset — every variable below stays empty in a normal deployment. The API only reads and validates them when you turn the feature on. Concretely, the API refuses to boot only when M365_CUSTOMER_GRAPH_READ_ONBOARDING_ENABLED=true and one of the required variables is missing or malformed; while the flag is off (or absent) these variables are never parsed and any values you set are ignored.

Customer Graph-read lets a customer administrator grant read-only Microsoft Graph consent to Breeze’s dedicated multi-tenant application without handing you a reusable secret. The Entra certificate and Key Vault access live entirely inside an isolated executor sidecar — the API holds only an opaque, version-pinned reference and a private key it uses to sign short-lived internal requests to that sidecar. See Customer Graph Read for the admin-facing side.

Variable Required when enabled Format / example Meaning
M365_CUSTOMER_GRAPH_READ_ONBOARDING_ENABLED — (the switch) true / false (default false) Master switch for new consent initiation only. Existing connection status, retest, and disconnect flows are independent of it. When false, none of the variables below are validated.
M365_CUSTOMER_GRAPH_READ_ONBOARDING_ORG_IDS Yes Literal * or comma-separated canonical org UUIDs (e.g. * or 1111...,2222...) Which Breeze organizations may start consent. * = all organizations; otherwise an allowlist of canonical UUIDs. Boot fails if enabled and this is empty.
M365_CUSTOMER_GRAPH_READ_CLIENT_ID Yes Canonical UUID Entra application (client) ID of the shared multi-tenant Graph-read app.
M365_CUSTOMER_GRAPH_READ_CREDENTIAL_VERSION Yes Exactly 32 lowercase hex characters Pins which stored credential version the executor must use. Must equal the version segment of M365_CUSTOMER_GRAPH_READ_VAULT_REF.
M365_CUSTOMER_GRAPH_READ_VAULT_REF Yes akv://<vault-host>/m365-customer-graph-read/<32-lowercase-hex-version> Opaque Key Vault reference to the app’s certificate material. The trailing version segment must match M365_CUSTOMER_GRAPH_READ_CREDENTIAL_VERSION, or boot fails.
M365_GRAPH_READ_EXECUTOR_URL Yes Origin-only HTTPS, e.g. https://m365-executor.internal (no path, query, fragment, or userinfo) Private base URL of the executor sidecar. Anything other than a bare https://host[:port] origin is rejected at boot.
M365_GRAPH_READ_EXECUTOR_AUDIENCE Yes Literal m365-graph-read-executor JWT audience for the API→executor internal auth token. Must equal that exact string.
M365_GRAPH_READ_EXECUTOR_SIGNING_KID Yes Non-empty string Key ID of the API’s signing JWK. If the JWK file carries a kid, it must match this value.
M365_GRAPH_READ_EXECUTOR_SIGNING_PRIVATE_JWK_FILE Yes Absolute path to a file, e.g. /run/secrets/m365_graph_read_executor_signing_private_jwk The API’s Ed25519 (kty: OKP, crv: Ed25519) private signing JWK. The file must be a regular file whose mode denies all group/other access (0600 or stricter) and should be mounted read-only. Boot fails on a symlink, a relative path, over-broad permissions, or a JWK that isn’t a valid 32-byte Ed25519 key. Do not put the private JWK inline in an env var.
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.
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
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)
ANTHROPIC_BASE_URL Self-hosted only. Point the AI Agent at an Anthropic-compatible /v1/messages backend (vLLM 0.23+, LiteLLM). Must be an http(s) URL. Permitted only when IS_HOSTED is explicitly false (or 0/no/off); refused at boot if IS_HOSTED is true, unset, or invalid.
ANTHROPIC_AUTH_TOKEN Bearer token for the custom backend (use instead of ANTHROPIC_API_KEY when ANTHROPIC_BASE_URL is set).
ANTHROPIC_MODEL claude-sonnet-4-6 Override the default model id for a raw vLLM backend. Leave unset with a LiteLLM gateway that aliases claude-sonnet-4-6 → your model.

Self-hosted: alternative Anthropic-compatible backends

Section titled “Self-hosted: alternative Anthropic-compatible backends”

A self-hosted operator can run the AI Agent against any backend that speaks the Anthropic /v1/messages dialect — keeping full tool-use and the aiGuardrails stack — by setting:

Terminal window
IS_HOSTED=false # required — ANTHROPIC_BASE_URL is refused otherwise
ANTHROPIC_BASE_URL=http://localhost:8000 # your vLLM / LiteLLM endpoint
ANTHROPIC_AUTH_TOKEN=<backend bearer token>
# Raw vLLM only — match the served model id (skip with a LiteLLM alias):
ANTHROPIC_MODEL=<served-model-id>

The recommended route is a LiteLLM gateway that aliases claude-sonnet-4-6 to your backend model, so no ANTHROPIC_MODEL override is needed. For an OpenAI-dialect-only endpoint, use the separate MCP_LLM_* openai-compatible path instead (chat-only, no tool-use).

ANTHROPIC_BASE_URL is fail-closed: it is honored only when self-host is affirmatively declared (IS_HOSTED explicitly false/0/no/off). If IS_HOSTED is true, unset, or set to an unrecognized value, the API refuses to boot when ANTHROPIC_BASE_URL is present, and the value is also stripped from the SDK subprocess environment — so a stray or unmapped IS_HOSTED can never redirect platform AI traffic to a third-party endpoint.

Cost tracking is best-effort. The SDK can’t price a non-Anthropic model id, so it reports total_cost_usd: 0; Breeze then falls back to token-based pricing, and an unrecognized model id is priced at conservative Opus-tier DEFAULT_PRICING ($5/$25 per MTok) — i.e. likely an over-estimate for a cheap local model, not $0. For accurate accounting, add the served model id to MODEL_PRICING in aiCostTracker.ts, or use the openai-compatible path’s MCP_LLM_PRICE_* overrides.

Variable Default Description
QBO_CLIENT_ID Intuit OAuth client ID for the QuickBooks Online integration
QBO_CLIENT_SECRET Intuit OAuth client secret
QBO_REDIRECT_URI OAuth callback URL registered with Intuit (e.g. https://your-domain/accounting/quickbooks/callback)
QBO_ENVIRONMENT sandbox or production
Variable Default Description
NVD_API_KEY Optional NIST NVD API key. Raises NVD request rate limits so vulnerability feed syncs run faster. Without it, syncs use the slower public rate; the feature works either way.