Production
Deploy behind real domains with automatic TLS.
The production layout uses three hostnames on one VM:
nodus.talibdar.tech -> web:3000
relay.nodus.talibdar.tech -> relay:8080
doc.nodus.talibdar.tech -> docs:3001Storage Nodes and the mobile app connect to the Relay origin. The browser
loads the web app from the web origin, calls its /api/* BFF there, and
opens the Relay WebSocket at NEXT_PUBLIC_RELAY_URL.
1. Point DNS at the host
Add A/AAAA records for all three hostnames. Keep them DNS-only (no proxy) so Caddy can complete Let's Encrypt HTTP-01 challenges.
2. Configure deploy/.env
WEB_HOST=nodus.example.com
RELAY_HOST=relay.nodus.example.com
DOCS_HOST=doc.nodus.example.com
PUBLIC_RELAY_URL=https://relay.nodus.example.com
NEXT_PUBLIC_RELAY_URL=https://relay.nodus.example.com
ALLOWED_ORIGINS=https://nodus.example.com
SESSION_COOKIE_SECURE=true
SESSION_COOKIE_DOMAIN=.nodus.example.com
REDIS_PASSWORD=<strong-secret>REDIS_PASSWORD is required — Compose refuses to start without it rather than
falling back to a default. It must be URL-safe (no @, :, /, #, or
whitespace) because Compose interpolates it into REDIS_URL without encoding.
NEXT_PUBLIC_RELAY_URL is inlined into the browser bundle at build time. If it
changes, rebuild the web image:
docker compose -f deploy/docker-compose.yml --env-file deploy/.env build web3. Bring it up
docker compose -f deploy/docker-compose.yml --env-file deploy/.env up -d --buildCaddy obtains and renews one certificate per hostname automatically.
Origin and cookie matching
ALLOWED_ORIGINSmust exactly match the browser origin (https://nodus.example.com), or the Relay rejects the WebSocket.SESSION_COOKIE_DOMAINmust be the parent domain (.nodus.example.com) so the session cookie is also sent torelay.nodus.example.com.SESSION_COOKIE_SECUREmust betrueover HTTPS.
The browser's WebSocket target comes from NEXT_PUBLIC_RELAY_URL. Leaving it
empty keeps the original single-origin behavior (/ws on the web host), which
is what the localhost quickstart uses.
Reverse-proxy trust
Caddy runs in front of the Relay, so TRUST_PROXY is pinned to "true" in
deploy/docker-compose.yml for correct client IPs. Do not enable it when
nothing trustworthy terminates the connection.
Web push
Browser push additionally needs NEXT_PUBLIC_VAPID_PUBLIC_KEY as a build arg,
which must match the Relay's VAPID_PUBLIC_KEY. See
Configuration.