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.
| Stack | Template | Compose file |
|---|---|---|
| Caddy | .env.caddy | docker-compose.caddy.yml |
| Direct HTTP | .env.compose | docker-compose.yml |
| Traefik | .env.traefik | docker-compose.traefik.yml |
Required secrets
| Variable | Purpose | Guidance |
|---|---|---|
JWT_SECRET | Signs session JWTs | Generate with openssl rand -hex 32. Changing it signs users out. |
DB_PASSWORD | PostgreSQL account password | Generate 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
| Variable | Default | Purpose |
|---|---|---|
DB_DATABASE | bearicorn | PostgreSQL database name |
DB_USERNAME | bearicorn | PostgreSQL role used by the app |
DB_PASSWORD | bearicorn in the template | PostgreSQL role password; replace it |
DB_SCHEMA | public | PostgreSQL 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
| Variable | Default | Purpose |
|---|---|---|
TZ | UTC | Container timezone |
EXPO_NOTIFICATIONS | false | Send message, device-unlink, and incoming-call notifications via Expo |
EXPO_SEND_NAME | NONE | Put 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.
| Variable | Default | Purpose |
|---|---|---|
ICE_STUN_URLS | stun:stun.l.google.com:19302 | Comma-separated STUN URLs; the public Google STUN is used when unset |
TURN_URLS | empty (TURN disabled) | Comma-separated turn:/turns: URLs of an operator-run relay (e.g. coturn) |
TURN_USERNAME | empty | Static username for the TURN server |
TURN_PASSWORD | empty | Static password for the TURN server |
CALL_RING_TIMEOUT_SECONDS | 30 | Server-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
| Variable | Default | Purpose |
|---|---|---|
APP_PORT | 8080 | Host port published to the application container |
Keep this port private when an existing HTTPS proxy fronts the Direct stack.
Caddy
| Variable | Default | Purpose |
|---|---|---|
CADDY_SITE_ADDRESS | localhost | Exact hostname Caddy serves |
CADDY_HTTP_PORT | 8080 | Internal Caddy listener; do not change independently |
CADDY_HTTPS_PORT | 8443 | Internal 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
| Variable | Default | Purpose |
|---|---|---|
TRAEFIK_HOST | localhost | Exact hostname matched by the routers |
TRAEFIK_ACME_EMAIL | [email protected] | Certificate-registration contact |
TRAEFIK_DASHBOARD_PORT | 8081 | Host 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:
docker compose --env-file .env -f docker-compose.caddy.yml configReplace the file name for Direct HTTP or Traefik.