Skip to main content
For a deployment accessible beyond a single machine, follow these steps.
The simplest production layout puts the client and the signaling server behind one domain, so there is a single certificate and a single URL to configure. See Reverse Proxy for copy-pasteable Caddy and nginx configuration. This page covers the two-subdomain layout, which is still fully supported.

Steps

1

Put both services behind a reverse proxy with HTTPS

Browsers require a secure context (HTTPS) for WebRTC and the Screen Wake Lock API. Use Nginx, Caddy, Traefik, or a managed platform like Render or Fly.Proxy each service to a hostname you control:
  • app.your-domain.com to the client on :3000
  • api.your-domain.com to the signaling server on :3001
The signaling server uses WebSockets. Make sure your proxy forwards the Upgrade and Connection headers.
2

Set NEXT_PUBLIC_SOCKET_URL and rebuild

In .env:
Then restart. No rebuild: the client reads this address at runtime.
3

Set CLIENT_URL

In .env:
This adds your client origin to the server’s CORS allow-list. Without it, browser requests from your domain will be blocked.
4

Set TRUSTED_PROXY_COUNT

Set this to the number of proxy hops in front of the signaling server so per-IP rate limiting reads real client IPs instead of proxy IPs:
One reverse proxy is 1, a CDN in front of that proxy is 2. The server’s own default is 1; Docker Compose passes 0 explicitly, which is correct only when the container ports are published directly. Setting it higher than your real hop count lets clients forge X-Forwarded-For and bypass the per-IP rate limits, so if you expose the server directly with no proxy, set 0 deliberately rather than leaving it unset.

CORS note

The server’s allow-list also includes the official floe.one origins (https://floe.one and https://www.floe.one) plus http://localhost:3000 for local development. Your CLIENT_URL is added on top of these, so browser clients on your domain and on floe.one can both reach your server. If you are running a private fork and want a strict allow-list, remove the hard-coded entries from server/server.js.