Skip to main content
A TURN server relays the (still end-to-end encrypted) stream when two peers cannot reach each other directly. This is common with symmetric NAT or carrier-grade NAT. Without TURN, those specific transfers fail. All other transfers still work over direct connections.

Infrastructure requirements

TURN requires a public IP address, a domain name, and TLS certificates. The bundled coturn service uses host networking and is intended for a Linux host with a public IP.
The coturn service uses host networking (network_mode: host). This only works on Linux. On macOS or Windows with Docker Desktop, you will need to run coturn separately or on a Linux VM.

Setup

1

Create the coturn config

cp coturn/turnserver.conf.example coturn/turnserver.conf
Edit coturn/turnserver.conf and set:
  • static-auth-secret to a strong random value (e.g. openssl rand -hex 32)
  • realm to your TURN hostname (e.g. turn.your-domain.com)
  • cert and pkey to the paths of your TLS certificate and key
See the volume mounts in docker-compose.yml for how to make certificates available inside the container.
2

Match the server environment

In .env:
TURN_SECRET=<same value as static-auth-secret>
TURN_DOMAIN=turn.your-domain.com
The signaling server uses these to issue time-limited HMAC-SHA1 credentials for coturn. Credentials expire after 24 hours.
3

Open firewall ports

On the host, open the following ports:
PortProtocolPurpose
3478UDP/TCPSTUN and TURN
5349UDP/TCPTURNS (TURN over TLS)
49152-65535UDPRelay data range (configurable in turnserver.conf)
4

Start the stack with the TURN profile

docker compose --profile turn up -d --build

Verify

Check that the signaling server returns TURN credentials:
curl http://localhost:3001/api/turn-credentials
The response should include turn: and turns: entries alongside STUN:
[
  { "urls": "stun:stun.l.google.com:19302" },
  { "urls": "turn:turn.your-domain.com:3478", "username": "...", "credential": "..." },
  { "urls": "turns:turn.your-domain.com:5349", "username": "...", "credential": "..." }
]

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.