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

hastreamer.conf — все директивы

Полный справочник конфигурации: грамматика, все 110 директив с типами, значениями по умолчанию, классом применения и дословными сообщениями об ошибках.

Вся настройка сервера — один текстовый файл. Путь к нему передаётся первым аргументом командной строки; служба hastreamer.service передаёт /etc/hastreamer/hastreamer.conf.

Справочник описывает все 110 форм директив, которые принимает разбор: 37 на верхнем уровне и 73 вложенных. Директивы, которой здесь нет, не существует — разбор отвергнет её с номером строки.

Грамматика#

Инструкции#

Инструкция — это имя [аргументы] ; либо имя [аргументы] { вложенные инструкции }.

http 8080;                        # скаляр: одно значение, точка с запятой обязательна
trusted_proxies 10.0.0.0/8 ::1;   # несколько значений в одной строке
acme;                             # голый флаг: без значения, означает «включено»

tls {                             # блок: фигурные скобки вместо точки с запятой
  cert /etc/ssl/media.crt;
  key  /etc/ssl/media.key;
}

storage archive /srv/dvr {        # именованный блок: имя, аргументы и тело
  segment_secs 1800;
}
  • Каждая директива со значением заканчивается на ;. Пропуск — ошибка: line 2: directive "rtsp" not terminated with ';'.
  • Блок заменяет точку с запятой. Не пишите tls { … };.
  • Незакрытая скобка даёт unexpected end of file inside a block (missing '}'), лишняя — line 3: unmatched '}'.

Комментарии#

# начинает комментарий до конца строки. Блочных комментариев нет. # внутри кавычек — данные, а не комментарий.

Комментарии сохраняются байт в байт, когда конфигурацию переписывает API или панель управления.

Значения, кавычки и экранирование#

Слово без кавычек заканчивается на пробеле, ;, {, } или #. Чтобы включить любой из этих символов — берите значение в кавычки:

admin_password "па роль; с # символами";
input "rtsp://admin:p@ss@10.0.0.10:554/Streaming/Channels/101";
Последовательность внутри кавычек Результат
\" символ "
\\ символ \
любая другая \x сохраняется как есть, вместе с обратной косой
перевод строки допустим; так хранятся многострочные ключи PEM

Незакрытая кавычка — line 4: unterminated quote.

Типы#

Разбор определяет тип скаляра сам, по порядку: целое число → дробное число → on/true = да, off/false = нет → строка.

Там, где число было бы ошибкой (URL, адреса почты, секреты, ключи S3, поля auth_backend, storage … s3 и principal), значение принудительно считается строкой — секрет из одних цифр не исказится. Кавычки при этом всегда безопасны.

Голые флаги#

Любая логическая директива понимает обе формы — это общее правило, а не особенность отдельных директив:

on_demand;        # голый флаг → включено
on_demand on;     # явное включение
on_demand off;    # явное выключение

Так работают: acmecertificate), admin_ip_bindauth), bind_ipsession_keys) и флаги потока http_ts, hls_ts, audio_only_playlist, disabled, on_demand.

Порядок и повторы#

  • Порядок директив свободен.
  • Механизма включения файлов нет. Один файл, и только он. Директивы include не существует.
  • Повторённый скаляр молча выигрывает последним. http 8080; а затем http 9443; даёт 9443 без предупреждения. Не полагайтесь на это — держите по одной строке на директиву.
  • Три директивы накапливаются, а не перезаписываются: trusted_proxies, allow_origins, public_paths. Очистить накопленный список можно только удалив строки.
  • Повторённые input внутри одного stream образуют цепочку резервирования по порядку.
  • Повторённые permission внутри principal образуют список прав.
  • Повторённые блоки certificate, storage, stream, principal, template, vod добавляют записи; совпадение имён — ошибка проверки.

Тело { } обязательно для tls, auth, auth_backend, session_keys, cluster, principal, certificate, stream и template:

line 3: `tls` needs a { block }
line 3: `stream` takes a name and a { block }

У storage и vod тело необязательно — storage local /var/lib/hastreamer/dvr; полностью корректная однострочная запись.

Неизвестные директивы#

Отвергаются при разборе, с номером строки, на любом уровне вложенности:

line 3: unknown directive "cors"
line 3: unknown stream directive "frobnicate"
line 3: unknown auth directive "admin_pass"
line 4: unknown tls directive "bogus"
Опечатка никогда не деградирует мягко

Неизвестная директива, неверное значение перечислимого типа, выход за диапазон — всё это жёсткие ошибки, останавливающие запуск. «Молча проигнорировать и взять умолчание» сервер не умеет принципиально. Всегда проверяйте файл hastreamer --validate до systemctl restart.

Что происходит с неверным файлом#

Когда Поведение
При запуске ошибка печатается, процесс завершается кодом 1. Restart=on-failure поднимает его каждые 2 секунды — получается цикл. Читайте journalctl -u hastreamer -n 50
При systemctl reload config reload REJECTED: <ошибки> (running config unchanged)работающий сервер продолжает раздавать видео. Это безопасный способ проверить правку
Несколько ошибок сразу проверка накапливает все и печатает через ; — файл чинится за один проход

Формат определяется по расширению файла: .toml — TOML, .json — JSON, всё остальное, включая .conf, — эта текстовая грамматика. Все три попадают в одну модель и одну проверку. Не называйте конфигурацию hastreamer.json.

Глобальные директивы#

Слушатели#

Параметр Тип и допустимые значения По умолчанию Применение
http u16, не может быть нулём 8080 рестарт
https u16; 0 = выключено 0 рестарт
rtsp u16, не может быть нулём 8554 рестарт
rtsps u16; 0 = выключено 0 рестарт
rtmp u16; 0 = выключено 0 рестарт
rtmps u16; 0 = выключено 0 рестарт
webrtc u16 и необязательное public_ip=<IPv4>; 0 = выключено 0 рестарт
http   8080;
https  8443;
rtsp   8554;
rtsps  8555;
rtmp   1935;
rtmps  1936;
webrtc 40000 public_ip=203.0.113.10;

Слушатель http обслуживает всё сразу: HLS, LL-HLS, DASH, MSE-WS, HTTP-TS, превью, плеер, /api/v1, /admin/, /metrics и ответчик ACME. Отдельной директивы для API или панели нет. https даёт ту же поверхность поверх TLS.

Проверки: 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.

Типичная ошибка — задать webrtc без порта: line 3: 'webrtc' needs a UDP port. Подробности о том, что и куда открывать, — Порты и сеть.

Рабочие ядра и задержка#

Параметр Тип и допустимые значения По умолчанию Применение
cores целое ≥ 0; 0 = все производительные ядра 0 рестарт
low_latency on | off on рестарт
log_level debug | info | warn | error info горячее
cores 0;
low_latency on;
log_level info;

