Managed TURN via Cloudflare (recommended)
Cloudflare’s Realtime TURN service runs on Cloudflare’s global anycast network. It needs no public IP, no UDP port range, and no TLS certificates on your side, and it includes a generous free tier.1
Create a TURN key
In the Cloudflare dashboard, open Realtime > TURN Server and create a key. Copy the Turn Token ID and its API token (the token is shown only once).
2
Set the server environment
In The signaling server mints short-lived ICE credentials from Cloudflare and caches them. These variables take precedence over the coturn variables below, so you do not need to run coturn.
.env:.env
Self-hosting with coturn
Prefer to run the relay yourself? Leave the Cloudflare variables unset and configure coturn instead. TURN requires a public IP address, a domain name, and TLS certificates. The bundledcoturn service uses host networking and is intended for a Linux host with a public IP.
Setup
1
Create the coturn config
Terminal
coturn/turnserver.conf and set:static-auth-secretto a strong random value (e.g.openssl rand -hex 32)realmto your TURN hostname (e.g.turn.your-domain.com)certandpkey(both commented out) to the paths of your TLS certificate and keyexternal-ipto the machine’s public IP, if the interface itself holds a private address
external-ip is commented out in the example file, and uncommenting it is the normal case on AWS, GCP, Azure, and any VPS behind 1:1 NAT. Leave it commented out only when the public address is bound directly to the interface. Get it wrong and coturn advertises a relay candidate nobody can route to, so relayed transfers fail with no error message.The certificate mount is shipped commented out too. Uncomment it in docker-compose.yml so the paths you just set in turnserver.conf exist inside the container:docker-compose.yml
curl quickstart rather than a clone, that means editing your downloaded docker-compose.yml. Skip it and the signaling server still advertises a turns: URL, pointing at a port that cannot complete a TLS handshake.2
Match the server environment
In The signaling server uses these to issue time-limited HMAC-SHA1 credentials for coturn. Credentials expire after 24 hours.
.env:.env
3
Open firewall ports
On the host, open the following ports:
4
Start the stack with the TURN profile
Terminal
Verify
Check that the signaling server returns TURN credentials:Terminal
turn: and turns: entries, plus a stun: entry pointing at your TURN host:
Output
turn.cloudflare.com entries. When neither the Cloudflare variables nor TURN_SECRET / TURN_DOMAIN are set, the endpoint returns the Google public STUN servers only.
How credentials work
The signaling server generates time-limited credentials using HMAC-SHA1. The username is{expiry_unix_timestamp}:floeuser and the password is base64(HMAC-SHA1(TURN_SECRET, username)). coturn validates these against the shared secret without needing a database of user accounts.
Relayed transfers stay capped at 2 GB per session even on a relay you run yourself. The cap is compiled into the browser client, the CLI, and the desktop app, not read from your server, so raising it means building all three from modified source. Direct connections are unaffected and have no size limit. See The 2 GB Relay Limit.