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; # явное выключение
Так работают: acme (в certificate), admin_ip_bind (в auth), bind_ip (в session_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 собирает всю работу всех потоков на одно ядро. Это самая дорогая ошибка настройки:
внешне сервер работает, но упирается в одно ядро при свободных остальных. Если вы не уверены —
оставьте 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 — параметр
потока, ограничивающий транспорт раздачи зрителю по 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 держится подключённым после ухода
последнего зрителя. Это же значение служит окном ожидания при подъёме — намеренно, чтобы поток не
«мигал».
Значение поднимается до 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 растягивает холодный старт большого числа источников в равномерный
разгон вместо одномоментного залпа.
На приём 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)
Запись при обновлении будет прочитана наполовину. Именно от этого защищает промежуточная копия:
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.
Как только вы добавляете 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 и говорит об этом при запуске.
Перед паролем администратора стоит задержка и таблица отсрочек, перед статическим токеном — ничего. Единственная защита — энтропия самого токена. Минимум 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
Опция 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.
Поток со строкой 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 суток) |
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>/<имя>, не найдёт приёмника и получит отказ.
Каждая цель публикации должна быть настроенным блоком 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 { 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; # подключать при первом зрителе }
Что дальше#
- Применение изменений — что действует сразу, а что ждёт перезапуска.
- Порты и сеть — что открывать и как работать за обратным прокси.
- Приём видео: обзор — какой источник выбрать под задачу.
- Модель доступа — как устроены два механизма доступа.