Skip to content

Environment Variables ​

The complete reference for .env (see .env.example in the repo, which is the source of truth — this page explains it in prose). scripts/setup.sh automatically generates everything marked "generated secret"; everything else has a sensible default or is optional.

Database and queue ​

VariableRequiredDescription
POSTGRES_USERYesThe migration user (app_migrator by default). Only migrate connects with this role.
POSTGRES_PASSWORDYes (generated secret)The migration user's password.
POSTGRES_DBYesThe database name (seredina by default).
POSTGRES_PORTNoThe port exposed by the Postgres container (5432 by default).
REDIS_PORTNoThe port exposed by Redis (6379 by default).
APP_TENANT_DB_PASSWORDYes (generated secret)Password for the app_tenant role, created by packages/db/prisma/rls/policies.sql at migration time. The only role api and worker ever connect as — they never use the migration role in production.

Security ​

VariableRequiredDescription
JWT_SECRETYes (generated secret)Signs session tokens.
JWT_EXPIRES_INNoHow long a console login lasts before the user has to sign in again (8h by default; accepts values like 30m, 12h, 1d). Deactivating a user or changing their role takes effect immediately regardless.
ENCRYPTION_KEYYes (generated secret)Encrypts email channel IMAP/SMTP passwords at rest (AES-256-GCM), plus other per-tenant secrets. Must be exactly 64 hex characters (openssl rand -hex 32).

Losing this ENCRYPTION_KEY is irreversible

If you lose it or rotate it without migrating existing data, every already-stored email channel password becomes undecryptable — back it up with the same seriousness as a database password.

Deployment mode ​

VariableRequiredDescription
SEREDINA_MODEYesself_hosted or cloud. See Cloud mode for what this actually changes.

AI copilot (optional) ​

Unconfigured, the AI copilot responds with a clear 503 instead of the API refusing to boot — it's an optional feature, not an install requirement.

VariableRequiredDescription
AI_PROVIDERNoanthropic, openai, or ollama. Left unset, defaults to anthropic if ANTHROPIC_API_KEY is set (backward compatibility).
ANTHROPIC_API_KEY / ANTHROPIC_MODELNoA key from console.anthropic.com. ANTHROPIC_MODEL overrides the default model.
OPENAI_API_KEY / OPENAI_MODELNoA key from platform.openai.com.
OLLAMA_BASE_URL / OLLAMA_MODELNoNo per-call cost — runs against a local Ollama install. OLLAMA_BASE_URL defaults to http://localhost:11434/v1.

On top of this deployment-level configuration, any tenant can bring their own key (BYOK) from Settings → AI in the console — if they have one, it's used exclusively, never falling back to the deployment's global config.

Networking and ports ​

VariableRequiredDescription
API_PORTNoThe API's port (4000 by default).
WEB_PORTNoThe web console's port (8080 by default).
WEB_ORIGINYesMust match how the browser reaches the console (never the in-compose-network hostname). api also builds every public link from it: CSAT survey links, customer portal sign-in links, and the address Microsoft 365 / Gmail and your SSO provider send the browser back to (<WEB_ORIGIN>/api/email-channels/oauth/callback and <WEB_ORIGIN>/api/auth/sso/callback, unless API_PUBLIC_URL is set). The worker gets the same value, for the customer portal link in emails. Left unset, those features don't work.
VITE_API_URLNoLeave empty: the console reaches the API at /api on its own address. Only set it to point the console at an API on a different origin (baked in at build time).
API_PUBLIC_URLOnly if using TelegramA real, internet-reachable HTTPS base URL for your API — Telegram calls it directly to deliver messages, so it can never be localhost or an internal compose hostname. Also the address the Devices page puts in agent enrollment commands, and, when set, the base of the OAuth and SSO redirect URIs (<API_PUBLIC_URL>/email-channels/oauth/callback, <API_PUBLIC_URL>/auth/sso/callback). configure-address.sh sets it to https://<address>/api.
SEREDINA_SITEWith the proxy profileThe address the HTTPS proxy serves: a domain or IP (http://… when TLS_MODE=off). Set by scripts/configure-address.sh.
TLS_MODEWith the proxy profileacme (Let's Encrypt), custom (certs/cert.pem + certs/key.pem), internal (generated CA), or off.
ACME_EMAILWith TLS_MODE=acmeGets certificate expiry warnings if renewal ever fails.
HTTP_PORT / HTTPS_PORTNoThe proxy's ports (80 / 443).
TLS_CA_FILENoA CA certificate agents pin, for a certificate that isn't publicly trusted. Set by the script for internal and custom; the Devices page puts it in the enrollment command. A file that contains a private key is refused.
AGENT_DOWNLOAD_URLNoAn internal web folder holding a copy of an agent release's files, for devices that can't reach GitHub. The Devices page's install commands then download from there.
WEB_BIND / API_BINDNoWhich interface the web and API ports listen on (0.0.0.0). The script sets 127.0.0.1 once the proxy is in front, so the network only gets in over HTTPS.
DB_BINDNoPostgres and Redis listen on 127.0.0.1 only. Redis has no password: don't expose it.
TRUST_PROXYNoWhich hops may set X-Forwarded-For, so per-IP rate limits see the real client behind the proxies. Compose sets loopback,uniquelocal.
COMPOSE_PROFILESNoproxy starts the HTTPS proxy; add mcp for the MCP server.

Other optional variables ​

VariableRequiredDescription
UPDATER_TOKENNoTurns on installing updates from the console, and is what the API presents to the updater service. Set by scripts/enable-updater.sh, with SEREDINA_HOST_DIR (the installation folder) and the updater profile. See Updates.
SEREDINA_COMPOSE_FILESNoThe compose files the installation runs with, :-separated (infra/docker-compose.yml by default). The updater rebuilds with the same ones.
SENTRY_DSNNoError tracking (api/worker). Unset, it no-ops — points at Sentry.io or a self-hosted GlitchTip instance (protocol-compatible with the Sentry SDK).
VITE_SENTRY_DSNNoThe same, for the web console. Baked in when the web image is built.
EMAIL_POLL_INTERVAL_MSNoHow often the worker checks each active email channel's IMAP inbox (30000 ms by default).
MCP_HTTP_PORTNoOnly used by the mcp-server-http service, profile-gated (docker compose --profile mcp up). See MCP Server.

Startup validation ​

api and worker validate every required variable at startup and report everything missing or malformed in a single message — they don't stop at the first missing variable. If a container won't start, docker compose logs api (or worker) is always the first place to look.

Released under AGPL-3.0-only.