−25%

no Windows com pagamento anual, até 31/10. Ver planos

EQVPS
Começar

VPS para um servidor TURN (coturn) para WebRTC

Chamadas que falham atrás de NAT rígido precisam de um relay TURN. coturn num servidor com IPv4 próprio: portas, credenciais temporárias e uma config testada.

Seu app WebRTC funciona no seu Wi-Fi e falha justamente para o cliente que liga de um hotel. Mídia ponto a ponto precisa de um caminho entre os dois lados; quando ambos estão atrás de NAT rígido, ou um firewall bloqueia UDP, não há caminho e a chamada simplesmente não conecta. Ninguém vê erro nenhum — só um «conectando…» sem fim.

Um servidor TURN é o plano B para essas chamadas: os dois lados mandam a mídia para ele, e ele retransmite. Se você está colocando vídeo ou voz num app, rodando Matrix ou Jitsi para uma equipe ou fazendo chat de voz para um jogo, você precisa de um. O coturn é a implementação open source padrão, e é leve.

Qual plano

O TURN gasta pouca CPU e memória. O que ele usa é banda: cada fluxo retransmitido passa duas vezes pelo servidor, na ida e na volta. Nos nossos planos o tráfego é ilimitado a 1 Gbit/s, então a pergunta é quantas chamadas retransmitidas rodam ao mesmo tempo, e não quanto vai aparecer na conta.

Chamadas retransmitidas ao mesmo tempoPlano
Algumas: uma equipe, um app pequenoNano-IP: 2 vCPU, 1 GB, 15 GB ($8/mês)
DezenasMicro-IP: 2 vCPU, 2 GB, 25 GB ($10/mês)
Mais, ou TURN ao lado do servidor do appSmall-IP: 4 vCPU, 4 GB, 35 GB ($16/mês)

Precisa ser um plano com IPv4 próprio: TURN é todo sobre conexões de entrada em muitas portas, e planos NAT só aceitam SSH de fora. Nos nossos planos com IP dedicado, o endereço público fica direto na interface do servidor, então o coturn o encontra sem linha external-ip. Deixe o servidor perto dos seus usuários: Alemanha ou Finlândia, com a disponibilidade mostrada na hora do pedido. Pagamento em cripto, sem KYC, se isso importa para você.

Portas para abrir: 3478 UDP e TCP, 49152–65535 UDP para a mídia retransmitida e 5349 TCP se você adicionar TLS.

Instalação e configuração

Como root no Ubuntu 24.04 ou Debian 12:

apt install -y coturn
ip -4 addr    # seu IP público deve aparecer na interface

Escreva a configuração com um segredo compartilhado novo:

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"    # seu backend precisa deste valor
systemctl restart coturn
ufw allow 22/tcp && ufw allow 3478 && ufw allow 49152:65535/udp && ufw enable

Não pule as linhas denied-peer-ip. Sem elas, qualquer pessoa com credenciais válidas pode usar seu relay para alcançar endereços privados — inclusive serviços do lado interno do próprio servidor. Conferimos: com essas linhas, um relay para um endereço privado é recusado com «403 Forbidden IP».

Credenciais que expiram

Com use-auth-secret, o coturn aceita um nome de usuário que contém um horário de expiração e uma senha que é um HMAC dele. Seu backend gera os dois; o segredo nunca sai do lado do servidor. Em Node.js:

const crypto = require("crypto");

// Usuário/senha TURN temporários (o esquema TURN REST API que o coturn entende 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")));

No navegador, peça ao backend um par novo e passe para o 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,
    },
  ],
});

Teste

No servidor, com o mesmo esquema usando openssl (ele produz exatamente a mesma senha que o código Node.js — comparamos):

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

No final você quer ver «Total lost packets 0». Com a senha errada, o cliente para em «Cannot complete Allocation» — é o servidor fazendo o trabalho dele.

Também testamos a partir de um Chromium de verdade: com iceTransportPolicy: "relay" e credenciais novas, o navegador recebeu candidatos relay do servidor; com uma senha ruim, nenhum. Se quiser testar sua configuração do mesmo jeito, ative essa opção por um instante — ela força toda chamada a passar pelo TURN.

TLS, se precisar

Algumas redes bloqueiam UDP e são exigentes com TCP puro; TURN sobre TLS passa por mais delas. Obtenha um certificado para turn.example.com (o certbot serve). Os arquivos dele só podem ser lidos pelo root, enquanto o coturn roda como o usuário turnserver, então dê ao coturn uma cópia própria:

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

Adicione turns:turn.example.com:5349?transport=tcp à lista urls. Os certificados duram pouco, então coloque a cópia num deploy hook do certbot — senão o TLS quebra em silêncio na primeira renovação.

Bom saber

  • TURN não transforma uma conexão ruim em boa. Ele acrescenta um salto, então coloque o servidor perto de quem precisa dele.
  • Se você roda um SFU — o videobridge do Jitsi, por exemplo —, é uma peça separada. O TURN ajuda os clientes que não conseguem alcançá-lo diretamente.
  • O segredo é todo o modelo de segurança. Mantenha-o fora do frontend e troque-o se algum dia vazar.

Relacionados

Pronto para implantar? Pague com cripto, sem KYC — online em cerca de um minuto.

Implantar agora →

FAQ

Por que chamadas WebRTC precisam de um servidor TURN?

O WebRTC tenta conectar os participantes diretamente, e quase sempre consegue. Quando os dois lados estão atrás de NAT simétrico ou de um firewall que bloqueia UDP — Wi-Fi de hotel, redes de escritório, algumas operadoras móveis —, não há caminho direto e a chamada falha em silêncio. Um servidor TURN retransmite a mídia justamente nessas chamadas; a proporção costuma ser citada em torno de uma a cada dez.

O TURN roda num plano NAT?

Não. Os clientes se conectam em UDP e TCP 3478 e na faixa de portas de relay, e um plano NAT só aceita de fora a sua porta SSH. Você precisa de um plano com IPv4 próprio.

Quanta banda ele usa?

Cada fluxo retransmitido passa duas vezes pelo servidor: entra de um lado e sai para o outro. Uma videochamada a dois de 1–2 Mbit/s por sentido dá alguns Mbit/s no servidor. CPU e RAM mal percebem; o teto real é a porta de 1 Gbit/s.

Por que não colocar um usuário e senha fixos no app?

Porque tudo que está no JavaScript do navegador é público, e um servidor TURN com senha conhecida é um relay gratuito para a internet inteira. Com use-auth-secret, seu backend distribui credenciais que expiram, assinadas com um segredo que o navegador nunca vê.

Preciso de TLS na porta 5349?

Ajuda em redes que bloqueiam UDP e são rígidas com TCP puro. Adicione depois que o TURN simples estiver funcionando: dê ao coturn um certificado para o nome do host TURN e abra 5349/tcp. Também testamos o relay sobre TLS.

Comentários

Nenhum comentário ainda. Seja o primeiro.

Deixe um comentário

Os comentários são moderados antes de aparecerem.