SIRINVIDEO Документация администратора и интегратора На сайт 2026.08

Порты и сеть

Какой слушатель за что отвечает, что открывать в межсетевом экране, как работать за обратным прокси и какие UDP-порты нужны WebRTC и RTSP.

Сервер открывает ровно те порты, которые перечислены в конфигурации. Отдельного порта у API, панели управления, метрик и плеера нет — всё это едет по HTTP-слушателю вместе с медиа.

Слушатели#

Директива Протокол По умолчанию Что обслуживает
http TCP 8080 HLS, LL-HLS, DASH, MSE-WS, HTTP-TS, превью, плеер, REST API, панель, /metrics, ответчик ACME
https TCP 0 (выключен) то же самое поверх TLS
rtsp TCP 8554 раздача по RTSP
rtsps TCP 0 (выключен) раздача по RTSP поверх TLS
rtmp TCP 0 (выключен) приём публикации и раздача по RTMP
rtmps TCP 0 (выключен) то же поверх TLS
webrtc UDP 0 (выключен) медиа WebRTC: просмотр (WHEP) и публикация (WHIP)
http    8080;
https   8443;
rtsp    8554;
rtsps   8555;
rtmp    1935;
rtmps   1936;
webrtc  40000 public_ip=203.0.113.10;

Правила проверки, все они срабатывают при разборе файла:

  • http и rtsp обязательны и не могут быть нулевымиhttp_port and rtsp_port must be non-zero;
  • они должны различаться — http_port and rtsp_port must differ (both 8080);
  • все ненулевые порты попарно различны — https and rtsps both use port 8443 — listener ports must be distinct;
  • значение больше 65535 не проходит разбор.

0 означает «слушатель выключен» для всех портов, кроме http и rtsp.

Отдельного порта у API и панели нет

Директивы api, admin или metrics_port не существует. /api/v1, /admin/, /metrics и <поток>/embed.html обслуживаются тем же слушателем httphttps), что и видео. Если вы хотите закрыть управление от публики — разграничивайте это на межсетевом экране или обратном прокси по пути URL, а не портом.

Слушатели принимают только IPv4 и только на всех интерфейсах

Все TCP-слушатели открываются на 0.0.0.0. Директивы для выбора интерфейса (bind, listen, address) не существует. Ограничить доступ конкретным интерфейсом можно только средствами операционной системы: правилами межсетевого экрана либо IPAddressAllow в юните systemd.

Что открывать в межсетевом экране#

Минимум — просмотр в браузере#

Направление Порт Зачем
Входящий TCP 8080 (или 443 через прокси) HLS, MSE-WS, DASH, плеер, API
Исходящий TCP 554 до камер приём RTSP

Этого достаточно: HLS, LL-HLS, DASH, MSE-WS, превью и панель живут на одном TCP-порту.

Добавления по мере включения возможностей#

Возможность Что открыть
TLS на самом сервере входящий TCP 443 (или ваш https)
Выпуск сертификата по ACME входящий TCP 80 — обязательно, см. ниже
Раздача по RTSP входящий TCP 8554
Раздача по RTSP через UDP входящий TCP 8554 + эфемерный диапазон UDP, см. ниже
Приём публикации по RTMP входящий TCP 1935
WebRTC входящий и исходящий UDP на одном порту webrtc
Приём по HLS, DASH, HTTP-TS исходящий TCP 80/443 до источника
Приём по UDP или multicast входящий UDP на порту из URL источника, плюс IGMP до маршрутизатора
Копирование архива в S3 исходящий TCP 443 до адреса хранилища
Кластер входящий и исходящий TCP и UDP на порту из peer <имя> <адрес>
Без настроенной авторизации порт RTMP открыт

Приём публикации авторизуется, но только когда настроен auth_backend. Пока он не настроен, поток пишет любой, кто дотянулся до порта, — как и всё остальное на таком узле.

У RTMP нет заголовков, поэтому удостоверение едет в строке запроса: rtmp://media.example.com/live/поток?token=…. Отказ приходит публикатору как NetStream.Publish.Denied. Проверка выполняется ДО захвата потока, поэтому неавторизованный publisher не может занять его и запереть законного.

Порт rtmp всё равно разумно держать во внутреннем сегменте: сетевая граница дешевле разбора неудачных попыток. См. Авторизация публикации и Приём публикации.

Порт 80 и выпуск сертификатов#

Ответчик ACME HTTP-01 обслуживается слушателем http, но удостоверяющий центр всегда обращается на порт 80. Это несовпадение — самая частая причина, по которой сертификат не выпускается.

