ESPN DeportesMiami reaccionó y conservó su invicto tras visita a North CarolinaESPNTwo soon! How Williams ignited Valkyries to WNBA title in their second seasonPunchMy brother was beaten to death by step-siblings over bag theft allegation — SisterInquirerUndas 2026: PITX logs over 1.38 million passengers as of Nov. 1ZDF heuteAktuelle Pressemitteilungen des ZDFThe Jerusalem PostIsrael needs a bold, fresh approach and unity government in wake of election stalemate - editorialSouth China Morning Post‘Be alive’: Hongkonger with muscular dystrophy turns 18, against all oddsХабрВиза талантов в США для айтишника경향신문남아서 식은 파스타가 더 건강에 좋다고?中国新闻网湖北宜昌:1.6万跑者穿行“水电之都”DeadlineInde Navarrette Kicks Off ‘Saturday Night Live’ Debut With Shane Gillis Quip About Her “Little Whore Outfit” For Getting Into Marvel ShapeNHK 社会兼六園で冬の風物詩「雪吊り」の作業始まる 金沢
The Daily Newsstand · Free, Always
Sunday, November 1, 2026

Slyber TURN Server для WebRTC приложений с установкой в одну команду

Translate
Slyber Turn Server

Slyber Turn Server

Привет Хабр!

В этой статье я расскажу зачем я создал собственный TURN сервер в то время когда есть древний Coturn который я устал постоянно разворачивать и настраивать для своих приложений. 

В моих глобал проектах на WebRtc около 20 процентов пользователей всегда находятся за NAT, CGNAT или за корпоративными файрволами. Напрямую такие юзеры соединиться не могут, поэтому трафик нужно пропускать через сервер посредник "TURN", иначе будут жаловаться в тех поддержку.

Долгое время я использовал древний тяжелый Coturn написанный на C. Он закрывает базовые задачи, но при настройке новых серверов появляются много ручной работы. В итоге я не выдержал и написал свой сервер Slyber TURN Server на Go поверх библиотеки pion/turn/v4. Он собирается в один статический бинарник для linux/amd64 и linux/arm64 без внешних зависимостей и ставится одной командой.

Ниже разберу технические проблемы, из за которых я ушел с Coturn, и как они решены в моем сервере.

Что меня не устраивало в Coturn

Первая проблема связана с конфигурацией и сетью. В turnserver.conf много параметров. На облачных виртуалках сервер не видит свой внешний IPv4 адрес. Приходится писать костыли, которые при старте запрашивают внешний IP, записывают его в конфиг и перезапускают службу.

Вторая проблема это авторизация юзеров. Хранить статический логин и пароль на фронтенде нельзя, иначе доступы украдут и начнут гонять чужой трафик. Понятное дело что это можно было бы реализовать на бекенде самого приложения но это не удобно постоянно делать для каждого отдельного приложения проще когда все в одном месте и ты точно знаешь какой там стандарт.

Третья проблема это отсутствие встроенной проверки. Чтобы проверить реальное выделение порта или дать нагрузку, приходится устанавливать сторонние решения, это очень долго особенно когда ты разворачиваешь десятки серверов.

Как устроен Slyber TURN Server

Я убрал внешние конфиги и скрипты обвязки, перенеся всю логику внутрь бинарника и установщика.

Работа с сетью и ядром Linux

При запуске сервер сам делает STUN запрос и узнает свой публичный IPv4 адрес. Чтобы распределить нагрузку по всем ядрам процессора, процесс смотрит значение NumCPU и открывает соответствующее количество независимых UDP сокетов на порту 3478 с системным флагом SO_REUSEPORT. Ядро Linux само распределяет входящие пакеты по очередям разных сокетов без блокировок между потоками.

Во время установки и старта буферы чтения и записи сокетов net.core.rmem_max и net.core.wmem_max автоматически увеличиваются до 8 МБ. Это убирает потери UDP пакетов при всплесках трафика. 

Встроенный HTTP API для выдачи временных токенов

Чтобы не писать генерацию паролей на бэкенде приложения, я встроил в бинарник HTTP сервер с эндпоинтом /api/turn-credentials. Он генерирует локальные HMAC токены менее чем за миллисекунду. Эндпоинт закрыт проверкой заголовка Origin с учетом поддоменов, списком разрешенных IP и ограничением частоты запросов.

