Votre application WebRTC fonctionne sur votre Wi-Fi et échoue chez le seul client qui appelle depuis un hôtel. Les médias pair-à-pair ont besoin d'un chemin entre les deux côtés ; quand les deux sont derrière un NAT strict, ou qu'un pare-feu bloque l'UDP, il n'y a pas de chemin et l'appel ne se connecte tout simplement pas. Personne ne voit d'erreur — juste un « connexion… » interminable.
Un serveur TURN est la solution de repli pour ces appels : les deux côtés lui envoient leurs médias, et il relaie. Si vous intégrez la vidéo ou la voix dans une app, faites tourner Matrix ou Jitsi pour une équipe, ou proposez un chat vocal pour un jeu, il vous en faut un. coturn est l'implémentation open source de référence, et elle est légère.
Quelle offre
TURN consomme peu de CPU et de mémoire. Ce qu'il utilise, c'est la bande passante : chaque flux relayé traverse le serveur deux fois, à l'aller et au retour. Le trafic est illimité à 1 Gbit/s sur nos offres, donc la question est de savoir combien d'appels relayés tournent en même temps, pas combien vous serez facturé.
| Appels relayés en simultané | Offre |
|---|---|
| Quelques-uns — une équipe, une petite app | Nano-IP — 2 vCPU, 1 Go, 15 Go (8 $/mois) |
| Quelques dizaines | Micro-IP — 2 vCPU, 2 Go, 25 Go (10 $/mois) |
| Davantage, ou TURN à côté de votre serveur d'app | Small-IP — 4 vCPU, 4 Go, 35 Go (16 $/mois) |
Il faut une offre avec sa propre IPv4 — TURN, ce sont des connexions entrantes sur de nombreux ports, et les offres NAT n'acceptent que le SSH de l'extérieur. Sur nos offres à IP dédiée, l'adresse publique est directement sur l'interface du serveur, donc coturn la trouve sans ligne external-ip. Placez le serveur près de vos utilisateurs : Allemagne ou Finlande, la disponibilité s'affiche à la commande. Paiement en crypto, sans KYC, si cela compte pour vous.
Ports à ouvrir : 3478 en UDP et TCP, 49152–65535 en UDP pour les médias relayés, et 5349 en TCP si vous ajoutez TLS.
Installation et configuration
En root sur Ubuntu 24.04 ou Debian 12 :
apt install -y coturn
ip -4 addr # votre IP publique doit apparaître sur l'interface
Écrivez la configuration avec un secret partagé tout neuf :
SECRET=$(openssl rand -hex 32)
cat > /etc/turnserver.conf <<EOF
listening-port=3478
fingerprint
use-auth-secret
static-auth-secret=$SECRET
realm=turn.example.com
min-port=49152
max-port=65535
no-cli
no-multicast-peers
denied-peer-ip=0.0.0.0-0.255.255.255
denied-peer-ip=10.0.0.0-10.255.255.255
denied-peer-ip=100.64.0.0-100.127.255.255
denied-peer-ip=127.0.0.0-127.255.255.255
denied-peer-ip=169.254.0.0-169.254.255.255
denied-peer-ip=172.16.0.0-172.31.255.255
denied-peer-ip=192.168.0.0-192.168.255.255
EOF
echo "$SECRET" # votre backend a besoin de cette valeur
systemctl restart coturn
ufw allow 22/tcp && ufw allow 3478 && ufw allow 49152:65535/udp && ufw enable
Ne sautez pas les lignes denied-peer-ip. Sans elles, n'importe qui disposant d'identifiants valides peut utiliser votre relais pour atteindre des adresses privées — y compris des services du côté interne du serveur lui-même. Nous avons vérifié : avec ces lignes, un relais vers une adresse privée est refusé avec « 403 Forbidden IP ».
Des identifiants qui expirent
Avec use-auth-secret, coturn accepte un nom d'utilisateur qui contient une date d'expiration et un mot de passe qui en est le HMAC. C'est votre backend qui les génère ; le secret ne quitte jamais le côté serveur. En Node.js :
const crypto = require("crypto");
// Identifiant/mot de passe TURN temporaires (le schéma TURN REST API que coturn comprend via use-auth-secret).
function turnCredentials(secret, user, ttlSeconds = 3600) {
const username = `${Math.floor(Date.now() / 1000) + ttlSeconds}:${user}`;
const credential = crypto.createHmac("sha1", secret).update(username).digest("base64");
return { username, credential };
}
console.log(JSON.stringify(turnCredentials(process.env.TURN_SECRET, "alice")));
Dans le navigateur, demandez une nouvelle paire à votre backend et passez-la à RTCPeerConnection :
const { username, credential } = await fetch("/api/turn-credentials").then((r) => r.json());
const pc = new RTCPeerConnection({
iceServers: [
{ urls: "stun:turn.example.com:3478" },
{
urls: ["turn:turn.example.com:3478?transport=udp", "turn:turn.example.com:3478?transport=tcp"],
username,
credential,
},
],
});
Le tester
Depuis le serveur, avec le même schéma via openssl (il produit exactement le même mot de passe que le code Node.js — nous avons comparé) :
U="$(( $(date +%s) + 3600 )):test"
P=$(echo -n "$U" | openssl dgst -binary -sha1 -hmac "$SECRET" | base64)
turnutils_uclient -y -n 10 -u "$U" -w "$P" YOUR_SERVER_IP
À la fin, vous voulez voir « Total lost packets 0 ». Avec un mauvais mot de passe, le client s'arrête sur « Cannot complete Allocation » — c'est le serveur qui fait son travail.
Nous avons aussi testé depuis un vrai Chromium : avec iceTransportPolicy: "relay" et des identifiants frais, le navigateur a obtenu des candidats relay du serveur ; avec un mauvais mot de passe, aucun. Pour tester votre propre installation de la même façon, activez cette option un instant — elle force chaque appel à passer par TURN.
TLS, si besoin
Certains réseaux bloquent l'UDP et se montrent pointilleux avec le TCP en clair ; TURN sur TLS en traverse davantage. Obtenez un certificat pour turn.example.com (certbot convient). Ses fichiers ne sont lisibles que par root, alors que coturn tourne sous l'utilisateur turnserver : donnez donc à coturn sa propre copie :
mkdir -p /etc/coturn
cp /etc/letsencrypt/live/turn.example.com/fullchain.pem /etc/letsencrypt/live/turn.example.com/privkey.pem /etc/coturn/
chown turnserver: /etc/coturn/*.pem && chmod 640 /etc/coturn/privkey.pem
cat >> /etc/turnserver.conf <<'EOF'
tls-listening-port=5349
cert=/etc/coturn/fullchain.pem
pkey=/etc/coturn/privkey.pem
EOF
systemctl restart coturn && ufw allow 5349/tcp
Ajoutez turns:turn.example.com:5349?transport=tcp à la liste urls. Les certificats ont une durée de vie courte : placez la copie dans un deploy hook de certbot, sinon TLS cassera discrètement au premier renouvellement.
Bon à savoir
- TURN ne rend pas bonne une mauvaise connexion. Il ajoute un saut, donc placez le serveur près des personnes qui en ont besoin.
- Si vous faites tourner un SFU — le videobridge de Jitsi, par exemple —, c'est une brique séparée. TURN aide les clients qui ne peuvent pas l'atteindre directement.
- Le secret est tout le modèle de sécurité. Gardez-le hors du frontend, et changez-le s'il fuit un jour.
Sur le même sujet
- VPS pour Jitsi Meet — des appels vidéo sur votre propre serveur
- Héberger Matrix Synapse — les appels Matrix ont aussi besoin d'un serveur TURN
- VPS pour un site web sur sa propre IP — l'app qui distribue les identifiants
- Configurer un pare-feu ufw
Commentaires
Pas encore de commentaires. Soyez le premier.