Home
/ Blog /
WebRTC TURN Server: Internals and BeyondOctober 10, 202211 min read
Share
We know that WebRTC powers almost every kind of live video solution imaginable these days. And not using a TURN server in a WebRTC-based solution, can be compared to not bringing a spare car tyre to a trip to the Himalayas. It may not look like a big deal at first, but in reality, you might actually need more than one spare tyre to complete the trip.
It is estimated that almost 20% of WebRTC call connections require a TURN server, whatever may the architecture of the application be. Even the latest WebRTC ingest and egress standards—WHIP and WHEP make use of STUN/TURN servers. In this article, we’ll discuss everything you need to know about STUN and TURN servers. We will also try to deploy and test a popular open-source TURN server in the end.
Depending on the architecture, WebRTC creates a connection between peers directly or with a media server in the middle. But sometimes, a direct connection to other peers or the media server itself may fail at times. This can happen mainly because of 2 reasons—NAT and Firewall. We will briefly look into them here.
The Network Address Translation is a mechanism that maps the public transport address into private transport address of a device within its local network and vice-versa. A NAT usually lives on a router that sits between the local network and the internet.
A Transport address is nothing but the combination of an IP address and a port number. It is used to uniquely identify a device for communication.
NAT was designed to offer security and help conserve IPV4 addresses over the internet. But it also came with a few issues in respect to direct connection:
Every host device has its own firewall that regulates all the incoming and outgoing network traffic for security purposes. Many enterprise firewalls simply block UDP traffic, as it is not as secure as other transport layer protocols such as TCP.
Since, WebRTC uses UDP for all of its media sessions to optimize for performance, there is a high chance that it may be blocked too. Sometimes, the firewall might also find other peers suspicious, blocking them from establishing a direct connection.
WebRTC uses ICE (Interactive Connection Establishment) framework to find the best path to connect the peers. When the direct connection fails, there must be a way for the peers to establish a connection. This is where STUN and TURN come into picture. Based on several parameters, the ICE framework will automatically try to use the configured STUN and/or TURN servers, when a direct connection is impossible. Since, how ICE works is out of the scope of this article, let us focus only on the STUN and TURN servers.
To understand how these servers help in establishing a connection, let us first try to understand what a STUN server and a TURN server does.
STUN is a network protocol used to retrieve the public IP address (or Transport address) of a device behind NAT so that the device can communicate after knowing its address on the internet. Usually, a STUN server is requested by the peer to know its public IP addresses (or specifically its transport address). Then, the retrieved address is used to communicate with devices outside its local network.
Sometimes, a direct connection is not possible due to NAT restrictions or a firewall blocking a connection, even with the help of STUN server. The only way for peers is to communicate in this case, is by routing the media through a relay server. A TURN server is used for cases like this.
TURN is a network protocol that enables a server to relay data packets (media in this case) between peers when no direct connections are possible. The peers may route media to the TURN server which will relay it to the other peer continuously.
TURN servers are usually referred to as Relay Servers. According to the RFC8656 specification, TURN is considered an extension to the STUN. So, a typical TURN server would include a STUN server implementation by default.
Before trying to understand the operations of a TURN server, let’s take a look at some terminologies involved.
There are 2 participants associated with a TURN session:
The Transport Addresses associated with TURN client and Peers:
The Transport Addresses associated with a TURN server:
The TURN client already has access to the Server Transport Address of the TURN server, from ICE server configuration in case of WebRTC. The TURN server can only sense the Server-Reflexive Transport Address of the client (and peer) and not the Host Transport Address.
This happens when there’s a NAT in the middle, that maps the Server-Reflexive Transport Address to the Host Transport Address for the client/peer. When there’s no NAT in the connection, there’s no need to differentiate the addresses and it can simply be called Transport Address.
Every TURN client is assigned its own Relayed Transport Address for relaying the data. The peers will receive the data from this address and any data that the peers send to this address will be relayed to the respective TURN client that was allocated that address.
The following table illustrates the protocols used for transport between a TURN client to a server and TURN server to a peer.
TURN client to TURN server | TURN server to peer |
---|---|
UDP | UDP |
TCP | UDP |
TLS-over-TCP | UDP |
DTLS-over-UDP | UDP |
According to RFC8656 specification, the communication between the server and a peer always uses UDP. This is very helpful in case of WebRTC. Since the media sessions use UDP for transport, a peer doesn’t have to differentiate between another peer and the TURN server to communicate with it.
And if the client blocks UDP traffic completely, there’s always room to use other transport protocols like TCP, TLS-over-TCP and DTLS-over-UDP. But, what happens if both the client and a peer happen to block UDP traffic? We will come back to that in a later section.
Now let us try to understand the exact steps involved in using a TURN server to achieve connectivity among peers. The peer that cannot participate in a direct connection is usually the TURN client and it will initiate the process.
A client can use TURN commands to create and manipulate an ALLOCATION on the TURN server, by communicating with the server on its Server Transport Address. An ALLOCATION is basically a “TURN Session” associated with the client. Among other things, every ALLOCATION has a corresponding Relayed Transport Address to be used.
The Relayed Transport Address is the address that the other peers can use to interact with. A peer can use the address to relay the data to client. Additionally, the source of the data from the client, relayed to the peer will be the Relayed Transport Address from the peer’s perspective.
When the peers send data to the Relayed Transport Address, it’ll be matched with the ALLOCATION and be relayed to the client who is associated with it. But the data is discarded until a PERMISSION is created for the peer to send data to the client.
The PERMISSION for a peer can be created by the client, by using the address of the peer as it appears to the TURN server. The peer can get this address by sending a STUN Binding Request to the same TURN server (not any other STUN/TURN server) and then forward send it to the client by other means. ICE Candidates are used to handle this in case of WebRTC. Once this is done, the peer can start communicating with the client through the TURN server.
The reason that the peer has to send a STUN Binding Request to the same server is, the transport address the peer got from a different STUN server, may not work for the target TURN server. This happens when the mapping behaviour is either “address-dependant” or “address-and-port-dependant”.
Now, the TURN is ready for relaying data between the client and peers. There are 2 mechanisms for sending and receiving data from the peers through the relay server.
In this mechanism, SendIndication and DataIndication messages are used to relay data between the client and the peers. The client sends a SendIndication message to the server which contains the data and the peer information the data has to be relayed to. The server forms a UDP Datagram using that message and sends it to the respective peer.
Similarly, when a peer sends a UDP Datagram to the server, it is then converted into a DataIndication message and is relayed to the client.
b. Channel Mechanism
In this mechanism, a channel is created for communication between a client-peer pair by using both their Transport Addresses once. There is no need to specify the Transport Address when sending data, unlike in the Send and Data mechanism. This mechanism is recommended when there’s a need for sending lots of data, mainly due of its smaller packet size.
The client creates a channel by sending a ChannelBind request with the peer’s Transport Address and a unique ChannelId. The communication between the client and the server is done by use of ChannelData messages that contain a ChannelId and data among other things. The ChannelData message is converted to a UDP Datagram and sent to the peer. Similarly, any data received from the peer corresponding to a channel is packaged into a ChannelData message before being relaying to the respective client.
Every ALLOCATION has a LIFETIME attribute, denoting the time after which it will expire. The client has to send a refresh request to keep its ALLOCATION alive.
There are mainly 2 ways a TURN server can be used to achieve connectivity. We will look into them by considering one-on-one connection as an example.
In this case, there is one TURN client and one peer. Usually, when only one party has issues with the direct connection, this is the recommended way.
In this case, both parties are TURN clients communicating with each other. This is the solution when both the parties don’t support direct connection and that includes blocking UDP traffic.
Now that we’ve seen too much theoretically about TURN server, let us also try to setup and test our own TURN server. We will be using coTURN, a really popular open-source TURN server implementation.
In this section, we will set up our own TURN server on Ubuntu (and similar Linux based OSes), using coTURN. We will do it in the following steps:
First, create an AWS EC2 instance or a GCP Cloud Compute instance of Ubuntu OS. We will be installing hosting the TURN server in this instance. Then, connect to the instance with the help of SSH.
Run the following commands to update the repo and install coTURN.
sudo apt-get update
sudo apt-get install coturn
To make sure that coTURN always runs at startup, edit the file /etc/default/coturn.
sudo nano /etc/default/coturn
Inside the file, find the line TURNSERVER_ENABLED=1
and uncomment it. Now start the coTURN server by running the following command.
systemctl start coturn
Before modifying the configuration file it is recommended to copy the original configuration file in case something goes wrong.
mv /etc/turnserver.conf /etc/turnserver.conf.backup
sudo nano /etc/turnserver.conf
Now, proceed to edit the configuration file and replace it with the below settings.
realm=<Your Domain>
server-name=turnserver
fingerprint
listening-ip=0.0.0.0
external-ip=<External IP Address>
listening-port=3478
min-port=10000
max-port=20000
user=testname:testpass
lt-cred-mech
log-file=/var/log/turnserver.log
verbose
After finishing the changes, you can restart the coTURN server with the following command.
sudo service coturn restart
Now that we’ve installed and configured a TURN server with coTURN, it is time to test if it works correctly. One of the easiest ways to do this is to use this site that checks for Trickle ICE functionality.
First add the STUN and TURN information in the in the following format. For STUN server URI stun:<IP Address>:<Port>
and for TURN URI turn:<IP Address>:<Port>
with the username and password configured before. Then, click on “Add Server” button.
Once everything is set, you can start the test by clicking on the “Gather Candidates” button.
If your results look similar to the one in the image above without any fatal errors below the button, then the TURN server is working as expected.
Special Mention: If you’re trying to build a custom TURN server/client tuned for your use case, check out pion TURN. It is open source and has great support from the community.
Now that you know everything you need about TURN servers and the role it plays in your WebRTC call, you might as well try building a simple WebRTC app with this guide I wrote.
General
Share