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 при этом тишина.
108 lines
6.8 KiB
Plaintext
108 lines
6.8 KiB
Plaintext
# 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
|