Files
vidconf/deploy/livekit/livekit.yaml.template
Max Ronzhin e018837a1d fix(livekit): анонсировать клиентам внешний TURN — relay не работал совсем
coturn поднимался, был healthy и слушал 3478 — но клиенты о нём никогда не
узнавали: встроенный TURN выключен (`turn.enabled: false`), внешний в
конфигурации не объявлен, фронтенд `iceServers` не задаёт. За всё время
работы сервера в логах coturn нет ни одной аллокации.

Следствие: у участников из сетей, где прямое UDP-соединение не проходит,
не было relay-фолбэка вообще — только прямой UDP и TCP 7881. На
нагрузочном тесте 28.07 все разрывы `PEER_CONNECTION_DISCONNECTED`
пришлись на внешних участников и ни одного — на офисных.

Добавлена секция `rtc.turn_servers` (UDP и TCP на 3478). Эти серверы
только анонсируются клиенту в списке ICE — сам SFU через них не ходит
(см. iceServersForParticipant в LiveKit). Credentials генерируются по
механизму TURN REST API из общего `TURN_STATIC_AUTH_SECRET`, поэтому
`render-templates.sh` теперь подставляет его и `TURN_EXTERNAL_IP` также в
конфигурацию LiveKit.

TLS (5349/443) намеренно не анонсируется: сертификаты в coturn не
смонтированы, а неработающий `turns:` заставил бы клиента ждать таймаута
перед переходом к рабочему кандидату. Что нужно для его включения —
описано в разделе 8 руководства.

Там же исправлено умолчание в правилах ufw: помимо 3478 нужен диапазон
relay-аллокаций `49160:49200/udp`. Без него TURN отвечает на запросы, но
релей не работает, причём в логах coturn при этом тишина.
2026-07-29 00:17:19 +03:00

108 lines
6.8 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# LiveKit SFU. Верифицировано по официальной документации
# (github.com/livekit/livekit config-sample.yaml + configuration.md).
# Реальный API key/secret — из .env (LIVEKIT_API_KEY / LIVEKIT_API_SECRET);
# этот файл намеренно не содержит `keys:` — ключи передаются через
# LIVEKIT_KEYS (см. docker-compose.yml, формат "key: secret").
#
# LiveKit НЕ читает переменные окружения внутри своего YAML-конфига (в
# отличие от `keys:`, которые подаются отдельно через LIVEKIT_KEYS) —
# статические поля (use_external_ip/node_ip/webhook.api_key) рендерятся
# из этого шаблона в livekit.yaml скриптом deploy/render-templates.sh
# (envsubst) ПЕРЕД `docker compose up`. Не редактируйте livekit.yaml
# напрямую — правки затрутся при следующем рендере.
port: 7880
rtc:
tcp_port: 7881
# Диапазон сужен для dev (см. комментарий в docker-compose.yml); в проде
# расширить и синхронизировать с пробросом портов.
port_range_start: 54000
port_range_end: 54100
# use_external_ip: false + node_ip=127.0.0.1 — режим для локальной
# разработки (Docker Desktop): use_external_ip=true определяет публичный
# IP через STUN, что в контейнере на macOS даёт недостижимый изнутри хоста
# внутренний IP (172.18.x.x) — DTLS-хендшейк по data-каналам не проходит
# ("dtls timeout" в логах). node_ip=127.0.0.1 работает, потому что порты
# 7881/tcp и 54000-54100/udp проброшены на loopback хоста, а браузер-клиент
# запускается на том же хосте.
# В проде (LIVEKIT_USE_EXTERNAL_IP=true, LIVEKIT_NODE_IP=<внешний IP/домен
# сервера> в .env) клиенты снаружи хоста подключаются по этому адресу —
# сервер не должен быть за NAT без проброса портов 1:1.
use_external_ip: ${LIVEKIT_USE_EXTERNAL_IP}
node_ip: ${LIVEKIT_NODE_IP}
# Внешний TURN (сервис coturn, профиль `media`) — АНОНС КЛИЕНТАМ.
# Сам SFU через эти серверы не ходит: LiveKit лишь отдаёт их браузеру в
# списке ICE-серверов при подключении (см. iceServersForParticipant в
# pkg/service/roommanager.go), а клиент уже решает, нужен ли ему relay.
#
# Зачем. До 28.07.2026 coturn работал, но КЛИЕНТЫ О НЁМ НЕ ЗНАЛИ: секция
# `turn` ниже выключена (встроенный TURN не поднимаем), внешний в конфиге
# объявлен не был, а фронтенд `iceServers` не задаёт. За всё время работы
# в логах coturn — ноль ALLOCATE. Итог: у клиентов из сетей с жёстким NAT
# не было relay-фолбэка вообще, только прямой UDP и TCP 7881. Именно так
# объясняются `PEER_CONNECTION_DISCONNECTED` на нагрузочном тесте — все
# у внешних участников, ни одного у офисных (.forcc/LOAD-FINDINGS.md,
# причина C).
#
# `secret` обязан совпадать с `static-auth-secret` в turnserver.conf —
# оба рендерятся из одного TURN_STATIC_AUTH_SECRET (deploy/render-templates.sh).
# Логин/пароль LiveKit генерирует сам по механизму TURN REST API.
#
# UDP и TCP на 3478 — оба порта уже открыты в ufw. TLS (5349) намеренно не
# объявляем: в turnserver.conf сертификаты не смонтированы, и анонс
# неработающего `turns:` заставил бы клиента впустую ждать таймаута,
# прежде чем перейти к рабочему кандидату.
turn_servers:
- host: ${TURN_EXTERNAL_IP}
port: 3478
protocol: udp
secret: ${TURN_STATIC_AUTH_SECRET}
ttl: 14400
- host: ${TURN_EXTERNAL_IP}
port: 3478
protocol: tcp
secret: ${TURN_STATIC_AUTH_SECRET}
ttl: 14400
# Redis обязателен для сервиса egress (см. deploy/egress/) — он использует
# его как pub/sub и key-value хранилище состояния запущенных записей;
# без него egress не может получать room/track-события от LiveKit
# (проверено по официальной документации livekit/egress, раздел "Running
# locally"). LiveKit сам по себе тоже использует redis для координации
# между узлами кластера (здесь один узел, но сервис оставлен включённым).
# password подставляется рендером (deploy/render-templates.sh) из
# REDIS_PASSWORD в .env — redis в docker-compose.yml запускается с
# --requirepass, без пароля LiveKit не подключится (см.
# .forcc/deploy/SESSION2-FINDINGS.md про redis без пароля).
redis:
address: redis:6379
password: ${REDIS_PASSWORD}
# TURN обслуживает отдельный сервис coturn (профиль `media`, deploy/coturn).
# При публичной экспозиции LiveKit разместите coturn/TURN-TLS на 443 и
# держите эту секцию отключённой, чтобы не поднимать два TURN-сервера.
turn:
enabled: false
# Webhook-приёмник backend'а: события room_started/participant_joined/
# participant_left/room_finished подписываются ключом api_key, который
# должен совпадать с одним из ключей в LIVEKIT_KEYS (см. выше и
# docker-compose.yml) — берём тот же LIVEKIT_API_KEY из .env.
webhook:
api_key: ${LIVEKIT_API_KEY}
urls:
- http://backend:8000/api/v1/livekit/webhook
# Если backend запускается на хосте (uvicorn вне docker-compose, а
# LiveKit — внутри), используйте вместо этого:
# - http://host.docker.internal:8000/api/v1/livekit/webhook
logging:
level: info
json: false
# Prometheus metrics (scraped by the monitoring profile).
prometheus:
port: 6789