Работают оба варианта:

# Вариант А: сервер сам слушает 80.
http  80;
https 443;
# Вариант Б: сервер на 8080, а внешний 80 пробрасывается на него
# правилом DNAT межсетевого экрана.
http  8080;
https 443;
# Проброс внешнего 80 на 8080. Первые две строки создают таблицу и цепочку,
# поэтому набор выполняется на чистой системе целиком.
sudo nft add table ip hastreamer
sudo nft add chain ip hastreamer prerouting '{ type nat hook prerouting priority dstnat; }'
sudo nft add rule  ip hastreamer prerouting tcp dport 80 redirect to :8080

# Проверка: правило появилось в списке.
sudo nft list chain ip hastreamer prerouting
table ip hastreamer {
	chain prerouting {
		type nat hook prerouting priority dstnat; policy accept;
		tcp dport 80 redirect to :8080
	}
}
Правило DNAT не переживает перезагрузку само

Команды nft add меняют только работающий набор правил. Чтобы правило вернулось после перезагрузки, внесите его в постоянный набор правил вашей системы.

Предпосылки выпуска, все обязательны:

  1. настроен хотя бы один TLS-слушатель (https, rtsps или rtmps ненулевой) — иначе задача выпуска не запускается вовсе;
  2. есть блок certificate <имя> { hosts …; acme; } с конкретным именем узла — подстановочные имена по HTTP-01 невозможны;
  3. удостоверяющий центр достаёт http://<имя>/.well-known/acme-challenge/<токен> на порту 80;
  4. разрешён исходящий HTTPS до адреса из acme_directory.
Перенаправление на HTTPS не мешает выпуску — но только в правильном порядке

Когда https настроен, сервер отвечает 307 на любой открытый HTTP-запрос, перенаправляя его на HTTPS. Запросы ACME-испытания из этого правила исключены и всегда отдаются в открытом виде. Если же перенаправление делает ваш обратный прокси — исключите путь /.well-known/acme-challenge/ из его правила, иначе выпуск сертификата не состоится.

Подробности выпуска и обновления — TLS и сертификаты.

Работа за обратным прокси#

Типовая схема: прокси терминирует TLS на 443 и проксирует на http сервера. Тогда https в конфигурации сервера остаётся нулевым, и перенаправление на HTTPS сервер не делает — этим занимается прокси.

Проброс адреса клиента — обязателен#

Сервер верит заголовкам Forwarded, X-Forwarded-For и X-Real-IP только если непосредственный TCP-собеседник перечислен в trusted_proxies. По умолчанию список пуст, то есть заголовки пересылки не принимаются никогда — прямой клиент не может подделать свой адрес.

trusted_proxies 10.0.0.0/8 192.168.0.0/16 ::1;
Параметр Тип и допустимые значения По умолчанию Применение
trusted_proxies список IP-адресов и подсетей CIDR; голый адрес считается /32 или /128. Директиву можно повторять — значения накапливаются [] (пусто) горячее

Порядок разбора при доверенном собеседнике: Forwarded: for=X-Forwarded-ForX-Real-IP; доверенные узлы срезаются справа по цепочке.

Без trusted_proxies все клиенты выглядят как один

Если вы поставили обратный прокси и не заполнили trusted_proxies, сервер видит адрес прокси для каждого зрителя. Ломается сразу восемь вещей:

  • привязка токена администратора к IP (admin_ip_bind);
  • задержка при переборе пароля — счётчик становится общим на всех, один злоумышленник блокирует вход всем;
  • привязка билета сессии к IP (session_keys { bind_ip });
  • проверка полей ip и net в токенах просмотра;
  • ключ ограничения частоты отказов авторизации медиа;
  • поле client_ip в списке сессий;
  • поле адреса в журнале аудита;
  • географическая и сетевая диагностика по журналам.

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

Адрес клиента доходит до сервера

Откройте плеер потока с рабочего места и посмотрите список сессий:

curl -sS "https://media.example.com/api/v1/sessions" \
  -H "Authorization: Bearer $TOKEN"

В поле client_ip должен быть адрес вашего рабочего места, а не адрес прокси. Если там адрес прокси — либо прокси не ставит заголовок, либо его адрес не попал в trusted_proxies.

Что должен уметь прокси#

