Environment variables
All configuration comes from the environment. See .env.example in the repo root. Secrets must come from a secret store in production, never a committed file.
Postgres
| Variable | Notes |
|---|---|
POSTGRES_USER | Default zeallm |
POSTGRES_PASSWORD | Required — compose fails if unset |
DATABASE_URL | Full URL; local tooling uses host port 55432 |
Portal
| Variable | Notes |
|---|---|
AUTH_SECRET | NextAuth secret (32 random bytes). Rotating invalidates sessions |
AUTH_URL | Portal public URL |
ZEALLM_ENCRYPTION_KEY | AES-256-GCM master key (64 hex / base64) or akv:<secret-name> |
ZEALLM_ENCRYPTION_KEY_FALLBACK | Previous key during rotation |
ZEALLM_ADMIN_EMAILS | Comma-separated bootstrap admins |
ZEALLM_ALLOWED_DOMAIN | Email domain restriction |
AUTH_DEV_BYPASS | true = password-less sign-in. Local/dev only. Ignored when NODE_ENV=production. Keep false in production .env and rebuild portal after auth changes |
AZURE_AD_CLIENT_ID / _SECRET / _TENANT_ID | Entra ID SSO (required in production) |
NEXT_PUBLIC_DOCS_URL | Documentation site URL. Default http://localhost:3002 |
ZEAGATE_PUBLIC_URL | Public gateway URL shown to clients (portal only) |
ZEAGATE_INTERNAL_URL | Gateway URL the portal calls itself (key "Send test request"), e.g. http://zeagate:8080. Falls back to ZEAGATE_PUBLIC_URL |
ZEALLM_TIMEZONE | Same value as the gateway's; the portal uses it for budget forecast dates (default: server time zone) |
OPENAI_API_KEY | Seeds an OpenAI credential on first portal boot |
CRON_SECRET | Bearer secret (32+ random characters) for scheduled jobs on /api/cron/*, e.g. the weekly digest. Unset = jobs disabled (503) |
APPROVAL_LINKS_REQUIRE_SIGNIN | true = Approve/Reject links in approval emails also require signing in. Default false: email links are bound to the recipient and work without a session. Slack/Teams links always require sign-in |
Gateway
| Variable | Notes |
|---|---|
DATABASE_URL | Required |
ZEALLM_ENCRYPTION_KEY | Required |
REDIS_URL | Shared rate limits + cache invalidation |
ZEALLM_TIMEZONE | Budget reset timezone (default UTC) |
ZEALLM_BUDGET_RESET_TIME | HH:MM (default 00:00) |
AZURE_KEY_VAULT_URL | Resolves akv: refs |
ZEAGATE_PORT | Listen port (default 8080) |
ZEAGATE_CACHE_TTL_SECONDS | In-memory cache TTL (default 15) |
ZEALLM_PORTAL_URL | Portal URL for gateway internals |
AI Subscriptions
| Variable | Notes |
|---|---|
SUBSCRIPTION_COMPANY_ONLY | Default on: AI Subscriptions tracks only company-paid accounts. Set false to let account creators manage their own accounts and to allow device collection |
SUBSCRIPTION_DEVICE_COLLECTION_ENABLED | true (with SUBSCRIPTION_COMPANY_ONLY=false) shows Enroll my collector. Default off |
Docs site (build arguments)
The docs image reads these at build time (docker build --build-arg … or build.args in Compose). Without them the navbar links point at the local stack.
| Variable | Notes |
|---|---|
DOCS_SITE_URL | Public URL of this site, used for canonical links and the sitemap. Default http://localhost:3002 |
DOCS_PORTAL_URL | Target of the navbar Portal link. Default http://localhost:3000 |
DOCS_GATEWAY_URL | Gateway base URL; the navbar Gateway link opens <url>/health. Default http://localhost:8080 |
Email
| Variable | Notes |
|---|---|
SMTP_HOST | Optional; without it invites still create accounts |
SMTP_PORT | Default 587 |
SMTP_USER / SMTP_PASS / SMTP_FROM | SMTP auth and from-address |
Do not reuse developer .env values in production. Generate fresh secrets and rotate anything that was ever shared.