feat(coturn): TURN over TLS на 5349 — сертификаты, монтирование, анонс клиентам
coturn (nobody:nogroup, без root-фазы в entrypoint) не может сам прочитать приватный ключ Let's Encrypt — coturn-certs-init (по образцу recordings-init/llm-models-init) копирует fullchain/privkey в отдельный volume под правами 644, не трогая права на ключ на хосте. TURN_TLS_HOST в .env — единственный переключатель фичи: пусто (dev-дефолт) вырезает TLS-блоки из turnserver.conf и rtc.turn_servers целиком (маркеры BEGIN/END-TLS-* в *.template, render-templates.sh), непустое значение включает оба сразу — TLS без анонса LiveKit клиентам не имеет смысла (история 0.0.14: coturn работал healthy, но клиенты о нём не знали, и не было ни одной аллокации). Значение обязано быть доменом сертификата, а не IP — иначе браузер не пройдёт TLS-валидацию по имени хоста для turns:. TLS-запись в rtc.turn_servers стоит последней в списке (фолбэк дороже прямого UDP/TCP).
This commit is contained in:
@@ -432,6 +432,49 @@ services:
|
||||
profiles: ["media"]
|
||||
logging: *default-logging
|
||||
|
||||
# Образ coturn/coturn — Dockerfile прописывает `USER nobody:nogroup`, и это
|
||||
# НЕ runtime-привилегия, которую можно сбросить: Docker exec'ает entrypoint
|
||||
# сразу от этого uid, root-фазы внутри контейнера нет вовсе (в отличие от
|
||||
# официального образа nginx, который стартует entrypoint от root и только
|
||||
# nginx-воркеры позже понижают права по директиве в конфиге — см.
|
||||
# deploy/nginx/docker-entrypoint-certs.sh). Значит coturn физически не может
|
||||
# сам прочитать приватный ключ Let's Encrypt (root:root, обычно 0600) —
|
||||
# никакой volume-опцией это не обойти, не ослабляя права на ключ на хосте.
|
||||
#
|
||||
# Решение — по образцу уже существующего `recordings-init`/`llm-models-init`
|
||||
# в этом файле: отдельный init-контейнер (busybox, дефолтный root) читает
|
||||
# /etc/letsencrypt (той же ro-монтировкой, что и у nginx) и копирует
|
||||
# fullchain/privkey в СВОЙ volume под правами 644 — это копия, а не
|
||||
# оригинал, оригинальный ключ на хосте прав не меняет. Копия достаточно
|
||||
# открыта, чтобы её прочитал nobody:nogroup внутри coturn.
|
||||
#
|
||||
# Если /etc/letsencrypt/live/<домен> не существует (dev, нет реальных
|
||||
# сертификатов) — команда ниже просто ничего не копирует и завершается
|
||||
# успешно; coturn стартует как раньше, без TLS (см. TURN_TLS_HOST в
|
||||
# render-templates.sh — вторая половина того же переключателя).
|
||||
coturn-certs-init:
|
||||
image: busybox:1.36
|
||||
command: >
|
||||
sh -c '
|
||||
SRC="/etc/letsencrypt/live/$$NGINX_CERT_NAME";
|
||||
if [ -f "$$SRC/fullchain.pem" ] && [ -f "$$SRC/privkey.pem" ]; then
|
||||
cp "$$SRC/fullchain.pem" /certs/cert.pem;
|
||||
cp "$$SRC/privkey.pem" /certs/key.pem;
|
||||
chmod 644 /certs/cert.pem /certs/key.pem;
|
||||
echo "[coturn-certs-init] сертификат $$SRC скопирован в volume coturn-certs";
|
||||
else
|
||||
echo "[coturn-certs-init] $$SRC не найден — TLS для coturn не настроен (норма для dev без TURN_TLS_HOST)";
|
||||
fi
|
||||
'
|
||||
environment:
|
||||
NGINX_CERT_NAME: ${NGINX_CERT_NAME:?NGINX_CERT_NAME не задан в .env}
|
||||
volumes:
|
||||
- /etc/letsencrypt:/etc/letsencrypt:ro
|
||||
- coturn-certs:/certs
|
||||
restart: "no"
|
||||
profiles: ["media"]
|
||||
logging: *default-logging
|
||||
|
||||
coturn:
|
||||
image: coturn/coturn:latest
|
||||
restart: unless-stopped
|
||||
@@ -444,6 +487,10 @@ services:
|
||||
# (deploy/render-templates.sh, вызывается install.sh).
|
||||
volumes:
|
||||
- ./coturn/turnserver.conf:/etc/coturn/turnserver.conf:ro
|
||||
- coturn-certs:/etc/coturn/certs:ro
|
||||
depends_on:
|
||||
coturn-certs-init:
|
||||
condition: service_completed_successfully
|
||||
network_mode: host
|
||||
# Образ coturn/coturn — минимальный (debian-slim), в нём нет pgrep/ps/nc/
|
||||
# curl/wget, поэтому проверка процесса по имени не работает
|
||||
@@ -887,6 +934,11 @@ volumes:
|
||||
# Загруженные пользователями файлы (аватары) — общий том между
|
||||
# backend (запись при загрузке) и nginx (раздача статики, `location /media/`).
|
||||
media:
|
||||
# Копия fullchain/privkey Let's Encrypt под правами 644 для coturn
|
||||
# (nobody:nogroup) — источник в /etc/letsencrypt не трогаем, см.
|
||||
# coturn-certs-init выше. Обновляется при каждом перезапуске
|
||||
# coturn-certs-init (deploy-hook certbot делает это при продлении).
|
||||
coturn-certs:
|
||||
# Метрики Prometheus (профиль `monitoring`) — переживают пересоздание контейнера.
|
||||
prometheus_data:
|
||||
# Дашборды/настройки Grafana (профиль `monitoring`) — переживают пересоздание.
|
||||
|
||||
Reference in New Issue
Block a user