Требование Почему
Передавать X-Forwarded-For или Forwarded иначе см. предыдущий блок
Пропускать апгрейд до WebSocket на /<поток>/mse.ws иначе не работает раздача MSE-WS
Не буферизовать ответы HTTP-TS и поток событий SSE (/api/v1/events) отдаются без указания длины и закрываются по разрыву; буферизация превращает их в зависший запрос
Не менять и не отбрасывать заголовок Range перемотка архива и прямая загрузка файлов VoD работают на диапазонах и отвечают 206
Пропускать Authorization это единственный способ передать учётные данные для /metrics
Не кэшировать ответы с Cache-Control: no-store так помечены превью, плейлисты архива и потоки с включённой защитой от встраивания
Не перенаправлять /.well-known/acme-challenge/ иначе не выпускается сертификат
Сегменты кэшируются, плейлисты — нет

Инициализационные сегменты и медиасегменты живого потока помечены как неизменяемые и пригодны для кэширования на прокси и в сети доставки. Плейлисты — нет. Исключение: если у потока задан allowed_referers, его сегменты понижаются до no-store и кэширование для этого потока отключается полностью. Защита от встраивания и кэширование в сети доставки несовместимы.

CORS#

Если панель или плеер открываются с другого домена, ограничьте список источников:

allow_origins https://console.example.com https://ops.example.com;
Параметр Тип и допустимые значения По умолчанию Применение
allow_origins список источников; директиву можно повторять — значения накапливаются ["*"]любой источник горячее

Совпадение точное, без подстановок и суффиксов. Источник не из списка не получает заголовка CORS вообще. Предварительный запрос OPTIONS сервер отвечает сам: 204, Allow-Methods: GET, HEAD, OPTIONS, POST, DELETE, Allow-Headers: Range, Content-Type, Authorization, Max-Age: 86400.

Ответ /metrics и ответчик ACME заголовков CORS не отдают намеренно.

UDP для WebRTC#

webrtc 40000 public_ip=203.0.113.10;
Параметр Тип и допустимые значения По умолчанию Применение
webrtc <порт> u16; 0 = выключено 0 рестарт
public_ip=<адрес> литерал IPv4; пусто = определить по маршруту по умолчанию пусто рестарт

Нужен ровно один UDP-порт. Сервер работает в режиме ICE-lite и объявляет один-единственный кандидат — свой адрес и этот порт. Диапазона портов нет, каждое рабочее ядро открывает тот же самый порт через SO_REUSEPORT. Медиа идёт по нему в обе стороны.

Правило межсетевого экрана — одно:

# Разрешить входящий UDP на порт WebRTC. Цепочка `inet filter input` есть в
# стандартном наборе правил; если её нет — создайте её так же, как выше.
sudo nft add rule inet filter input udp dport 40000 accept
За NAT обязательно задайте public_ip=

Без public_ip= сервер объявляет адрес, определённый по маршруту по умолчанию. На машине за NAT или в облаке это внутренний адрес — браузер получит кандидата, до которого не дотянется, и соединение не установится. Диагностический признак: страница плеера открывается, а видео не появляется; в отладочной панели плеера видно, что проверки ICE не проходят. Укажите внешний адрес явно и перезапустите службу.

WebRTC — единственный протокол, играющий звук G.711 в браузере

Если камера отдаёт G.711, ни MSE-WS, ни HLS не воспроизведут её звук — это ограничение браузера. WebRTC его играет. Обратное тоже верно: WebRTC не передаёт AAC. См. Протоколы раздачи.

UDP для RTSP#

RTSP умеет два транспорта, и настраиваются они разными директивами — их часто путают.

Директива Область Что задаёт
source_transport глобальная как сервер забирает видео с камеры
rtsp_transports у потока что разрешено запросить клиенту, который смотрит по RTSP

Раздача по RTSP через UDP#

Когда клиент запрашивает RTP/AVP;unicast;client_port=…, сервер занимает пару соседних UDP-портов из эфемерного диапазона ядра: RTP на P, RTCP на P+1. Настраиваемого диапазона нет — директивы для него не существует.

Практические следствия:

  • при строгих правилах для входящего UDP откройте эфемерный диапазон (sysctl net.ipv4.ip_local_port_range), либо запретите UDP-раздачу;
  • если свободной пары не нашлось (сервер делает 8 попыток), клиент получает честный ответ 461 Unsupported Transport, а счётчик отказов виден в /api/v1/system;
  • межсетевые экраны с отслеживанием состояния обычно пропускают эти пакеты сами, так как сессия открывается по управляющему TCP-соединению.

Самое простое решение для закрытых сетей — оставить только чередующийся TCP:

