−25%

på Windows vid årsbetalning, till 31/10. Till paketen

EQVPS
Kom igång

VPS för en TURN-server (coturn) för WebRTC

Samtal som fastnar bakom strikt NAT behöver ett TURN-relä. coturn på en server med egen IPv4: portar, tidsbegränsade inloggningsuppgifter, testad konfig.

Din WebRTC-app fungerar på ditt wifi och misslyckas för just den kund som ringer från ett hotell. Peer-to-peer-media behöver en väg mellan de två sidorna; när båda sitter bakom strikt NAT, eller en brandvägg släpper UDP, finns ingen väg och samtalet kopplas helt enkelt inte upp. Ingen ser något fel — bara ett ändlöst ”ansluter…”.

En TURN-server är reservvägen för just de samtalen: båda sidor skickar sina media till den, och den vidarebefordrar. Bygger du in video eller röst i en app, kör Matrix eller Jitsi för ett team eller gör röstchatt för ett spel, vill du ha en. coturn är den vanliga implementationen med öppen källkod, och den är lätt.

Vilken plan

TURN kräver lite CPU och minne. Det som går åt är bandbredd: varje vidarebefordrad ström passerar servern två gånger, in och ut. Trafiken på våra planer är obegränsad på 1 Gbit/s, så frågan är hur många vidarebefordrade samtal som pågår samtidigt, inte hur mycket du blir debiterad.

Vidarebefordrade samtal samtidigtPlan
En handfull — ett team, en liten appNano-IP: 2 vCPU, 1 GB, 15 GB ($8/mån)
DussintalsMicro-IP: 2 vCPU, 2 GB, 25 GB ($10/mån)
Fler, eller TURN bredvid din appserverSmall-IP: 4 vCPU, 4 GB, 35 GB ($16/mån)

Det måste vara en plan med egen IPv4 — TURN handlar helt om inkommande anslutningar på många portar, och NAT-planer tar bara emot SSH utifrån. På våra planer med egen IP ligger den publika adressen direkt på serverns gränssnitt, så coturn hittar den utan en external-ip-rad. Placera servern nära dina användare: Tyskland eller Finland, tillgängligheten syns vid beställning. Betalning med krypto, utan KYC, om det spelar roll för dig.

Portar att öppna: 3478 UDP och TCP, 49152–65535 UDP för vidarebefordrad media och 5349 TCP om du lägger till TLS.

Installera och konfigurera

Som root på Ubuntu 24.04 eller Debian 12:

apt install -y coturn
ip -4 addr    # din publika IP ska synas på gränssnittet

Skriv konfigurationen med en ny delad hemlighet:

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"    # din backend behöver det här värdet
systemctl restart coturn
ufw allow 22/tcp && ufw allow 3478 && ufw allow 49152:65535/udp && ufw enable

Hoppa inte över raderna denied-peer-ip. Utan dem kan vem som helst med giltiga uppgifter använda ditt relä för att nå privata adresser — även tjänster på serverns egen interna sida. Vi kontrollerade: med de här raderna nekas ett relä till en privat adress med ”403 Forbidden IP”.

Inloggningsuppgifter som går ut

Med use-auth-secret accepterar coturn ett användarnamn som innehåller en utgångstid och ett lösenord som är en HMAC av det. Din backend genererar dem; hemligheten lämnar aldrig serversidan. I Node.js:

const crypto = require("crypto");

// Tillfälligt TURN-användarnamn och lösenord (TURN REST API-schemat som coturn förstår 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")));

I webbläsaren ber du din backend om ett nytt par och ger det till 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,
    },
  ],
});

Testa

Från servern, med samma schema via openssl (det ger exakt samma lösenord som Node.js-koden — vi jämförde):

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

I slutet vill du se ”Total lost packets 0”. Med fel lösenord stannar klienten vid ”Cannot complete Allocation” — det är servern som gör sitt jobb.

Vi testade också från en riktig Chromium: med iceTransportPolicy: "relay" och färska uppgifter fick webbläsaren relay-kandidater från servern; med fel lösenord inga alls. Vill du testa din egen uppsättning på samma sätt, slå på det alternativet en stund — det tvingar varje samtal genom TURN.

TLS, om du behöver det

Vissa nät blockerar UDP och är petiga med vanlig TCP; TURN över TLS tar sig igenom fler av dem. Skaffa ett certifikat för turn.example.com (certbot duger). Filerna kan bara läsas av root, medan coturn körs som användaren turnserver, så ge coturn en egen kopia:

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

Lägg till turns:turn.example.com:5349?transport=tcp i listan urls. Certifikat är kortlivade, så lägg kopieringen i en deploy hook för certbot — annars går TLS tyst sönder vid första förnyelsen.

Bra att veta

  • TURN gör inte en dålig anslutning bra. Den lägger till ett hopp, så placera servern nära dem som behöver den.
  • Kör du en SFU — till exempel Jitsis videobridge — är det en separat del. TURN hjälper klienterna som inte når den direkt.
  • Hemligheten är hela säkerhetsmodellen. Håll den borta från frontend och byt ut den om den någonsin läcker.

Relaterat

Redo att distribuera? Betala med krypto, ingen KYC — igång på ungefär en minut.

Distribuera nu →

FAQ

Varför behöver WebRTC-samtal en TURN-server över huvud taget?

WebRTC försöker koppla ihop deltagarna direkt, och det lyckas oftast. När båda sidor sitter bakom symmetrisk NAT eller en brandvägg som släpper UDP — hotell-wifi, kontorsnät, vissa mobiloperatörer — finns ingen direkt väg, och samtalet misslyckas utan att något syns. En TURN-server vidarebefordrar media för just de samtalen; andelen som brukar nämnas ligger runt ett samtal av tio.

Kan TURN köras på en NAT-plan?

Nej. Klienterna ansluter till UDP och TCP 3478 och till reläets portintervall, och en NAT-plan tar bara emot din SSH-port utifrån. Du behöver en plan med egen IPv4.

Hur mycket bandbredd går åt?

Varje vidarebefordrad ström går två gånger genom servern — in från ena sidan, ut till den andra. Ett videosamtal mellan två på 1–2 Mbit/s per riktning blir några Mbit/s på servern. CPU och RAM märker knappt något; det verkliga taket är porten på 1 Gbit/s.

Varför inte bara lägga ett fast användarnamn och lösenord i appen?

För att allt i webbläsarens JavaScript är offentligt, och en TURN-server med känt lösenord är ett gratis relä för hela internet. Med use-auth-secret delar din backend ut inloggningsuppgifter som går ut, signerade med en hemlighet som webbläsaren aldrig ser.

Behöver jag TLS på port 5349?

Det hjälper i nät som blockerar UDP och är strikta med vanlig TCP. Lägg till det när vanlig TURN fungerar: ge coturn ett certifikat för TURN-värdnamnet och öppna 5349/tcp. Vi testade reläet över TLS också.

Kommentarer

Inga kommentarer än. Bli först.

Lämna en kommentar

Kommentarer modereras innan de visas.