Reverse proxy and HTTPS
Anyone outside your LAN should reach the server over HTTPS. It protects passwords and the chronicle in transit, and it is what browsers require before they will grant the microphone, Bluetooth for Pixels dice, or an installable web app. Only the web port goes behind the proxy; the voice media port, if you use the media server, is opened directly.
Caddy
play.example.com {
reverse_proxy 127.0.0.1:3005
}Caddy fetches and renews the certificate itself and forwards the headers the server needs.
nginx
server {
listen 443 ssl http2;
server_name play.example.com;
ssl_certificate /etc/letsencrypt/live/play.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/play.example.com/privkey.pem;
client_max_body_size 32m;
location / {
proxy_pass http://127.0.0.1:3005;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 600s;
proxy_buffering off;
}
}The long read timeout and buffering off matter: narration streams, the event stream stays open, and a Dungeon Master turn on a local model can take minutes. The body size covers uploads of maps and handouts.
Tell the server its address
- Set Public URL in Admin, Server settings, Server, or
APP_PUBLIC_URL=https://play.example.com. Share links, QR codes, the invite preview and the Discord redirect are built from it. A proxy that forwardsX-Forwarded-HostandX-Forwarded-Protolets the server work it out, but setting it removes the guesswork. COOKIE_SECURE=1behind HTTPS;0if the server is only ever reached on plain http on a LAN.- Login throttling keys on the address the proxy appended, so
X-Forwarded-Forshould be set by your proxy and not by clients.
Cloudflare and tunnels
Cloudflare's proxy or a Cloudflare Tunnel works for the web port, with two cautions. Voice: the built-in media server's UDP port cannot go through Cloudflare, so use the mesh transport, or a voice domain on a DNS-only record. Pictures: Cloudflare drops the Vary: Origin header the server sets on media, which once poisoned the apps' cache; the apps from 0.12.6 work around it, so keep them current. Uploads, generated pictures and narration audio need a sign-in and are cached privately, so a cache in front of the server never keeps a copy for the next caller.
The apps' cross-origin calls
The desktop and Android apps draw the server's screens themselves and call its data routes from their own origin, with a bearer token. The server allows those origins by default; a self-built app or an unusual setup can add more with ODM_APP_ORIGINS.
Certificates for a LAN
For a table that is entirely inside one house, the apps do not need HTTPS: they are a secure context of their own and can use voice on a plain-http address. Browsers on the LAN do need it for the microphone; a local certificate authority (mkcert) or a real certificate for a private name are the usual answers.