stream cam1 {
  input rtsp://admin:пароль@10.0.0.10:554/Streaming/Channels/101;
  rtsp_transports tcp;      # клиенту доступен только TCP, UDP отклоняется
}
Параметр Тип и допустимые значения По умолчанию Применение
rtsp_transports both | tcp | udp both горячее
rtp_max_payload u16, полезная нагрузка RTP в байтах 1200 рестарт

1200 подобрано так, чтобы пакет проходил через VPN без фрагментации. Внутри одной сети с MTU 1500 значение можно поднять примерно до 1460.

rtsp_transports — параметр потока: его изменение пересоздаёт этот один поток, зрители остальных не затрагиваются. rtp_max_payload — глобальный и требует перезапуска службы. Разбор классов изменений — Применение изменений.

Приём с камеры через UDP#

source_transport udp-then-tcp;
Параметр Тип и допустимые значения По умолчанию Применение
source_transport tcp | udp | udp-then-tcp tcp рестарт

При udp и udp-then-tcp сервер тоже занимает соседние пары портов из эфемерного диапазона и сообщает их камере в client_port=. Соединение инициирует сервер, поэтому межсетевой экран с отслеживанием состояния пропускает ответный поток без отдельного правила.

По умолчанию — TCP, и это правильный выбор

Чередующийся TCP использует одно соединение, проходит через NAT и межсетевые экраны без настройки и не теряет пакеты. UDP имеет смысл только там, где камера или сеть заметно лучше себя ведут на нём. Значение udp-then-tcp пробует UDP и при отказе 461 переходит на TCP для всей сессии, не смешивая транспорты.

Четыре тюнинговых параметра UDP относятся только к приёму по RTSP

udp_ingest_rcvbuf, udp_ingest_shards, udp_ingest_pool_slots и udp_pull_rate настраивают маршрутизатор RTSP-over-UDP. На приём udp:// и multicast:// они не влияют вообще — там размер буфера и очередь заданы в коде. При source_transport tcp эти четыре параметра не делают ничего.

UDP для приёма MPEG-TS и multicast#

Порт задаётся не директивой, а самим URL источника:

stream headend {
  input udp://@239.1.1.1:1234?iface=10.0.0.5;
}
  • адрес должен быть литералом IPv4 — ни DNS-имени, ни IPv6;
  • ?iface=<IPv4> закрепляет интерфейс присоединения к группе;
  • ?source=<IPv4> выполняет присоединение к конкретному источнику (IGMPv3, только Linux); значение обязано быть одноадресным, иначе конфигурация отвергается;
  • на межсетевом экране нужен входящий UDP на этом порту, а на маршрутизаторе — разрешённый IGMP.

Подробности — RTSP, HLS, DASH, MPEG-TS.

Порты кластера#

cluster {
  key "общий-секрет-кластера";
  peer alpha 10.0.0.10:9000 { public https://alpha.example.com; zone dc1; }
  peer beta  10.0.0.11:9000 { public https://beta.example.com;  zone dc2; }
}

Один порт на узел (9000 в примере) обслуживает и UDP — обмен сведениями о живости, и TCP — канал между узлами. Открывайте оба протокола между узлами кластера.

Зрителей между узлами сервер перенаправляет, а не проксирует: клиент получает 302 (для WHIP и WHEP — 307) на адрес из public. Поэтому адреса из public должны быть доступны зрителям, а не только узлам кластера.

Итоговая карта портов типовой установки#

Зрители  ── TCP 443 ─────────► обратный прокси ── TCP 8080 ──► сервер
Зрители  ── UDP 40000 ────────────────────────────────────────► сервер   (WebRTC)
Зрители  ── TCP 8554 ─────────────────────────────────────────► сервер   (RTSP)
Сервер   ── TCP 554 ──────────────────────────────────────────► камеры
Сервер   ── TCP 443 ──────────────────────────────────────────► S3, ACME
Наблюдение ── TCP 8080 /metrics ──────────────────────────────► сервер
Слушатели действительно подняты
sudo ss -tulnp | grep hastreamer
tcp   LISTEN 0 4096 0.0.0.0:8080  0.0.0.0:*  users:(("hastreamer",pid=1234,fd=12))
tcp   LISTEN 0 4096 0.0.0.0:8554  0.0.0.0:*  users:(("hastreamer",pid=1234,fd=13))
udp   UNCONN 0 0    0.0.0.0:40000 0.0.0.0:*  users:(("hastreamer",pid=1234,fd=14))

Каждый настроенный порт должен присутствовать. Строк на один порт может быть несколько — по числу рабочих ядер: слушатели открываются с SO_REUSEPORT.

Что дальше#