На фронтенде получение доступов и подключение к WebRTC выглядит так:

const res = await fetch("https://turn.example.com/api/turn-credentials?user_id=user_42");

const turn = await res.json();

const pc = new RTCPeerConnection({
  iceServers: [{
    urls: turn.uris,
    username: turn.username,
    credential: turn.password
  }]
});

Очистка подвисших мобильных сессий и ограничение скорости

На сервере под релей выделяется диапазон портов от 49152 до 65535, всего 16384 порта. Когда пользователь на телефоне переключается с домашнего WiFi на мобильную сеть LTE, его IP адрес меняется. Клиент сразу создает новую аллокацию на сервере, а старый сокет остается висеть до конца стандартного таймаута и занимает порт.

Поэтому при запросе токена передается параметр user_id. Сервер группирует сессии по этому идентификатору. Когда тот же пользователь подключается с новой сети, его старые неактивные сокеты принудительно закрываются через 5 секунд и освобождают порты.

Для ограничения скорости на каждую сессию можно задать лимит MAX_KBPS_PER_SESSION. Ограничитель работает по алгоритму Token Bucket на атомарных операциях sync/atomic без использования мьютексов.

Фильтрация SSRF и поддержка TURN Hairpinning

Внутри релея по умолчанию включен фильтр адресов. Он блокирует пересылку пакетов на адреса облачных метаданных 169.254.0.0/16 и fd00:ec2::254/128, петлевые интерфейсы и приватные подсети. Также отсекаются запросы, когда браузер пытается отправить через TURN свои локальные адреса.

При этом сохранена работа механизма TURN Hairpinning. Если два клиента находятся за NAT и подключены к одному и тому же серверу slyber_turn, они общаются друг с другом через внешний IP этого сервера. Фильтр распознает собственный внешний адрес на релейных портах и пересылает пакеты между клиентами внутри памяти.

Установка в одну команду и встроенные тесты

Для запуска на чистом сервере нужна только одна команда

curl -fsSL https://raw.githubusercontent.com/slyber-app/slyber-turn-server/main/install.sh | sudo bash

Если нужно сразу указать свой домен, порт для HTTP API или лимит скорости на сессию, параметры передаются через переменные окружения:

curl -fsSL https://raw.githubusercontent.com/slyber-app/slyber-turn-server/main/install.sh | \
  sudo REALM="turn.example.com" \
       PUBLIC_IP="auto" \
       HTTP_PORT=":8080" \
       MAX_KBPS_PER_SESSION="2000" \
       bash

Установщик определяет архитектуру процессора, проверяет контрольную сумму SHA256SUMS, настраивает сетевые буферы в sysctl, открывает порты в ufw или firewalld, создает конфиг /opt/slyber_turn/.env, регистрирует службу в systemd и запускает проверку. Вам не придется в ручную все настраивать ввели одну команду и все автоматически настраивается.

В сам бинарник встроены две консольные команды slyber_turn doctor и slyber_turn bench. Первая вызывается автоматически после установки, проверяет доступность по STUN и делает реальную тестовую аллокацию порта:

[OK] Configuration valid (realm: turn.example.com, relay port pool: 49152-65535, capacity: 16384 sessions)
[OK] HTTP API protection active (origins: 1, require_secret: false)
[OK] STUN check passed in 12ms: PUBLIC_IP (203.0.113.50) matches external IP
[OK] HTTP API (:8080/healthz) responded normally (200 OK)
[OK] TURN Allocate succeeded in 390µs (allocated relay address: 203.0.113.50:50124)

Вторая команда нужна для нагрузочного тестирования прямо с сервера:

sudo slyber_turn bench -clients 20 -duration 5s

Она поднимает 20 клиентских соединений, выделяет порты, гонит через них поток UDP пакетов и выводит задержку RTT, процент потерь и джиттер по формуле RFC 3550.

Для мониторинга в продакшене есть эндпоинт /metrics в формате Prometheus, суточная статистика /api/node-stats с данными по пулу портов и лог событий /opt/slyber_turn/events.jsonl.

Спецификация и команды управления собраны на странице проекта Slyber TURN Server. Документацию можно почитать тут https://slyber.com/docs/slyber-turn-server. 

Сервер полностью бесплатный.

Если эта публикация вас вдохновила и вы хотите поддержать автора — не стесняйтесь нажать на кнопку

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.