Skip to content

Relay server (TURN)

Pure P2P connections sometimes can't be established due to firewall / NAT issues on one or all users' ends. To address those issues and bypass the most recalcitrant firewalls, one or more TURN (Traversal Using Relay NAT) servers can be used.

Drovio Server supports two ways of providing relays, that you can set with webrtc.turn_provider.type in settings.conf:

type Relays Credentials
shared_secret (default) Your own coturn servers Computed locally from a shared secret
cloudflare Cloudflare Realtime TURN Requested from the Cloudflare API

Running your own coturn server keeps every relayed packet on the infrastructure you control and lets you control the ports and protocols being opened. Cloudflare removes the machine to install, patch and monitor. Both ways are covered below.

Existing deployments

shared_secret is the default: a deployment that does not declare turn_provider at all keeps behaving exactly as before.

Run your own coturn

We use coturn (github.com/coturn/coturn) for our TURN servers, as most vendors do (Slack, Zoom…). Coturn also works as a STUN server to answer basic "what is my public IP address" queries.

Dedicated machine

We don't recommend deploying a TURN server on the same machine where Drovio Server is deployed, for security and performance reasons.

Install on Debian

Coturn is packaged for Debian (Debian 13 comes with the ~latest version) and runs on x64 as well as on arm64; the commands below are the same on both. Step by step, on a freshly installed Debian 13 machine:

sudo apt update
sudo apt install coturn
sudo nano /etc/default/coturn
  • Uncomment TURNSERVER_ENABLED=1 and save.
  • Open the config file (see Configure coturn below):
sudo nano /etc/turnserver.conf

Install on RHEL

Coturn is available through EPEL on RHEL 9 and 10. Step by step:

# Enable EPEL (RHEL 9 example; adjust the URL for your version)
sudo dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm
sudo dnf install coturn

Then open the config file (see Configure coturn below):

sudo nano /etc/coturn/turnserver.conf

Configure coturn

Edit turnserver.conf as follows:

Listening and network:

  • listening-port and tls-listening-port should be set to 80 and 443 instead of the default ports, to bypass most firewalls.
  • listening-ip = public IP, or the private IP if you are behind a NAT (e.g. AWS EC2).
  • relay-ip = same as listening-ip.
  • external-ip = the public IP, only when listening-ip is a private address behind a NAT.
  • min-port=49152 and max-port=65535: the UDP port range coturn allocates for relay traffic. Open this range in your firewall for UDP.

Authentication:

  • fingerprint should be uncommented.
  • static-auth-secret=MySeCrEt: replace with a long random string. This is the shared secret between Drovio Server and coturn.
  • realm=turn.example.com: replace; does not need to resolve to anything.
  • stale-nonce=600 should be uncommented.

Bandwidth:

  • max-bps: maximum bytes per second per session. Comment it out to leave it unlimited, or set it to at least the max bitrate configured in settings.conf (webrtc.service_quality.maximum). Note that max-bps is in bytes per second while webrtc.service_quality.maximum is in kbits per second (default is 10 Mbps, i.e. 1,250,000 bytes/s).

TLS (optional, for TURNS support):

  • cert and pkey paths should point to your certificate and private key. If you do not need TURNS, skip this and use port 80 only when referring to this server (see Configure Drovio Server).
  • Set cipher-list to "ECDH+AESGCM:ECDH+CHACHA20:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS:!AESCCM".
  • no-tlsv1 and no-tlsv1_1 should be uncommented.

Security hardening:

  • no-multicast-peers should be uncommented. allow-loopback-peers must stay commented (loopback is denied by default since coturn 4.5.2).
  • no-tcp-relay should be uncommented: Drovio uses UDP relay only, disabling TCP relay reduces the attack surface.
  • denied-peer-ip=0.0.0.0/8, denied-peer-ip=10.0.0.0/8, denied-peer-ip=172.16.0.0/12, denied-peer-ip=192.168.0.0/16, denied-peer-ip=127.0.0.0/8: prevents relayed traffic from reaching private or loopback networks.
  • no-software-attribute should be uncommented (hides the coturn version from responses).
  • no-rfc5780, no-stun-backward-compatibility and response-origin-only-with-rfc5780 should be uncommented. These disable legacy STUN features that are not needed and reduce exposure.

You may also want to isolate the server in its own network / VPC.

