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.

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.

Verify the relay server

To check that the relay server is working correctly:

  1. Start Firefox.
  2. Enter about:config in the URL bar, accept and continue.
  3. In the search bar, type relay.
  4. Set media.peerconnection.ice.relay_only to true.
  5. Open the Drovio app and sign in.
  6. Use the envelope icon and click Invite by URL.
  7. Paste the invite link into Firefox and proceed.
  8. Enter a display name (don't "start the app instead", use the web browser) and proceed.
  9. You should see your own screen (mirrored when viewing the shared screen).
  10. Open a new tab in Firefox (without closing the current one) and enter about:webrtc.
  11. Click Show details.
  12. You should see ICE State: succeeded, nominated: true, selected: true and relay mentioned next to your IP address (instead of host, srflx or prflx).

Reset the flag

Don't forget to set media.peerconnection.ice.relay_only back to false.