Skip to content

Configuration

All services read one shared .env at the repository root. Config classes read it through getenv and fail fast on a missing key, so a misconfigured service refuses to boot rather than misbehaving later.

Start from the template:

bash
cp .env.example .env

Core

VariableNotes
DOMAINBase domain for every subdomain router. localhost in development.
APP_ENVdevelopment or production
APP_LOG_LEVELMonolog level, e.g. debug, error
APP_MODEselfhosted or hosted
ACCESS_CONTROL_ALLOW_ORIGINCORS origin. In production set this to the admin origin, not *.
ROOT_ADMIN_EMAILSComma-separated bootstrap site admins. Promoted to a persisted flag on login.
REGISTRATION_MODEWho may create an account: open, invite or closed. See below.

Registration

REGISTRATION_MODE decides who may create an account on the instance. It gates account creation only — signing in, accepting an organization invitation and linking an SSO identity to an account that already exists are unaffected.

ValueWho gets in
open (default)Anyone. The signup form is on the sign-in screen.
inviteOnly an address a site admin has invited from the admin panel. The invite is consumed on use, so it works exactly once.
closedNobody, outstanding invites included. Issuing new invites is refused too, since they could not be redeemed.

The switch applies to every way an account is created — POST /auth/register and GitHub SSO alike. An SSO sign-in for an unknown GitHub account is refused before the "create an account" step is offered, and in invite mode the invite is matched against the provider's verified email, since OAuth returns an address rather than an invite token.

The dashboard reads GET /auth/registration and hides what it cannot offer, so a closed instance shows a sign-in form with no way to register. An unrecognised value falls back to open rather than locking an instance out of its own signup.

Secrets

Generate each of these; never ship the defaults.

VariableGenerate with
APP_ENCRYPTION_KEYopenssl rand -hex 32
JWT_SECRETopenssl rand -hex 32
INTERNAL_API_SECRETopenssl rand -hex 32

APP_ENCRYPTION_KEY is not rotatable in place

It encrypts stored channel credentials and is the root of the unsubscribe link signing key. Changing it invalidates every opt-out link already sitting in delivered mail, and makes stored channel credentials unreadable.

Datastores

VariableNotes
DB_NAME, DB_USER, DB_PASSWORDPostgreSQL
RABBITMQ_USER, RABBITMQ_PASSWORDBroker
INTERNAL_API_URLPublic API's address on the internal network

Mail

SMTP_* configures the outbound relay. In development it points at MailPit, which captures everything at mailpit.<DOMAIN> and delivers nothing.

Optional

VariableNotes
GITHUB_OAUTH_CLIENT_ID / _SECRETEnables "Continue with GitHub". Leave empty to hide the buttons.
KEY_EXPIRY_WARN_DAYSHow early to warn about expiring API keys
MESSAGE_RETENTION_DAYSMessage retention window in selfhosted mode

Released under the Apache 2.0 License.