cores 0 означает «все производительные ядра»: на гибридных процессорах берутся только производительные ядра, энергоэффективные пропускаются; на однородных — все. Положительное значение закрепляет ровно столько ядер, начиная с самых быстрых.

cores 1 — это не «одно ядро на поток»

cores 1 собирает всю работу всех потоков на одно ядро. Это самая дорогая ошибка настройки: внешне сервер работает, но упирается в одно ядро при свободных остальных. Если вы не уверены — оставьте 0.

low_latency off глобально отключает тела плейлистов LL-HLS и блокирующее обновление: маршруты .ll.m3u8 начинают отдавать 404, а мастер-плейлист откатывается к обычному. Настройки на уровне потока у этого параметра нет.

Низкая задержка выбирается адресом, а не параметром запроса

Обычный HLS — master.m3u8, низкозадержечный — master.ll.m3u8. Два протокола, два адреса. Параметра запроса для отключения LL не существует.

log_level задаёт минимальную тяжесть записи, попадающей в кольцевой журнал. Уже записанные строки остаются, пока их не вытеснит кольцо. Отладочная диагностика в выпускаемых сборках отсутствует физически, поэтому debug там не добавит новых строк. Неверное значение:

unknown variant `trace`, expected one of `debug`, `info`, `warn`, `error`

Приём и раздача#

Параметр Тип и допустимые значения По умолчанию Применение
source_transport tcp | udp | udp-then-tcp tcp рестарт
rtsp_frame_source cmaf | raw_au cmaf рестарт
rtp_max_payload u16, байты полезной нагрузки RTP 1200 рестарт
max_sessions целое ≥ 0; 0 = без ограничения 0 рестарт

source_transport — как сервер забирает видео с камеры. Значение udp-then-tcp пробует UDP и при отказе 461 переходит на TCP для всей сессии, никогда не смешивая транспорты. Настройки на уровне потока нет.

source_transport и rtsp_transports — разные вещи

source_transport — глобальный транспорт приёма с камеры. rtsp_transports — параметр потока, ограничивающий транспорт раздачи зрителю по RTSP. Это самая частая путаница в этом разделе.

rtsp_frame_source raw_au переключает раздачу RTSP на кольцо отдельных единиц доступа вместо кольца фрагментов fMP4 — задержка ниже, стоимость выше.

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

max_sessions — общий предел одновременных сессий раздачи по всем протоколам сразу, проверяемый после авторизации. Не на поток и не на учётную запись. Запрос RTSP SETUP сверх предела отклоняется кодом 453 Not Enough Bandwidth.

Ошибки: source_transport must be "tcp", "udp", or "udp-then-tcp" (got "quic") · rtsp_frame_source must be "cmaf" or "raw_au" (got "foo").

Тайминги#

Параметр Тип и допустимые значения По умолчанию Применение
media_timeout целое, секунды; 0 = выключено 20 рестарт
on_demand_grace целое, секунды 30 рестарт
dvr_cleanup_secs целое, секунды 600 рестарт

media_timeout — сторожевой таймер зависшего медиа. Ловит самый неприятный отказ камеры: сокет жив и здоров, а кадры идти перестали. По истечении срока источник принудительно переподключается. Отсчёт ведётся по монотонным часам, поэтому перевод системного времени его не запускает. Таймер не взводится для потоков, принимающих публикацию, — иначе он выбивал бы живого, но молчащего издателя.

on_demand_grace — сколько поток с флагом on_demand держится подключённым после ухода последнего зрителя. Это же значение служит окном ожидания при подъёме — намеренно, чтобы поток не «мигал».

on_demand_grace 0 означает 1 секунду, а не «выключено»

Значение поднимается до 1000 мс. Обратите внимание на асимметрию: media_timeout 0 действительно выключает сторожевой таймер, а on_demand_grace 0 — нет.

dvr_cleanup_secs — период обслуживания архива: применение сроков хранения, вытеснение по заполненности диска, выгрузка в S3, удаление пустых каталогов. Работа идёт на отдельном служебном потоке, вне обслуживающих ядер.

Тюнинг приёма по UDP#

Параметр Тип и допустимые значения По умолчанию Применение
udp_ingest_rcvbuf целое, байты; 64 KiB … 1 GiB 16777216 (16 МиБ) рестарт
udp_ingest_shards целое 1…16 2 рестарт
udp_ingest_pool_slots целое 64…4096 1024 рестарт
udp_pull_rate целое 0…100000, попыток в секунду; 0 = без ограничения 100 рестарт

Ошибки диапазона дословны: udp_ingest_rcvbuf 1024 out of range (64 KiB ..= 1 GiB) · udp_ingest_shards 99 out of range (1..=16) · udp_ingest_pool_slots 10 out of range (64..=4096) · udp_pull_rate 999999 out of range (0..=100000).

Значение udp_ingest_rcvbuf дополнительно ограничивается ядром по net.core.rmem_max. udp_ingest_pool_slots — число слотов кольца буферов на ядро, по 64 КиБ каждый, выделяются по мере надобности; повышайте его первым, если в /api/v1/system растёт счётчик перевзводов по ENOBUFS. udp_pull_rate растягивает холодный старт большого числа источников в равномерный разгон вместо одномоментного залпа.

Эти четыре параметра настраивают только приём по RTSP-over-UDP

На приём udp:// и multicast:// они не влияют: там размер буфера и глубина очереди заданы в коде и не настраиваются. При source_transport tcp (значение по умолчанию) все четыре бездействуют.

Край HTTP#

