La tua app WebRTC funziona sul tuo Wi-Fi e fallisce proprio per il cliente che chiama da un albergo. I flussi peer-to-peer hanno bisogno di un percorso tra i due lati; quando entrambi stanno dietro un NAT rigido, o un firewall blocca l'UDP, il percorso non c'è e la chiamata semplicemente non si connette. Nessuno vede un errore: solo un «connessione in corso…» infinito.
Un server TURN è il ripiego per quelle chiamate: entrambi i lati gli mandano i loro flussi, e lui li inoltra. Se stai integrando video o voce in un'app, gestisci Matrix o Jitsi per un team o fai chat vocale per un gioco, ti serve. coturn è l'implementazione open source di riferimento, ed è leggera.
Quale piano
TURN pesa poco su CPU e memoria. Quello che usa è la banda: ogni flusso inoltrato passa due volte dal server, in entrata e in uscita. Sui nostri piani il traffico è illimitato a 1 Gbit/s, quindi la domanda è quante chiamate inoltrate girano insieme, non quanto ti verrà fatturato.
| Chiamate inoltrate in contemporanea | Piano |
|---|---|
| Poche: un team, una piccola app | Nano-IP: 2 vCPU, 1 GB, 15 GB ($8/mese) |
| Decine | Micro-IP: 2 vCPU, 2 GB, 25 GB ($10/mese) |
| Di più, o TURN accanto al server dell'app | Small-IP: 4 vCPU, 4 GB, 35 GB ($16/mese) |
Dev'essere un piano con un IPv4 tutto suo: TURN vive di connessioni in entrata su molte porte, e i piani NAT accettano dall'esterno solo SSH. Sui nostri piani con IP dedicato l'indirizzo pubblico sta direttamente sull'interfaccia del server, quindi coturn lo trova senza la riga external-ip. Metti il server vicino ai tuoi utenti: Germania o Finlandia, la disponibilità si vede al momento dell'ordine. Pagamento in cripto, senza KYC, se per te conta.
Porte da aprire: 3478 UDP e TCP, 49152–65535 UDP per i flussi inoltrati e 5349 TCP se aggiungi TLS.
Installazione e configurazione
Come root su Ubuntu 24.04 o Debian 12:
apt install -y coturn
ip -4 addr # il tuo IP pubblico dovrebbe comparire sull'interfaccia
Scrivi la configurazione con un segreto condiviso nuovo:
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" # questo valore serve al tuo backend
systemctl restart coturn
ufw allow 22/tcp && ufw allow 3478 && ufw allow 49152:65535/udp && ufw enable
Non saltare le righe denied-peer-ip. Senza di esse, chiunque abbia credenziali valide può usare il tuo relay per raggiungere indirizzi privati, compresi i servizi sul lato interno del server stesso. Abbiamo verificato: con queste righe un relay verso un indirizzo privato viene rifiutato con «403 Forbidden IP».
Credenziali che scadono
Con use-auth-secret, coturn accetta un nome utente che contiene un'ora di scadenza e una password che ne è l'HMAC. Le genera il tuo backend; il segreto non lascia mai il lato server. In Node.js:
const crypto = require("crypto");
// Utente/password TURN temporanei (lo schema TURN REST API che coturn capisce tramite 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")));
Nel browser, chiedi al backend una coppia nuova e passala a 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,
},
],
});
Provalo
Dal server, con lo stesso schema usando openssl (produce esattamente la stessa password del codice Node.js: abbiamo confrontato):
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
Alla fine vuoi vedere «Total lost packets 0». Con una password sbagliata il client si ferma a «Cannot complete Allocation»: è il server che fa il suo lavoro.
Abbiamo verificato anche da un vero Chromium: con iceTransportPolicy: "relay" e credenziali fresche il browser ha ricevuto candidati relay dal server; con una password sbagliata, nessuno. Se vuoi provare la tua configurazione allo stesso modo, attiva quell'opzione per un momento: costringe ogni chiamata a passare da TURN.
TLS, se serve
Alcune reti bloccano l'UDP e sono pignole con il TCP in chiaro; TURN su TLS ne attraversa di più. Procurati un certificato per turn.example.com (va bene certbot). I suoi file sono leggibili solo da root, mentre coturn gira come utente turnserver, quindi dai a coturn una copia sua:
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
Aggiungi turns:turn.example.com:5349?transport=tcp all'elenco urls. I certificati durano poco, quindi metti la copia in un deploy hook di certbot: altrimenti TLS si rompe in silenzio al primo rinnovo.
Da sapere
- TURN non rende buona una connessione cattiva. Aggiunge un salto, quindi metti il server vicino a chi ne ha bisogno.
- Se usi un SFU, per esempio il videobridge di Jitsi, è un pezzo separato. TURN aiuta i client che non riescono a raggiungerlo direttamente.
- Il segreto è tutto il modello di sicurezza. Tienilo fuori dal frontend e cambialo se mai dovesse trapelare.
Correlati
- VPS per Jitsi Meet: videochiamate sul tuo server
- Matrix Synapse in self-hosting: anche le chiamate Matrix hanno bisogno di un server TURN
- VPS per un sito con IP proprio: l'app che distribuisce le credenziali
- Come configurare un firewall ufw
Commenti
Ancora nessun commento. Sii il primo.