CLI:

  • cli-ip=127.0.0.1, cli-port=5766, cli-password=myclipassword: change the CLI password. This is useful to check connected peers by running telnet localhost 5766, entering the password, then ps. Do not expose the CLI port externally.

Save, then restart coturn:

sudo systemctl restart coturn

Your relay / TURN (and STUN) server is now up and running.

Configure Drovio Server

Back on your Drovio Server instance:

sudo nano /etc/drovio-server/settings.conf

Look for webrtc, then replace turn_servers_secret with the static-auth-secret value set above and adapt the config below to your needs, making sure to replace the turn.example.com URL with the URL or IP of your coturn machine:

"webrtc": {
  "turn_servers_secret": "MySeCrEt",
  "turn_servers_auth_timeout": 300,
  "ice_servers": [
    { "url": "stun:turn.example.com:443" },
    { "url": "turn:turn.example.com:443" },
    { "url": "turn:turn.example.com:443?transport=tcp" },
    { "url": "turns:turn.example.com:443" }
  ],
  "service_quality": {
    "minimum": 1000,
    "maximum": 10000
  }
}
  • The first entry is STUN (only replies to "what is my IP address?" requests).
  • The second is the classic 443 UDP TURN (without the TLS layer).
  • The third is 443 TCP TURN (without the TLS layer).
  • The fourth is 443 UDP TURNS (extra TLS layer).

This should work with most recalcitrant firewalls. The webrtc section is applied live, so there is nothing to restart: the new relays are picked up within a few seconds.

Use Cloudflare Realtime TURN

Cloudflare Realtime TURN is a managed relay service: there is no machine to install, patch or monitor and each participant is served by the Cloudflare location closest to them. Cloudflare bills the relayed traffic, refer to their pricing page for current rates.

Create a TURN key

  1. Open the Cloudflare dashboard, then Realtime → TURN.
  2. Create a TURN key and note its Key ID and API token. The token is displayed once.

Point Drovio Server at Cloudflare

On your Drovio Server instance:

sudo nano /etc/drovio-server/settings.conf

Look for webrtc, set turn_provider to cloudflare and list Cloudflare's relays in ice_servers:

"webrtc": {
  "turn_provider": {
    "type": "cloudflare",
    "cloudflare": {
      "key_id": "<your key id>",
      "api_token": "<your api token>",
      "ttl": 86400
    }
  },
  "ice_servers": [
    { "url": "stun:stun.cloudflare.com:3478" },
    { "url": "turn:turn.cloudflare.com:3478?transport=udp" },
    { "url": "turn:turn.cloudflare.com:3478?transport=tcp" },
    { "url": "turns:turn.cloudflare.com:443?transport=tcp" }
  ],
  "service_quality": {
    "minimum": 1000,
    "maximum": 10000
  }
}

turn_servers_secret and turn_servers_auth_timeout are ignored while type is cloudflare. Leave them in place: setting type back to shared_secret restores your coturn setup without any other change.

Like the rest of the webrtc section, this is applied live and you don't have to restart Drovio Server.

Credential lifetime

ttl is how long in seconds a credential sent to a client remains valid.

  • Cloudflare refuses credentials living longer than 48 hours. Larger values get capped.
  • Drovio Server renews its credential halfway through that lifetime.
  • A client asks for a credential once when it opens a connection and never again. A ttl shorter than your longest meeting takes the relay down mid-session. Keep the default unless you have a reason not to.

If Cloudflare cannot be reached while renewing, Drovio Server keeps serving the credential it already holds until it really expires and logs the failure.

Firewall reach

Cloudflare answers UDP only on port 3478. Its port 443 is TCP only, wrapped in TLS (turns:). A participant behind a firewall that allows nothing but outbound 443 therefore falls back to a TCP relay. That adds latency and copes less well with packet loss than UDP.

If you have a restrictive firewall that only allows port 443 and performance matters, you may want to run your own coturn server with UDP port 443.

Verify the relay server

Adding ice=relay to the query string of a web client URL forces every connection of that session through a relay, in any browser.

  1. Open the Drovio app and sign in.
  2. Use the bolt icon to start an instant meeting.
  3. Copy then paste the invite link into a browser and append ?ice=relay to it.
  4. Proceed, enter a display name (don't "start the app instead", stay in the web browser) and proceed again.
  5. You should see your own screen, mirrored when viewing the shared screen.

If all you get is a loading spinner, the relay is not reachable or its credentials are refused. The browser console also displays a warning, The url forces every connection through the TURN server, which confirms the parameter was applied correctly.