Параметр Тип и допустимые значения По умолчанию Применение
trusted_proxies список IP и подсетей CIDR; повторы накапливаются [] горячее
allow_origins список источников; повторы накапливаются ["*"] — любой горячее
public_paths список путей, литералы или шаблоны с *; повторы накапливаются [] горячее
trusted_proxies 10.0.0.0/8 192.168.0.0/16 ::1;
allow_origins   https://console.example.com;
public_paths    lobby lobby/*;

trusted_proxies — единственный способ получить настоящий адрес зрителя за обратным прокси. Пустой список означает, что заголовкам пересылки не верят никогда. Подробности и последствия — Порты и сеть.

allow_origins — список источников CORS. Совпадение точное, без суффиксов и подстановок.

public_paths освобождает путь потока (не путь URL) от авторизации просмотра при любом типе auth_backend. Проверяется первым, до любой работы с учётными данными.

certificate { } и TLS#

tls { } — сертификат по умолчанию#

Параметр Тип и допустимые значения По умолчанию Применение
cert путь к цепочке PEM; абсолютный либо относительно хранилища TLS пусто горячее
key путь к закрытому ключу PEM пусто горячее
sync_from путь к исходному PEM, из которого поддерживается копия пусто горячее
self_signed_names список имён для самоподписанной пары ["localhost"] горячее
tls {
  cert /etc/hastreamer/tls/media.crt.pem;
  key  /etc/hastreamer/tls/media.key.pem;
  self_signed_names media.example.com localhost;
}

Это личность сервера по умолчанию — она отдаётся, когда ни один блок certificate не подошёл по имени SNI или когда клиент имени не прислал.

Если cert и key пусты, сервер один раз генерирует самоподписанную пару и сохраняет её, так что отпечаток не меняется между перезапусками, и его можно закреплять на клиенте. self_signed_names задаёт имена для этой пары и используется только в этом случае.

sync_from поддерживает cert и key копией указанного исходного PEM: файл проверяется, переносится атомарным переименованием, и живой резолвер TLS переключается без перезапуска и без разрыва соединений. Пригодно, когда сертификат обновляет другой процесс на той же машине.

Проверка:

tls: `sync_from` requires `cert` and `key` (the node-owned snapshot paths the source is copied into)
Никогда не указывайте cert прямо на файл, который обновляет чужой процесс

Запись при обновлении будет прочитана наполовину. Именно от этого защищает промежуточная копия: sync_from — исходник, cert/key — собственные файлы сервера.

certificate <имя> { } — сертификаты SNI#

Параметр Тип и допустимые значения По умолчанию Применение
hosts список имён: точное имя или *.суффикс из одной метки [], обязателен горячее
cert путь к цепочке PEM пусто горячее
key путь к закрытому ключу PEM пусто горячее
ca путь к промежуточным сертификатам пусто горячее
acme голый флаг или on | off off горячее
certificate public {
  hosts media.example.com *.cam.example.com;
  cert  certs/public/fullchain.pem;
  key   certs/public/privkey.pem;
  ca    certs/public/chain.pem;
}

certificate auto {
  hosts media.example.com;
  acme;                      # выпуск и обновление автоматически
}

Блоков может быть сколько угодно, имена должны быть уникальны. Проверки, дословно:

a certificate needs a non-empty name
duplicate certificate name "public"
certificate "public": needs at least one `hosts` entry (else it is never selected)
certificate "public": `cert` and `key` paths are required (or set `acme` to auto-issue)
certificate "auto": `acme` and explicit `cert`/`key` are mutually exclusive
certificate "auto": ACME/HTTP-01 cannot issue the wildcard "*.media.example.com" — give a concrete hostname
certificate "public": bad wildcard host "*.*.example.com" (use `*.suffix`, one label)

При включённом acme формулировка первой ошибки другая:

certificate "auto": needs at least one `hosts` entry (ACME issues for these hostnames)

Глобальные параметры ACME#

Параметр Тип и допустимые значения По умолчанию Применение
acme_directory строка URL https://acme-v02.api.letsencrypt.org/directory рестарт
acme_contact строка, адрес электронной почты пусто рестарт

Оба значения принудительно считаются строками, поэтому числовое на вид значение не исказится.

Выпуск идёт по HTTP-01. Задача на нулевом ядре проверяет состояние каждые 60 секунд, читая живую конфигурацию, — добавленный блок certificate { acme; } подхватывается без перезапуска. Обновление начинается за 30 суток до истечения, так что у неудачных попыток есть недели запаса. При отказе интервал растёт от 15 минут удвоением до потолка в 6 часов, чтобы не превысить ограничения удостоверяющего центра. Выпущенная пара подставляется в резолвер SNI на лету, без перезапуска и без потери зрителей; если что-то пошло не так — продолжает работать прежняя личность.

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

Требования к выпуску и разбор частых отказов — Порты и сеть и TLS и сертификаты.

storage { } — хранилища архива#

Хранилище объявляется один раз, а потоки ссылаются на него по имени в строке dvr. Имена уникальны: duplicate storage name "local". Тело { } необязательно.

Дисковое хранилище#

storage local /var/lib/hastreamer/dvr {
  segment_secs     900;
  evict_at_percent 90;
  identity         3f2a9c14-1c0e-4f7b-9d21-8a6f0b4e5c77;
}
Параметр Тип и допустимые значения По умолчанию Применение
segment_secs только 900, 1800 или 3600 900 горячее
evict_at_percent u8, процент занятости; 0 = клапан выключен 90 горячее
identity UUID в каноническом виде, строчными, не нулевой пусто горячее

Два позиционных аргумента обязательны — имя и путь (или литерал s3):

line 3: `storage` takes <name> <path>, or <name> s3 { … }

segment_secs — цель ротации файла записи. Множество значений закрытое: storage "local": segment_secs must be one of 900, 1800 or 3600 seconds. Меньшие значения взрывают число файлов и объектов, большие откладывают финализацию и восстановление после сбоя.

evict_at_percent — предохранительный клапан под индивидуальными сроками хранения. Когда файловая система переходит порог занятости, обслуживающий проход удаляет самые старые записи по всем потокам этого хранилища, пока занятость не опустится на 2 процентных пункта ниже порога. Диапазон не проверяется: значение больше 100 просто никогда не сработает — это молчаливый способ отключить клапан.

Правка хранилища перезапускает все пишущие в него потоки

Изменение path, segment_secs или identity пересоздаёт каждый поток, который в это хранилище записывает; изменение реквизитов учётной записи S3 — каждый поток, который туда копирует. Это ожидаемо: хранилище — часть отпечатка потока. См. Применение изменений.

identity на обычном сервере необязателен. Если он задан, сервер пишет на том файл-метку .hastreamer-storage-identity и строго её проверяет — это то, что отличает «архивный диск не смонтирован» от «архив пуст». При неудачной проверке хранилище отмечается неисправным в GET /api/v1/storages, запись прекращается, а чтение архива отвечает 503 вместо вводящего в заблуждение 404.

identity обязателен для копирования в S3

Как только вы добавляете copy= в строку dvr, дисковое хранилище обязано иметь канонический, не нулевой, записанный строчными буквами UUID: stream "cam": copy= requires local storage "local" to have a canonical non-nil lowercase UUID identity. Идентификатор служит корнем пространства имён объектов, поэтому задним числом его менять нельзя.

Учётная запись S3#

storage coldtier s3 {
  endpoint   s3.eu-central-1.example.com;
  region     eu-central-1;
  access_key ВАШ_КЛЮЧ;
  secret_key ВАШ_СЕКРЕТ;
  addressing vhost;
  tls_verify system;
}
Параметр Тип и допустимые значения По умолчанию Применение
endpoint хост[:порт] без схемы, обязателен горячее
region строка us-east-1 горячее
access_key строка, обязателен горячее
secret_key строка, обязателен горячее
addressing vhost | path vhost горячее
tls_verify пусто | system | insecure | pin:<64 hex> | ca:<путь> system горячее

Учётная запись S3 — это только реквизиты, а не цель записи. Корзина указывается в строке dvr конкретного потока, а не здесь. Записать поток напрямую в S3 нельзя: S3 — всегда холодная копия того, что уже записано на диск.

Проверки, дословно:

s3 storage "coldtier": endpoint is a bare host[:port] — the s3://|s3s:// scheme lives on the stream's copy= reference
s3 storage "coldtier": addressing must be "vhost" or "path" (got "weird")
s3 storage "coldtier": bad tls_verify "bogus": invalid verify spec "bogus": expected "", system, insecure, pin:<64-hex> or ca:<path>
missing field `endpoint`

addressing path нужен объектным хранилищам, не поддерживающим адресацию по поддомену. У записи S3 нет ни path, ни identity — это параметры дискового хранилища.

Подробности — Хранилища и S3.

auth { } и авторизация#

Сервер имеет два независимых механизма доступа, и их постоянно путают:

Механизм Настраивается Защищает Не защищает
Управление auth { } /api/v1/* и /metrics видео, оболочку панели, плеер
Просмотр auth_backend { } и связанные с ним всю раздачу медиа, архив и VoD /api/v1/*

Пароль администратора не защищает ваше видео. Отсутствие auth_backend означает, что любой, кто дотянулся до порта, смотрит любой поток. См. Модель доступа.

auth { } — доступ к API и панели#

auth {
  admin_password  "смените-этот-пароль";
  session_secret  "общий-секрет-подписи";
  admin_ip_bind;
  api_read_token  "ro-9f2c4b7e1a8d05c3";
  api_write_token "rw-3d81e6a094fb27ce";
}
Параметр Тип и допустимые значения По умолчанию Применение
admin_password строка; пустая запрещена не задан горячее
admin_ip_bind голый флаг или on | off off горячее
session_secret строка; пустая запрещена не задан горячее
api_read_token строка, не короче 16 символов не задан горячее
api_write_token строка, не короче 16 символов не задан горячее

admin_password — пароль входа в панель и в API. Если директива не задана, API открыт: сервер запускается и громко предупреждает об этом в журнале, но не отказывается работать. Пустое значение — ошибка: auth.admin_password must not be empty (omit it entirely to disable auth).

Вход: POST /api/v1/auth/login с телом {"password":"…"} возвращает токен на 12 часов (срок не настраивается). Дальше — заголовок Authorization: Bearer <токен>. Защита от перебора двухслойная: задержка 600 мс перед каждым неверным ответом плюс общесерверная таблица отсрочек по адресу; открытие новых соединений не помогает.

admin_ip_bind привязывает выданный токен к адресу, с которого выполнен вход.

session_secret — ключ подписи токенов администратора и корень, из которого выводится ключ билетов сессии просмотра. Если он не задан, при каждом запуске генерируется случайный: токены и билеты не переживают перезапуск. Задайте его — тогда переживут. Пустое значение — auth.session_secret must not be empty (omit it for an auto-generated per-boot secret).

api_read_token и api_write_token — статические токены для интеграций, которым нельзя выдавать пароль администратора:

Токен Что открывает
api_read_token безопасные методы (GET, HEAD, OPTIONS) в /api/v1/* и /metrics. Изменять не может ничего. Не может прочитать GET /api/v1/config — этот ответ содержит пароль администратора и токен записи в открытом виде
api_write_token любые методы в /api/v1/* и /metrics; строгое надмножество токена чтения

Ни один из них не является учётными данными для просмотра: сыграть поток по такому токену нельзя. Оба предъявляются заголовком Authorization.

Проверки:

auth.api_read_token must be at least 16 characters (use a generated random token)
auth.api_write_token must not be empty (omit it entirely to leave that tier unconfigured)
auth.api_read_token and auth.api_write_token must differ (an equal pair silently grants write to the read token)
Метрики требуют учётных данных

GET /metrics не открыт. Тело ответа перечисляет каждый поток, его состояние и число зрителей — это та же информация, ради которой закрыт /api/v1, поэтому она требует тех же учётных данных: статического токена API либо сессии администратора. Только заголовок Authorization, параметр ?token= здесь не принимается — долгоживущий токен в адресе оседает в журналах каждого прокси на пути. Узел без настроенных учётных данных отвечает 401 и говорит об этом при запуске.

Токены API не ограничиваются по частоте

Перед паролем администратора стоит задержка и таблица отсрочек, перед статическим токеном — ничего. Единственная защита — энтропия самого токена. Минимум 16 символов, рекомендация — 32 случайных. Одинаковые токены чтения и записи отвергаются: классификатор проверяет запись первой, и вы бы молча выдали право записи там, где хотели только чтение.

auth_backend { } — авторизация просмотра#

auth_backend {
  type        jwks;
  url         https://idp.example.com/.well-known/jwks.json;
  issuer      my-issuer;
  audience    my-audience;
  perms_claim grants;
  secret      "общий-секрет-hs256";
  revoked_url https://idp.example.com/revoked;
  tls_verify  system;
}
Параметр Тип и допустимые значения По умолчанию Применение
type none | internal | hs256 | jwks | http пусто горячее
url строка URL пусто горячее
issuer строка; проверяется, если задана пусто горячее
audience строка; проверяется, если задана пусто горячее
perms_claim строка — имя поля токена с массивом прав grants горячее
secret строка, общий секрет HS256 пусто горячее
revoked_url строка URL списка отзыва пусто горячее
tls_verify пусто | system | insecure system горячее
Значение type Что делает
none то же, что отсутствие блока: раздача открыта
internal сверяет с блоками principal в этом же файле, полностью офлайн
hs256 компактный JWS на общем секрете; алгоритм закреплён, токены none, RS* и ES* отвергаются
jwks RS256 и ES256 против набора ключей, забираемого по url и кэшируемого
http ограниченный запрос к url, только при установлении сессии, никогда не на каждый сегмент
Отсутствие блока означает открытую раздачу

Это намеренное и задокументированное поведение: нет auth_backend — нет проверки, любой запрос медиа проходит. Во всех остальных случаях отказ — закрытый: пустой кэш ключей запрещает, ошибка или таймаут внешнего запроса запрещают, действительная подпись без подходящего права даёт 403.

Проверки:

auth_backend.type must be one of none|internal|hs256|jwks|http (got "magic")
auth_backend type "jwks" requires a url
auth_backend type "hs256" requires a secret
auth_backend type "internal" needs at least one `principal` block

Подробности о полях токенов и способах их предъявления — Авторизация просмотра.

principal <имя> { } — встроенные учётные записи#

Имеет смысл только при auth_backend { type internal; }.

principal alice {
  pass  "пароль";
  token "статический-токен";
  permission read     live/*;
  permission read     live/cam1 hls;
  permission playback label=org-a label=tag-7 hls;
}

principal any { permission read lobby/*; }   # анонимный доступ
Параметр Тип и допустимые значения По умолчанию Применение
pass строка, пароль для базовой аутентификации не задан горячее
token строка, статический токен; сосуществует с pass не задан горячее
permission <действие> [<путь>] [label=<метка>…] [<протокол>…]; повторяемая горячее

Имя блока — это имя пользователя; principal any — анонимный доступ без пароля.

Разбор строки permission: первый токен — действие; следующий считается путём, если он не начинается с label=; каждое оставшееся label= — метка, всё прочее — протокол. Путь и метки комбинируются по ИЛИ.

  • Действия: read (живое видео), publish (публикация), playback (архив и VoD), api, manage, metrics. Первые три привязаны к пути, остальные — нет.
  • Протоколы: hls, dash, mse-ws, http-ts, rtsp, whep, whip, api. Пусто — все. LL-HLS покрывается значением hls.
  • Пустой путь — все потоки; путь с * — шаблон, в котором * покрывает и символ /.
  • Не более 40 меток, каждая от 1 до 64 байт, без пробелов и управляющих символов.

Проверки:

principal #0: needs a `token`, or a `user`+`pass`, or `user any`
principal #0 permission #0: a media permission needs a non-empty path or at least one label (use path `*` explicitly for all streams)

pass и token скрываются в ответах API и в отладочном выводе.

session_keys { } — билеты сессии просмотра#

session_keys {
  ttl             3600;
  vod_session_ttl 86400;
  bind_ip         off;
  secret          "отдельный-секрет-подписи-билетов";
}
Параметр Тип и допустимые значения По умолчанию Применение
ttl целое, секунды; диапазон не проверяется 3600 горячее
vod_session_ttl целое, секунды, 300…604800 86400 (24 часа) горячее
bind_ip голый флаг или on | off off горячее
secret строка пусто горячее

Билет — обязательный второй уровень авторизации, когда проверка просмотра включена. Дорогая проверка права выполняется один раз, при установлении сессии по плейлисту; дальше сервер вплетает компактный билет в каждый дочерний адрес, и каждый запрос сегмента проверяется одной быстрой операцией — без разбора токена и без обращений наружу. Повторный опрос плейлиста продлевает билет, не запуская проверку права заново.

Порядок выбора ключа подписи: session_keys { secret }auth { session_secret } → случайный ключ на время работы процесса. Изменение действующего корня аннулирует все выданные билеты.

bind_ip привязывает билет к адресу зрителя. Выключайте его, если зрители переходят между мобильной сетью и Wi-Fi или сидят за пулом NAT.

Проверка: session_keys.vod_session_ttl must be 300..=604800 seconds; got 60.

Устаревшая директива gate отвергается: unknown session_keys directive "gate".

stream { } — поток#

Один блок — один поток. Имя блока служит путём в адресе: поток cam1 доступен как https://media.example.com/cam1/master.m3u8 и rtsp://media.example.com:8554/cam1. Путь может содержать /, тогда вложенность сохраняется.

stream cam1 {
  input rtsp://admin:пароль@10.0.0.10:554/Streaming/Channels/101;
  dvr   local 24h 40G;
  labels org-a tag-7;
}

Пути обязаны быть непустыми и уникальными: duplicate stream path "cam1" · a stream has an empty path.

Изменение потока перезапускает только его

Отпечатком потока служит весь блок, кроме labels. Правка любого параметра пересоздаёт этот один поток — остальные сохраняют аптайм и сессии. Правка только labels не перезапускает ничего. Правка storage, на который поток пишет, перезапускает все пишущие туда потоки. Полная картина — Применение изменений.

Источник#

Параметр Тип и допустимые значения По умолчанию Применение
input input <url> [source_timeout=N];повторяемая, порядок задаёт приоритет обязателен горячее
tls_verify пусто | system | insecure | pin:<64 hex> | ca:<путь> system горячее
on_demand голый флаг или on | off off горячее
disabled голый флаг или on | off off горячее

Принимаемые схемы:

Схема Что делает
rtsp://, rtsps:// забор с камеры или кодировщика
http://, https:// забор по HTTP с автоопределением: HLS, DASH либо непрерывный MPEG-TS
udp://, multicast:// MPEG-TS по UDP, одноадресно или групповой рассылкой
rtmp://, rtmps:// исходящее подключение к источнику RTMP
file:// локальный файл MP4, зацикленный и выданный как живой поток
publish:// ожидание публикации извне (RTMP или WHIP)
demo:// встроенный синтетический источник для проверки установки
copy://<поток> повторная выдача уже принятого потока под другим именем, без второго приёма. Такой поток не записывается в архив и наследует метки исходного
stream cam1 {
  input rtsp://cam-primary.example.com/main;   # основной
  input rtsp://cam-backup.example.com/main;    # первый резерв
  input demo://;                               # последний рубеж
}

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

Ошибки строки input:

line 3: `input` needs a url
line 3: `input` option "foo" must be key=value
line 3: unknown `input` option "bar"
stream "cam": needs `source` or a non-empty `sources` chain
source_timeout= разбирается, но не действует

Опция input <url> source_timeout=N; принимается разбором и сохраняется в модели, однако ни один приёмник её не читает. Считайте её зарезервированной. Нужное вам поведение задаёт глобальный media_timeout.

tls_verify — политика доверия к сертификату источника для rtsps://, https:// и rtmps://. Проверяется при загрузке конфигурации, поэтому опечатка — жёсткая ошибка, а не молчаливый откат к системным корням: stream "cam": bad tls_verify "pinn:aa": invalid verify spec "pinn:aa": expected "", system, insecure, pin:<64-hex> or ca:<path>.

on_demand не подключает источник при запуске: поток ждёт первого зрителя и снова отключается, когда зрителей и запросов медиа нет дольше on_demand_grace.

on_demand молча игнорируется у записывающего потока

Поток со строкой dvr подключается всегда, а в журнал пишется on_demand ignored — recording pins demand (always pulls/accepts). Причина проста: «записывать, только когда смотрят» — это архив с дырами. То же касается источника publish://.

disabled — остановка по решению оператора: поток не запускается и убирается из работы, но его настройки полностью сохраняются в файле для последующего пуска.

Требование к publish://: должен быть настроен слушатель rtmp/rtmps либо порт webrtc:

stream "cam": a publish:// source needs an `rtmp`/`rtmps` listener (RTMP publish) or a `webrtc_udp_port` (WHIP)

Сегментация и задержка#

Параметр Тип и допустимые значения По умолчанию Применение
segments_count целое; 0 = значение по умолчанию 5 горячее
segment_seconds дробное, секунды; 0 = значение по умолчанию 2 горячее
prepush дробное, секунды; 0 = зависит от протокола 0 горячее

segments_count — сколько сегментов держится в живом окне манифеста HLS и DASH. Ещё один сегмент сверх окна остаётся в памяти для запоздавших клиентов.

segment_seconds — целевая длительность сегмента. Реальная лежит в промежутке от целевой до целевой плюс длина группы кадров: сегмент всегда закрывается по ключевому кадру.

prepush — насколько позади живого края начинает новый зритель. Больше — устойчивее к плохой связи, меньше — ниже задержка. Для минимальной задержки правильнее использовать LL-HLS или MSE-WS и уменьшить интервал ключевых кадров на камере.

Протоколы раздачи потока#

Параметр Тип и допустимые значения По умолчанию Применение
http_ts голый флаг или on | off off горячее
hls_ts голый флаг или on | off off горячее
audio_only_playlist голый флаг или on | off off горячее
multicast_out <группа>:<порт> и параметры ttl=, iface=, loopback=, tos= пусто горячее
rtsp_transports both | tcp | udp both горячее
caps список меток протоколов для плеера [] = автоматически горячее

HLS-fMP4, LL-HLS, DASH, MSE-WS, RTSP, превью и WebRTC (если задан порт) доступны без каких-либо директив. Перечисленные выше нужны только для дополнительных вариантов.

http_ts включает непрерывный MPEG-TS по адресу /<поток>/stream.ts; hls_ts — вариант плейлиста HLS с сегментами .ts. Оба используют одно общее кольцо MPEG-TS: любой из флагов включает мультиплексор.

audio_only_playlist добавляет в мастер-плейлист HLS вариант только со звуком — это требование магазина приложений для доставки на iOS.

multicast_out отправляет MPEG-TS в групповую рассылку. Обе записи равнозначны:

multicast_out 239.1.1.1:5000 ttl=4 iface=10.0.0.5 loopback=1 tos=184;
multicast_out 239.1.1.1:5000?ttl=4&iface=10.0.0.5&loopback=1&tos=184;
Параметр адреса Тип По умолчанию
ttl u8 4
loopback логический (0/false — выключить) включено
iface литерал IPv4 не задан; неразбираемое значение молча игнорируется
tos u8, DSCP не задан

Группа обязана быть литералом IPv4; неизвестные параметры адреса игнорируются. Проверка идёт при загрузке: stream "cam": bad multicast_out "239.1.1.1" (expected <group:port>[?ttl=&iface=&loopback=&tos=]).

Групповая рассылка — постоянный потребитель

Мультиплексор MPEG-TS не выключается, даже если по HTTP-TS никто не подключён. Учитывайте нагрузку.

rtsp_transports ограничивает транспорт, который зритель вправе запросить по RTSP. Клиенту с запрещённым транспортом отвечают 461 Unsupported Transport. Ошибка: stream "cam": rtsp_transports must be "tcp", "udp", or "both" (got "quic").

caps задаёт, какие вкладки протоколов предлагает встроенный плеер:

caps hls mse-ws;    # режим разрешения: только эти
caps -dash;         # режим запрета: всё, кроме этих

Словарь: hls, hls-ll, mse-ws, dash, webrtc, whip, dvr, timeshift, preview. Смешивать режимы нельзя, а разрешить можно только то, что сервер действительно отдаёт:

stream "cam": caps cannot MIX deny (`-x`) and allow (bare) tokens — use one mode
stream "cam": cap "webrtc" not served (not in the derivable set ["hls", "hls-ll", "mse-ws", "dash", "preview"])
stream "cam": unknown cap "foo" (known: hls, hls-ll, mse-ws, dash, webrtc, whip, dvr, timeshift, preview)

Доступ к потоку#

Параметр Тип и допустимые значения По умолчанию Применение
labels список меток, до 40, каждая 1…64 байта, без пробелов [] горячее
allowed_referers список имён узлов; литерал none разрешает отсутствие источника перехода [] = не ограничено горячее

labels — непрозрачные метки авторизации. Право зрителя подходит потоку, если наборы меток пересекаются. Так авторизуют тысячи потоков, не выписывая тысячу правил. Метка, записанная как UUID с дефисами, приводится к 22-символьной форме при загрузке — обе записи взаимозаменяемы. Изменение только labels никогда не перезапускает поток.

Ошибки: stream "cam": at most 40 labels (41 given) · label "…" exceeds 64 bytes · label "…" must not contain whitespace/control chars.

allowed_referers — защита от встраивания на чужих сайтах, а не аутентификация. Совпадение по суффиксу на границе точки: example.com разрешает cdn.example.com и никогда не разрешит evilexample.com. Собственное имя узла разрешено неявно, поэтому встроенный плеер не блокируется. Указывать нужно имена узлов, а не адреса: stream "cam": allowed_referers token "https://media.example.com/x" must be a host, not a URL path.

Защита от встраивания отключает кэширование потока

Как только у потока задан allowed_referers, его сегменты и инициализационный фрагмент понижаются с «неизменяемых» до no-store. Кэширование в браузере и в сети доставки для этого потока перестаёт работать. Совместить одно с другим нельзя.

dvr — запись в архив#

dvr <хранилище> [<срок>] [<объём>] [copy=s3[s]://<корзина>@<учётная-запись>] [<срок>] [<объём>];
dvr local 24h 40G;                                     # 24 часа либо 40 ГиБ — что наступит раньше
dvr fast 2h 3G copy=s3s://cam-archive@coldtier 30d 100G;   # горячее на диске, холодное в S3

Аргументы позиционные и распознаются по форме:

Форма аргумента Как понимается
просто слово имя дискового хранилища
цифры и s/m/h/d/w/mo/y срок хранения
цифры и K/M/G/T объём хранения, двоичные единицы
copy=s3://корзина@учётная-запись или copy=s3s://… ссылка на холодный уровень (s3s — с TLS)
содержит / цель репликации в кластере, <узел>/<том>
mode=async, mode=cross режим репликации в кластере

Порядок среди позиционных аргументов свободен, кроме одного: copy= — водораздел. Всё, что до него, относится к диску; всё, что после, — к архиву в S3.

Суффикс срока Значение
s секунды
m минуты
h часы
d сутки
w недели
mo месяцы (ровно 30 суток)
y годы (ровно 365 суток)
m — это минуты, mo — это месяцы

dvr local 30m хранит тридцать минут видео, а не тридцать месяцев. Эта ошибка уже приводила к реальной потере архива. Если вы имеете в виду месяцы — пишите 30mo.

Единицы объёма двоичные и только заглавными: K, M, G, T. Запись 500g не будет распознана как объём — она будет воспринята как имя хранилища, и вы получите stream "cam": record needs a known local DISK storage (got "500g"); use copy= for an s3 cold tier.

Пустое значение или 0 означают «без ограничения» для любого из двух измерений. Применяются они по очереди: сначала удаляется всё, что старше срока, затем — самое старое из оставшегося, пока сумма превышает объём. Последний завершённый сегмент потока не удаляется никогда, каким бы старым он ни был.

Два простых слова подряд означают, что имя хранилища молча переопределяется последним из них.

Проверки строки dvr, дословно:

stream "cam": record needs a known local DISK storage (got "nosuch"); use copy= for an s3 cold tier
stream "cam": bad dvr copy= "s3x://buck@cold" (expected s3://<bucket>@<name> or s3s://<bucket>@<name>)
stream "cam": copy= target "nope" is not a declared s3 storage
stream "cam": copy= bucket "BUCK" must be [0-9a-z.-] (S3 bucket grammar)
stream "cam": copy= needs a LOCAL retention — `dvr local <time|size> copy=…` — else local media never evicts
stream "cam": copy= requires local storage "local" to have a canonical non-nil lowercase UUID identity
stream "cam": s3 retention time "7d" is shorter than local retention time "14d"; cold retention must be uncapped or cover local retention to prevent delete/re-upload churn

Последнее правило существует, чтобы не возник цикл «удалили локально — загрузили заново»: срок и объём холодного хранения обязаны либо быть неограниченными, либо покрывать локальные.

Подробности — Запись архива.

Кластерные параметры потока#

Параметр Тип и допустимые значения По умолчанию Применение
host список имён узлов [] горячее
restream список имён узлов или * [] = выключено горячее

host перечисляет узлы, которым разрешено принимать этот поток, по порядку приоритета; restream — узлы, которым разрешено его ретранслировать. На одиночном сервере оба не имеют смысла.

Наследование настроек#

Параметр Тип и допустимые значения По умолчанию Применение
template имя блока template не задан горячее
template cam-defaults {
  segment_seconds 2;
  segments_count  6;
  caps hls mse-ws;
}

stream cam1 {
  template cam-defaults;      # берём значения по умолчанию
  input rtsp://10.0.0.10:554/s;
  segments_count 10;          # собственное значение важнее
}

Наследование одноуровневое: шаблон не может ссылаться на шаблон.

template "a": a template cannot inherit another template (one level only)
stream "cam": unknown template "nope"

Не наследуются никогда: имя, prefix и сама ссылка template.

template { } — шаблон настроек#

Блок template <имя> { … } принимает ровно те же вложенные директивы, что и stream, плюс одну собственную.

Параметр Тип и допустимые значения По умолчанию Применение
prefix один непустой сегмент пути, без / не задан горячее

prefix допустим только внутри template; на обычном потоке он отвергается как неизвестное поле. Ошибка:

template "t": publish `prefix` must be a single non-empty path segment (no '/')
Шаблон с prefix не создаёт потоки сам

Издатель, публикующий в несуществующий <prefix>/<имя>, не найдёт приёмника и получит отказ. Каждая цель публикации должна быть настроенным блоком stream.

vod — видео по запросу#

Две разные формы одной директивы.

Библиотека#

vod movies /srv/media/movies {
  segment_duration 6;
}
Параметр Тип и допустимые значения По умолчанию Применение
segment_duration целое, секунды; диапазон не проверяется 6 горячее

Имя библиотеки допускает только символы [A-Za-z0-9._-] и не может быть . или ..; имена уникальны, корень непустой. Библиотек может быть несколько.

vod library name "my/lib" must use only [A-Za-z0-9._-] and cannot be . or ..
duplicate vod library name "movies"
line 3: `vod` takes <name> <root> { … } or a bare `vod { … }` tuning block
Источник file:// требует объявленной библиотеки VoD

Путь источника file:// проверяется по корням объявленных библиотек vod, и проверка закрытая: без единой библиотеки любой file:// отвергается. Это самое неочевидное требование при приёме из файла.

Настройка кэша#

vod {
  index_cache 64;
  index_ttl   300;
}
Параметр Тип и допустимые значения По умолчанию Применение
index_cache целое 1…4096; 0 недопустим 64 горячее
index_ttl целое, секунды, 1…86400 300 горячее

index_cache — предел на ядро, ограничивающий одновременно и число разобранных индексов, и число открытых файловых дескрипторов: проверенный дескриптор хранится вместе с индексом, отдельного параметра для него нет.

vod { index_cache } must be 1..=4096 (0 is not a valid 'unlimited'); got 0
vod { index_ttl } must be 1..=86400 seconds; got 0
line 3: unknown vod tuning directive "foo" (want index_cache/index_ttl)

Подробности — VoD — видео по запросу.

cluster { } — несколько серверов как один#

cluster {
  key "общий-секрет-кластера";
  peer alpha 10.0.0.10:9000 {
    public https://alpha.example.com;
    zone   dc1;
    http 8080;  https 8443;
    rtsp 8554;  rtsps 8555;
    storage archive /srv/dvr { segment_secs 900; }
  }
  peer beta 10.0.0.11:9000 {
    public https://beta.example.com;
    zone   dc2;
  }
}
Изменения cluster не попадают в вердикт перезагрузки

Членство в кластере, канал между узлами и его ключ строятся один раз при запуске процесса. Блока cluster нет в таблице параметров, требующих перезапуска, поэтому systemctl reload о нём ничего не скажет — но и не применит его. Считайте любую правку cluster требующей systemctl restart. Живо пересчитывается только размещение потоков: директивы host и restream внутри блоков stream.

Параметр Тип и допустимые значения По умолчанию Применение
key строка, общий секрет узлов пусто рестарт
peer <имя> <адрес> блок; ровно два аргумента рестарт

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

peer <имя> <адрес> объявляет узел. Адрес — один порт, обслуживающий и обмен сведениями о живости по UDP, и канал между узлами по TCP. Неверное число аргументов — line 3: `peer` takes <name> <addr>.

Внутри peer { }, всё необязательно:

Параметр Тип и допустимые значения По умолчанию Применение
public строка, базовый адрес для перенаправления зрителей пусто = хост из адреса рестарт
zone строка — зона размещения пусто рестарт
http, https, rtsp, rtsps, rtmp, rtmps, webrtc u16; 0 = взять значение верхнего уровня 0 рестарт
storage <имя> <путь> { } блок хранилища этого узла; перекрывает одноимённое хранилище верхнего уровня рестарт

Модель простая: верхний уровень — значения по умолчанию для всех узлов, блок peer — личные отличия конкретного узла. Пустой список peer и есть переключатель «одиночный сервер»: все маршруты /api/v1/cluster* тогда отвечают 404.

Имя узла обязательно и по имени машины не определяется

Сервер находит себя в списке по аргументу --node <имя> или переменной окружения HS_NODE. Конфигурация с блоком cluster без имени не запустится: the config has a cluster section — pass --node <name> (or HS_NODE). Проверка выполняется при запуске, поэтому --validate эту ошибку не покажет.

Кластерный узел, включивший admin_password, обязан задать и общий auth.session_secret — иначе конфигурация отвергается: случайный посекундный секрет не позволит авторизовать потоки соседа.

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

Проверить принятое решение о размещении, ничего не запуская:

hastreamer --explain /etc/hastreamer/hastreamer.conf alpha cam1

Чего в конфигурации нет#

Перечислено, чтобы вы не искали. Каждая из этих строк — ошибка разбора или отсутствующая возможность.

Что Почему
license { … } у лицензирования нет настроек: путь к файлу лицензии, адрес активации и правила заложены в сборку. Строка даёт unknown directive "license". См. Лицензирование
transcode, encode перекодирования в продукте нет ни в каком виде
include механизма включения файлов нет, конфигурация — один файл
api, admin, metrics_port отдельного порта у API, панели и метрик нет — всё на http/https
bind, listen, address адрес привязки не настраивается: все слушатели открываются на 0.0.0.0
${ПЕРЕМЕННАЯ} подстановки переменных окружения нет; секреты пишутся текстом
cctv { … } блок принадлежит другому продукту линейки; здесь он не проходит разбор
параметр запроса для отключения LL-HLS режим выбирается адресом: master.m3u8 либо master.ll.m3u8
настройка длительности части LL-HLS она фиксирована и оператору недоступна
отдельный параметр для числа открытых файлов VoD его задаёт vod { index_cache }

Указатель директив#

Верхний уровень (37). Слушатели: http, https, rtsp, rtsps, rtmp, rtmps, webrtc. Тюнинг: cores, low_latency, log_level, rtsp_frame_source, source_transport, rtp_max_payload, max_sessions, media_timeout, on_demand_grace, dvr_cleanup_secs, udp_ingest_rcvbuf, udp_ingest_shards, udp_ingest_pool_slots, udp_pull_rate. Сертификаты: acme_directory, acme_contact, tls, certificate. Край HTTP: trusted_proxies, allow_origins, public_paths. Доступ: auth, auth_backend, session_keys, principal. Нагрузка: storage, stream, template, vod, cluster.

Вложенные (73).

Блок Вложенные директивы Число
tls { } cert, key, sync_from, self_signed_names 4
certificate <имя> { } hosts, cert, key, ca, acme 5
auth { } admin_password, admin_ip_bind, session_secret, api_read_token, api_write_token 5
auth_backend { } type, url, issuer, audience, perms_claim, secret, revoked_url, tls_verify 8
session_keys { } ttl, vod_session_ttl, bind_ip, secret 4
principal <имя> { } pass, token, permission 3
storage <имя> <путь> { } segment_secs, evict_at_percent, identity 3
storage <имя> s3 { } endpoint, region, access_key, secret_key, addressing, tls_verify 6
stream <путь> { } и template <имя> { } input, segments_count, segment_seconds, prepush, audio_only_playlist, http_ts, hls_ts, multicast_out, disabled, on_demand, tls_verify, rtsp_transports, caps, allowed_referers, labels, dvr, host, restream, template, prefix 20
cluster { } key, peer 2
cluster … peer <имя> <адрес> { } public, zone, http, https, rtsp, rtsps, rtmp, rtmps, webrtc, storage 10
vod <имя> <корень> { } segment_duration 1
vod { } index_cache, index_ttl 2
Всего 73

Полный пример#

# /etc/hastreamer/hastreamer.conf

# ── Слушатели (требуют перезапуска) ──────────────────────────────────────────
http   8080;              # HLS, DASH, MSE-WS, превью, API, панель, метрики, ACME
https  8443;              # то же поверх TLS
rtsp   8554;              # раздача по RTSP
webrtc 40000 public_ip=203.0.113.10;   # за NAT адрес указывать обязательно

# ── Ядра и задержка (требуют перезапуска) ────────────────────────────────────
cores       0;            # 0 = все производительные ядра
low_latency on;           # тела плейлистов LL-HLS
log_level   info;         # применяется горячо

# ── Тайминги приёма (требуют перезапуска) ────────────────────────────────────
source_transport tcp;     # транспорт забора с камеры
media_timeout    20;      # переподключить камеру, если медиа замерло
on_demand_grace  30;      # через сколько парковать поток без зрителей
dvr_cleanup_secs 600;     # период обслуживания архива

# ── TLS (применяется горячо) ─────────────────────────────────────────────────
tls {
  cert /etc/hastreamer/tls/media.crt.pem;
  key  /etc/hastreamer/tls/media.key.pem;
}

certificate public {
  hosts media.example.com;   # только конкретное имя: HTTP-01 не выпускает подстановочные
  acme;                      # внешний порт 80 должен доходить до слушателя http
}
acme_contact ops@example.com;

# ── Край HTTP (применяется горячо) ───────────────────────────────────────────
trusted_proxies 10.0.0.0/8;                   # иначе адрес зрителя = адрес прокси
allow_origins   https://console.example.com;  # по умолчанию разрешены любые источники

# ── Доступ (применяется горячо) ──────────────────────────────────────────────
auth {
  admin_password "смените-этот-пароль";
  session_secret "постоянный-секрет-подписи";   # без него токены не переживут перезапуск
  api_read_token "ro-9f2c4b7e1a8d05c3";   # 16+ символов, не пароль администратора
}

# ── Хранилище архива ─────────────────────────────────────────────────────────
storage local /var/lib/hastreamer/dvr {
  segment_secs     900;     # допустимо только 900, 1800 или 3600
  evict_at_percent 90;      # вытеснять самое старое при заполнении выше 90 %
}

# ── Потоки ───────────────────────────────────────────────────────────────────
template cam-defaults {
  segment_seconds 2;
  segments_count  6;
}

stream cam1 {
  template cam-defaults;
  input rtsp://admin:пароль@10.0.0.10:554/Streaming/Channels/101;   # основной
  input rtsp://admin:пароль@10.0.0.11:554/Streaming/Channels/101;   # резерв
  dvr    local 24h 40G;      # 24 ЧАСА и 40 ГиБ; 24m было бы 24 МИНУТЫ
  labels org-a;              # изменение меток не перезапускает поток
}

stream lobby {
  input demo://?res=1280x720&fps=25&vc=h264&ac=aac;   # синтетический источник
  on_demand;                                          # подключать при первом зрителе
}

Что дальше#