Ваше WebRTC-приложение работает у вас по Wi-Fi и не работает у того самого клиента, который звонит из гостиницы. Медиа между участниками нужен путь; когда обе стороны за строгим NAT или файрвол режет UDP, пути нет, и звонок просто не соединяется. Ошибки никто не видит — только бесконечное «соединение…».
TURN-сервер — запасной вариант для таких звонков: обе стороны отправляют медиа на него, а он ретранслирует. Если вы встраиваете видео или голос в приложение, держите Matrix или Jitsi для команды или делаете голосовой чат для игры — он вам нужен. coturn — стандартная открытая реализация, и она лёгкая.
Какой тариф
CPU и память TURN почти не трогает. Тратит он полосу: каждый ретранслируемый поток идёт через сервер дважды, туда и обратно. Трафик на наших тарифах безлимитный на 1 Гбит/с, так что вопрос не в счёте, а в том, сколько ретранслируемых звонков идёт одновременно.
| Звонков через релей одновременно | Тариф |
|---|---|
| Несколько — команда, небольшое приложение | Nano-IP — 2 vCPU, 1 ГБ, 15 ГБ ($8/мес) |
| Десятки | Micro-IP — 2 vCPU, 2 ГБ, 25 ГБ ($10/мес) |
| Больше, или TURN рядом с сервером приложения | Small-IP — 4 vCPU, 4 ГБ, 35 ГБ ($16/мес) |
Тариф обязательно со своим IPv4: TURN — это сплошь входящие соединения на множество портов, а NAT-тарифы снаружи принимают только SSH. На наших тарифах с выделенным IP публичный адрес висит прямо на интерфейсе сервера, так что coturn находит его сам, строка external-ip не нужна. Ставьте сервер поближе к пользователям: Германия или Финляндия, доступность видна при заказе. Оплата криптой без KYC — если для вас это важно.
Какие порты открыть: 3478 по UDP и TCP, 49152–65535 по UDP для ретранслируемого медиа и 5349 по TCP, если добавите TLS.
Установка и настройка
От root на Ubuntu 24.04 или Debian 12:
apt install -y coturn
ip -4 addr # публичный IP должен быть в списке на интерфейсе
Пишем конфиг со свежим общим секретом:
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" # это значение нужно вашему бэкенду
systemctl restart coturn
ufw allow 22/tcp && ufw allow 3478 && ufw allow 49152:65535/udp && ufw enable
Строки denied-peer-ip не пропускайте. Без них любой, у кого есть действующие учётные данные, может через ваш релей достучаться до частных адресов — в том числе до сервисов на внутренней стороне самого сервера. Мы проверили: с этими строками релей на частный адрес отклоняется с «403 Forbidden IP».
Учётные данные со сроком годности
С use-auth-secret coturn принимает имя пользователя, в котором зашито время истечения, и пароль — HMAC от этого имени. Генерирует их ваш бэкенд, секрет никогда не уходит со стороны сервера. На Node.js:
const crypto = require("crypto");
// Временные логин/пароль для TURN (схема TURN REST API, которую coturn понимает через 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")));
В браузере запрашиваете у бэкенда свежую пару и отдаёте её в 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,
},
],
});
Проверка
С самого сервера, по той же схеме через openssl (он даёт ровно тот же пароль, что и код на Node.js, — мы сравнивали):
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
В конце должно быть «Total lost packets 0». С неверным паролем клиент останавливается на «Cannot complete Allocation» — значит, сервер делает свою работу.
Ещё мы проверили из настоящего Chromium: с iceTransportPolicy: "relay" и свежими учётными данными браузер получил от сервера relay-кандидатов, с неверным паролем — ни одного. Хотите так же проверить свою установку — включите эту опцию ненадолго: она заставляет любой звонок идти через TURN.
TLS, если нужен
Некоторые сети режут UDP и придирчиво относятся к обычному TCP; TURN поверх TLS проходит через большее их число. Получите сертификат на turn.example.com (подойдёт certbot). Его файлы может читать только root, а coturn работает от пользователя turnserver, поэтому дайте coturn собственную копию:
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
Добавьте turns:turn.example.com:5349?transport=tcp в список urls. Сертификаты живут недолго, поэтому копирование положите в deploy hook certbot — иначе TLS тихо сломается при первом же продлении.
Полезно знать
- TURN не делает плохое соединение хорошим. Он добавляет ещё один участок пути, так что ставьте сервер ближе к тем, кому он нужен.
- Если у вас SFU — например, видеомост Jitsi, — это отдельная часть. TURN помогает тем клиентам, которые не могут достучаться до неё напрямую.
- Секрет — это вся модель безопасности. Держите его подальше от фронтенда и меняйте, если он когда-нибудь утечёт.
По теме
- VPS для Jitsi Meet — видеозвонки на своём сервере
- Свой Matrix Synapse — звонкам в Matrix тоже нужен TURN
- VPS для сайта на своём IP — приложение, которое выдаёт учётные данные
- Как настроить файрвол ufw
Комментарии
Пока нет комментариев. Будьте первым.