TLS и сертификаты
Включение HTTPS и RTSPS, загрузка своего сертификата, автоматический выпуск по ACME, несколько имён через SNI и разбор типичных ошибок выпуска.
Сервер принимает TLS-соединения сам: отдельный веб-сервер или обратный прокси для HTTPS не нужен. Сертификат можно загрузить свой, получить автоматически по протоколу ACME или оставить самоподписанный — последний создаётся сам и годится только для проверки.
Слушатели TLS#
TLS включается объявлением защищённого слушателя. Без него сертификаты не используются, даже если они настроены.
| Параметр | Тип и допустимые значения | По умолчанию | Применение |
|---|---|---|---|
https |
номер порта, 0 — выключено |
0 |
рестарт |
rtsps |
номер порта, 0 — выключено |
0 |
рестарт |
rtmps |
номер порта, 0 — выключено |
0 |
рестарт |
http 80; # оставьте открытым: на нём отвечает проверка ACME https 443; rtsp 8554; rtsps 8555;
Все порты применяются только при перезапуске службы (systemctl restart hastreamer), а не при
reload. Порты должны различаться между собой, иначе конфигурация отвергается:
invalid config /etc/hastreamer/hastreamer.conf: https and rtsps both use port 8443 — listener ports must be distinct
Порт http — не только «незащищённая версия» панели. На нём отвечает проверка владения именем при
выпуске сертификата ACME, и делает это до любой авторизации. Если вы закрыли http совсем,
автоматический выпуск работать не будет.
Три способа получить сертификат#
| Способ | Когда применять | Что настраивается |
|---|---|---|
| Самоподписанный | стенд, локальная проверка, внутренний контур без доверия к именам | ничего: создаётся автоматически |
| Свой сертификат | есть корпоративный УЦ или купленный сертификат, нужен подстановочный (*.example.com) |
блок certificate с путями к PEM |
| Автовыпуск ACME | публичное имя, доступное из интернета по порту 80 | блок certificate с флагом acme |
Способы сочетаются: одно имя может обслуживаться загруженным сертификатом, другое — выпущенным автоматически.
Самоподписанный сертификат#
Если объявлен защищённый слушатель, но не настроено ни одного сертификата, сервер сам создаёт пару и сохраняет её на диске — отпечаток не меняется при перезапусках, его можно закрепить в клиенте.
https 443; tls { self_signed_names media.example.com localhost; }
| Параметр | Тип и допустимые значения | По умолчанию | Применение |
|---|---|---|---|
cert |
путь к PEM-цепочке; абсолютный или относительно хранилища TLS | "" |
горячее |
key |
путь к PEM-ключу | "" |
горячее |
ca |
путь к промежуточным сертификатам (только в блоке certificate) |
"" |
горячее |
self_signed_names |
список имён для самоподписанной пары | localhost |
горячее |
sync_from |
путь к внешнему PEM-файлу, из которого копировать пару | "" |
горячее |
Блок tls { } задаёт сертификат по умолчанию: он предъявляется, когда клиент не прислал имя
(SNI) или когда ни один именованный сертификат под это имя не подошёл.
Файлы самоподписанной пары лежат в хранилище TLS — каталоге tls-state внутри рабочего каталога
службы (/var/lib/hastreamer/tls-state/ при установке по умолчанию). Относительные пути в cert и
key отсчитываются от него же.
sync_from нужен, когда пару обновляет другая служба на этом же хосте: сервер копирует исходный PEM
в собственные файлы cert/key, проверяет их и подменяет «на лету». Указывать cert и key при
этом обязательно — они и есть цель копирования:
invalid config …: tls: `sync_from` requires `cert` and `key` (the node-owned snapshot paths the source is copied into)
Браузер покажет предупреждение, а публикация из браузера (WHIP) и часть возможностей плеера требуют доверенного соединения. Для рабочей установки используйте ACME или сертификат вашего УЦ.
Свой сертификат#
Положите PEM-файлы и ограничьте права на ключ:
sudo install -d -o root -g root -m 0700 /etc/hastreamer/certs sudo install -o root -g root -m 0644 fullchain.pem /etc/hastreamer/certs/fullchain.pem sudo install -o root -g root -m 0600 privkey.pem /etc/hastreamer/certs/privkey.pem
Объявите именованный сертификат:
https 443; certificate edge1 { hosts media.example.com; cert /etc/hastreamer/certs/fullchain.pem; key /etc/hastreamer/certs/privkey.pem; ca /etc/hastreamer/certs/chain.pem; # необязательно: промежуточные УЦ }
Применение — горячее, разрыва соединений нет:
sudo hastreamer --validate /etc/hastreamer/hastreamer.conf sudo systemctl reload hastreamer
Тот же результат даёт панель (Configuration → Certificates → Add or replace a certificate, режим Upload PEM) или API:
curl -sS -X POST "https://media.example.com/api/v1/certs/edge1" \ -H "Authorization: Bearer $TOKEN" \ -H 'Content-Type: application/json' \ -d '{"hosts":["media.example.com"], "cert":"-----BEGIN CERTIFICATE-----\n…\n-----END CERTIFICATE-----\n", "key":"-----BEGIN PRIVATE KEY-----\n…\n-----END PRIVATE KEY-----\n"}'
Пара «сертификат — ключ» проверяется до сохранения: несовпадающая пара отвергается и ничего не
перезаписывает. Сохранённые файлы получают права 0600 и подхватываются без перезапуска.
Автоматический выпуск (ACME)#
Сервер умеет сам заказывать и продлевать сертификаты по ACME с проверкой HTTP-01.
Настройка#
http 80; # обязательно: на этом слушателе отвечает проверка https 443; acme_contact ops@example.com; certificate media.example.com { hosts media.example.com; acme; }
| Параметр | Тип и допустимые значения | По умолчанию | Применение |
|---|---|---|---|
acme_directory |
URL каталога удостоверяющего центра | https://acme-v02.api.letsencrypt.org/directory |
рестарт |
acme_contact |
адрес электронной почты для уведомлений УЦ | "" |
рестарт |
acme (в блоке certificate) |
флаг: acme;, acme on;, acme off; |
off |
горячее |
Обратите внимание на разное применение: сам блок certificate — «горячий» (добавляется без
перезапуска), а параметры учётной записи acme_directory и acme_contact — «рестартные».
Настраивайте их до первого выпуска.
Что должно совпасть, иначе выпуска не будет#
- Объявлен хотя бы один защищённый слушатель (
https,rtspsилиrtmps). Без него задача выпуска вообще не запускается. - Имена конкретные, без подстановок. HTTP-01 не выпускает
*.example.com. - Удостоверяющий центр должен достучаться до
http://media.example.com/.well-known/acme-challenge/<токен>по порту 80. Сервер отвечает на этот путь на своёмhttp-слушателе открытым текстом, до авторизации и маршрутизации. Еслиhttpне равен 80, пробросьте внешний 80-й порт на него. - Разрешены исходящие HTTPS-соединения к адресу из
acme_directory. - Имя в DNS указывает на этот сервер.
Конфигурация с acme проходит проверку, даже если ни одного защищённого слушателя нет: сервер
запустится и будет молча работать без сертификата. Смотрите журнал — сообщения об ошибках выпуска
начинаются с acme[<имя>]:.
Как это работает#
- Внутренняя задача выпуска сканирует конфигурацию раз в 60 секунд и начинает со сна — чтобы слушатели успели подняться до первой проверки со стороны УЦ.
- Конфигурация читается живой: добавленный через панель или API сертификат подхватывается за один цикл, без перезапуска.
- Продление начинается за 30 суток до окончания срока, так что у неудачного продления есть недели на повторы.
- При неудаче — нарастающая пауза: 15 минут после первой ошибки, удвоение на каждой следующей, верхний предел 6 часов. Это защита от лимитов УЦ.
- Выпущенная пара подставляется в SNI-хранилище на лету: без перезапуска и без обрыва зрителей. Если пересборка не удалась, продолжает работать прежний сертификат.
- Файлы:
tls-state/certs/<имя>/acme.cert.pem,acme.key.pemиacme.meta.jsonрядом. Ключ учётной записи ACME сохраняется вtls-state/acme/account.key.pemпри первом выпуске, поэтому учётная запись переживает перезапуски.
Успешный выпуск виден в журнале:
acme: issued/renewed cert(s) hot-swapped into the SNI store
Пока вы проверяете доступность порта 80 и записи DNS, укажите тестовый каталог:
acme_directory https://acme-staging-v02.api.letsencrypt.org/directory;. Он выдаёт недоверенные
сертификаты, зато с мягкими лимитами. Затем верните рабочий каталог и перезапустите службу —
параметр «рестартный».
Несколько имён и SNI#
Каждое имя описывается своим блоком certificate. Сервер выбирает сертификат по имени, которое
клиент прислал в TLS-рукопожатии (SNI); если совпадения нет — предъявляется пара из блока tls { }.
http 80; https 443; acme_contact ops@example.com; # Публичное имя — выпускается автоматически. certificate public { hosts media.example.com; acme; } # Внутреннее имя и весь домен филиалов — сертификат корпоративного УЦ. certificate internal { hosts media.internal.example.com *.branch.example.com; cert /etc/hastreamer/certs/internal-fullchain.pem; key /etc/hastreamer/certs/internal-privkey.pem; } # Что предъявлять, если имя не подошло или клиент его не прислал. tls { cert /etc/hastreamer/certs/internal-fullchain.pem; key /etc/hastreamer/certs/internal-privkey.pem; }
Правила именования узлов в hosts:
- перечисляйте имена через пробел, в одной строке;
- подстановка допускается только вида
*.suffix— одна метка (*.branch.example.comподходит,*.*.example.com— нет); - подстановочные имена возможны только с загруженным сертификатом: автовыпуск их не поддерживает;
- имена блоков должны быть уникальны.
Проверка#
openssl s_client -connect media.example.com:443 -servername media.example.com </dev/null 2>/dev/null \ | openssl x509 -noout -subject -issuer -dates
subject=CN = media.example.com issuer=C = US, O = Example CA, CN = Example CA R3 notBefore=Aug 19 09:14:00 2026 GMT notAfter=Nov 17 09:13:59 2026 GMT
Список всех известных серверу сертификатов, включая срок и состояние автовыпуска:
curl -sS "https://media.example.com/api/v1/certs" -H "Authorization: Bearer $TOKEN"
Данные читаются из сохранённых файлов, а не из конфигурации, поэтому показывают то, что сервер
действительно предъявит. То же видно в панели: Configuration → Certificates, где у записи с
автовыпуском есть значок ACME и состояние — сколько суток осталось, идёт ли выпуск, была ли
ошибка продления.
Типичные ошибки#
Ошибки конфигурации (проверяются hastreamer --validate, приведены дословно):
| Сообщение | Причина |
|---|---|
certificate "edge1": needs at least one `hosts` entry (else it is never selected) |
в блоке нет ни одного имени — такой сертификат никогда не будет выбран |
certificate "edge1": `cert` and `key` paths are required (or set `acme` to auto-issue) |
не указаны пути к PEM и не включён автовыпуск |
certificate "edge1": `acme` and explicit `cert`/`key` are mutually exclusive |
нельзя одновременно загрузить пару и заказать выпуск |
certificate "edge1": ACME/HTTP-01 cannot issue the wildcard "*.example.com" — give a concrete hostname |
подстановочное имя с флагом acme |
duplicate certificate name "edge1" |
два блока с одинаковым именем |
https and rtsps both use port 8443 — listener ports must be distinct |
два слушателя на одном порту |
Ошибки выпуска (конфигурация верна, сертификат не появляется):
| Симптом | Причина | Что делать |
|---|---|---|
Сертификата нет, и в журнале нет ни одной строки об ACME — ни об ошибке (acme[имя]: …), ни об успехе |
не объявлен защищённый слушатель — задача выпуска не запущена | добавьте https <порт>; и перезапустите службу |
acme[имя]: … с ошибкой проверки |
УЦ не смог получить http://<имя>/.well-known/acme-challenge/<токен> на порту 80 |
откройте порт 80 снаружи и пробросьте его на http-слушатель; проверьте запись DNS |
| Ошибка соединения с каталогом УЦ | закрыт исходящий HTTPS | разрешите исходящие соединения к адресу из acme_directory |
| Повторные попытки идут редко | сработала нарастающая пауза (до 6 часов) | исправьте причину и перезапустите службу, чтобы не ждать окончания паузы |
| Браузер показывает старый сертификат | клиент держит установленное соединение | подмена действует на новых рукопожатиях; переоткройте соединение |
| Сертификат есть, но не предъявляется | имя в hosts не совпадает с тем, что запрашивает клиент |
сверьте SNI: openssl s_client -servername … |
Что дальше#
- Порты и сеть — какие порты открывать и как их менять.
- Применение изменений — что применяется по
reload, а что требуетrestart. - Доступ к админке и API — защита панели после включения HTTPS.