Skip to content

Environment variables ​

Each Compose stack has a matching template in deploy/compose. Copy one template to .env, then run Compose from that directory with --env-file .env.

StackTemplateCompose file
Caddy.env.caddydocker-compose.caddy.yml
Direct HTTP.env.composedocker-compose.yml
Traefik.env.traefikdocker-compose.traefik.yml

Required secrets ​

VariablePurposeGuidance
JWT_SECRETSigns session JWTsGenerate with openssl rand -hex 32. Changing it signs users out.
DB_PASSWORDPostgreSQL account passwordGenerate with openssl rand -hex 16. Keep it in sync with the existing database volume.

DANGER

The templates contain development placeholders. Replace both secrets before the first public start and do not commit .env.

Database ​

VariableDefaultPurpose
DB_DATABASEbearicornPostgreSQL database name
DB_USERNAMEbearicornPostgreSQL role used by the app
DB_PASSWORDbearicorn in the templatePostgreSQL role password; replace it
DB_SCHEMApublicPostgreSQL schema

Changing database identity values after the postgres_data volume is initialized does not rewrite the existing role or database. Treat those changes as a database migration, not a routine configuration edit.

Common application settings ​

VariableDefaultPurpose
TZUTCContainer timezone
EXPO_NOTIFICATIONSfalseSend message, device-unlink, and incoming-call notifications via Expo
EXPO_SEND_NAMENONEPut FIRST, FULL, or no sender name in message notification text

Push is disabled unless EXPO_NOTIFICATIONS=true. The mobile app's FCM/APNs credentials are configured for its Expo/EAS project; the Hub only stores Expo push tokens and calls Expo's API.

Calls (WebRTC) ​

Voice/video calls run peer-to-peer between clients; the hub only relays end-to-end-encrypted signaling. These variables configure the ICE servers the hub hands to clients.

VariableDefaultPurpose
ICE_STUN_URLSstun:stun.l.google.com:19302Comma-separated STUN URLs; the public Google STUN is used when unset
TURN_URLSempty (TURN disabled)Comma-separated turn:/turns: URLs of an operator-run relay (e.g. coturn)
TURN_USERNAMEemptyStatic username for the TURN server
TURN_PASSWORDemptyStatic password for the TURN server
CALL_RING_TIMEOUT_SECONDS30Server-authoritative ringing timeout; integer from 5 to 300 seconds

Without a TURN relay, peers behind strict NATs or corporate firewalls may fail to connect. TURN relays only encrypted media (DTLS-SRTP); it cannot read call content.

Direct HTTP ​

VariableDefaultPurpose
APP_PORT8080Host port published to the application container

Keep this port private when an existing HTTPS proxy fronts the Direct stack.

Caddy ​

VariableDefaultPurpose
CADDY_SITE_ADDRESSlocalhostExact hostname Caddy serves
CADDY_HTTP_PORT8080Internal Caddy listener; do not change independently
CADDY_HTTPS_PORT8443Internal Caddy listener; do not change independently

The Compose file maps public ports 80 and 443 to the two internal listeners. Changing only an internal value breaks that mapping.

APP_PORT appears in .env.caddy but is not consumed by docker-compose.caddy.yml.

Traefik ​

VariableDefaultPurpose
TRAEFIK_HOSTlocalhostExact hostname matched by the routers
TRAEFIK_ACME_EMAIL[email protected]Certificate-registration contact
TRAEFIK_DASHBOARD_PORT8081Host binding for the insecure dashboard API

For this repository's Traefik stack, set TRAEFIK_DASHBOARD_PORT=127.0.0.1:8081 so the dashboard is reachable only through a local or SSH-tunneled connection.

Inspect the resolved configuration ​

Before starting, render the Compose configuration and check for unexpected placeholders:

bash
docker compose --env-file .env -f docker-compose.caddy.yml config

Replace the file name for Direct HTTP or Traefik.

Self-hosted chat and tasks with end-to-end encrypted content.