HTTPS и сертификаты

Панель умеет обслуживать HTTPS самостоятельно, без обратного прокси. Сертификат можно взять из файлов, задать прямо в конфигурации или получать автоматически через Let’s Encrypt.

Настройки задаются в config.env/etc/gameap/config.env в Linux, C:\gameap\web\config.env в Windows. После изменения нужен перезапуск: gameapctl panel restart.

Источники сертификата

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

  1. ACME — если заданы ACME_ENABLED=true, ACME_EMAIL и ACME_DOMAINS.
  2. Файлы — если заданы TLS_CERT_FILE и TLS_KEY_FILE.
  3. Значения в конфигурации — если заданы TLS_CERT и TLS_KEY.
  4. Нет сертификата — панель работает только по HTTP.

Проверяются именно пары: один TLS_CERT_FILE без TLS_KEY_FILE не считается заданным источником и молча игнорируется.

HTTPS слушается на порту из HTTPS_PORT (по умолчанию 443) и только при наличии сертификата. HTTP на HTTP_PORT (по умолчанию 8025) работает всегда.

Сертификат панели никак не связан с сертификатами gRPC, по которым панель общается с демонами. Те выпускаются внутренним центром сертификации автоматически, ACME на них не распространяется. Подробнее — GRPC API.

Сертификат из файлов

TLS_CERT_FILE=/etc/gameap/certs/panel.crt
TLS_KEY_FILE=/etc/gameap/certs/panel.key
HTTPS_PORT=443

В файле сертификата должна быть полная цепочка: сам сертификат, затем промежуточные. Без промежуточных часть клиентов не сможет проверить подпись.

Файлы читаются при запуске. После замены сертификата панель нужно перезапустить — сама она изменения в файлах не отслеживает.

Сертификат прямо в конфигурации

Удобно, когда конфигурация раскладывается системой управления секретами и лишние файлы на диске нежелательны.

TLS_CERT=LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0t...
TLS_KEY=LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0t...

Принимается как обычный PEM, так и PEM в кодировке base64 — панель определяет формат сама. Поскольку формат config.env не поддерживает многострочные значения, на практике используется base64:

base64 -w0 panel.crt
base64 -w0 panel.key

Let’s Encrypt

Панель содержит встроенный клиент ACME: сертификат выпускается и продлевается без внешних утилит вроде certbot.

Переменная По умолчанию Назначение
ACME_ENABLED false Включение автоматического выпуска
ACME_EMAIL "" Адрес для уведомлений об истечении. Обязателен
ACME_DOMAINS "" Домены через запятую. Обязательны
ACME_CHALLENGE_TYPE http-01 Способ подтверждения: http-01 или dns-01
ACME_DNS_PROVIDER "" Провайдер DNS, только для dns-01
ACME_DIRECTORY_URL боевой ACME Адрес каталога ACME
ACME_RENEWAL_THRESHOLD 720h За сколько до истечения продлевать. По умолчанию 30 суток
ACME_RENEWAL_CHECK_INTERVAL 12h Как часто проверять срок
ACME_PROPAGATION_TIMEOUT 180s Сколько ждать распространения DNS-записи при dns-01
ACME_STORAGE_PATH acme Каталог для сертификатов и ключа учётной записи ACME

ACME включается только при одновременно заданных ACME_ENABLED=true, ACME_EMAIL и ACME_DOMAINS, а для dns-01 — ещё и ACME_DNS_PROVIDER. Если чего-то не хватает, панель запустится без ACME и без ошибки. Проверить, что получилось, можно по состоянию в админке.

Подтверждение по http-01

Способ по умолчанию. Ничего, кроме доступности панели из интернета, не требует.

ACME_ENABLED=true
ACME_EMAIL=admin@example.com
ACME_DOMAINS=panel.example.com
ACME_CHALLENGE_TYPE=http-01
TLS_FORCE_HTTPS=true

Что нужно:

  • домены из ACME_DOMAINS должны резолвиться в адрес этого сервера;
  • запрос на порт 80 должен доходить до панели — центр сертификации обращается именно на него;
  • панель обслуживает путь /.well-known/acme-challenge/ самостоятельно, на своём HTTP-порту.

Панель по умолчанию слушает порт 8025, а центр сертификации всегда обращается на 80. Само по себе это не совпадает. Либо задайте HTTP_PORT=80, либо пробросьте 80-й порт на порт панели средствами системы:

iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8025

Это самая частая причина, по которой выпуск по http-01 не проходит.

Порт 80 нужен не только при первом выпуске: подтверждение повторяется при каждом продлении, поэтому закрывать его потом нельзя.

Способ http-01 не выпускает сертификаты на поддомены с подстановкой (*.example.com) — для них нужен dns-01.

Подтверждение по dns-01

Нужен, если панель не доступна из интернета по порту 80 или требуется сертификат с подстановкой.

Из встроенных провайдеров поддерживается только Cloudflare. Остальные подключаются плагинами: в этом случае в ACME_DNS_PROVIDER указывается <идентификатор-плагина>:<имя-провайдера>.

ACME_ENABLED=true
ACME_EMAIL=admin@example.com
ACME_DOMAINS=panel.example.com,*.example.com
ACME_CHALLENGE_TYPE=dns-01
ACME_DNS_PROVIDER=cloudflare
CLOUDFLARE_DNS_API_TOKEN=токен_из_панели_cloudflare

Токен создаётся в Cloudflare с правом Zone → DNS → Edit для нужной зоны. Кроме CLOUDFLARE_DNS_API_TOKEN принимаются CF_DNS_API_TOKEN, CLOUDFLARE_API_TOKEN и CF_API_TOKEN, а также устаревшая пара «глобальный ключ + почта»: CLOUDFLARE_API_KEY вместе с CLOUDFLARE_EMAIL. Предпочтительнее токен с ограниченными правами.

Если DNS-записи распространяются медленно, увеличьте ACME_PROPAGATION_TIMEOUT.

Настройка через gameapctl

Вместо ручной правки config.env можно воспользоваться мастером:

gameapctl panel letsencrypt setup

Он спросит домены, адрес почты и способ подтверждения, запишет настройки в config.env и перезапустит панель.

Тот же вызов без вопросов:

gameapctl panel letsencrypt setup --non-interactive \
  --domains=panel.example.com \
  --email=admin@example.com \
  --challenge=http-01

Полезные флаги:

Флаг Назначение
--challenge http-01 или dns-01
--domains Домены через запятую
--email Адрес учётной записи ACME
--dns-provider Провайдер DNS для dns-01
--env Дополнительные строки КЛЮЧ=ЗНАЧЕНИЕ в config.env — для доступов к DNS
--staging Тестовый каталог Let’s Encrypt
--non-interactive Не задавать вопросов, а завершиться с ошибкой при нехватке параметров

Отключение:

gameapctl panel letsencrypt disable

Команда удаляет из config.env переменные ACME_* и перезапускает панель. Флаг --purge-certs объявлен, но пока не реализован — выпущенные сертификаты остаются на диске.

Отладка выпуска

У боевого каталога Let’s Encrypt жёсткие ограничения на число попыток для одного домена, и исчерпать их при настройке легко. Пока настройка не заработала, используйте тестовый каталог:

ACME_DIRECTORY_URL=https://acme-staging-v02.api.letsencrypt.org/directory

Его сертификаты браузер считает недоверенными, зато ограничения несравнимо мягче. Когда выпуск пройдёт, уберите эту переменную, удалите содержимое каталога из ACME_STORAGE_PATH и перезапустите панель, чтобы получить боевой сертификат.

Продление

Панель проверяет срок каждые ACME_RENEWAL_CHECK_INTERVAL (по умолчанию раз в 12 часов) и продлевает сертификат, когда до истечения остаётся меньше ACME_RENEWAL_THRESHOLD (по умолчанию 30 суток). Отдельная задача в планировщике или cron не нужна.

Сертификаты, ключ учётной записи ACME и служебные данные хранятся в каталоге ACME_STORAGE_PATH внутри файлового хранилища панели. Если FILES_DRIVER=s3, они попадают в S3 — это то, что позволяет нескольким экземплярам панели использовать один сертификат.

Состояние сертификата

Текущее состояние доступно администратору по адресу GET /api/admin/letsencrypt/status:

{
  "enabled": true,
  "state": "active",
  "challenge_type": "http-01",
  "domains": ["panel.example.com"],
  "not_after": "2026-10-30T12:00:00Z",
  "last_renewal_at": "2026-08-01T12:00:00Z",
  "next_renewal_check_at": "2026-08-02T00:00:00Z"
}

Возможные значения state:

Значение Что означает
disabled ACME выключен
pending Сертификат ещё не выпущен
active Сертификат выпущен и действителен
renewing Идёт продление
failed Последняя попытка не удалась, причина в last_error

Перенаправление на HTTPS

TLS_FORCE_HTTPS=true

Все запросы по HTTP получают перенаправление 301, кроме /.well-known/acme-challenge/ — иначе подтверждение по http-01 перестало бы работать.

Эта же переменная влияет на два других механизма: заголовок HSTS начинает отдаваться, даже если TLS завершается на обратном прокси, и адрес источника для CORS вычисляется со схемой https.

Панель за обратным прокси

Если TLS завершается на nginx, Traefik или другом прокси, сертификаты в панели настраивать не нужно — оставьте ACME_ENABLED=false и не задавайте TLS_*. Панель будет работать по HTTP на 8025, а прокси — обслуживать HTTPS.

Что при этом важно:

  • Прокси должен передавать заголовок X-Forwarded-Proto: https, иначе панель не поймёт, что соединение защищено, и не отдаст HSTS.
  • Заголовки X-Forwarded-Proto и заголовок из AUDIT_CLIENT_IP_HEADER прокси должен перезаписывать, а не дополнять: панель доверяет им без проверки отправителя.
  • Порт 31718 через прокси обычно не проходит — демоны должны подключаться к панели напрямую. Задайте GRPC_EXTERNAL_HOST с адресом, по которому панель доступна демонам.
  • Если публичный адрес отличается от HTTP_HOST, перечислите его в HTTP_ALLOWED_ORIGINS.

Частые ошибки

Признак Причина
Панель запустилась, но HTTPS не слушается Не задана пара переменных целиком либо не хватает одной из обязательных ACME_*
state: failed при http-01 Порт 80 недоступен извне, домен не резолвится в этот сервер или его перехватывает другой сервис
state: failed при dns-01 Нет прав у токена DNS или запись не успела распространиться — увеличьте ACME_PROPAGATION_TIMEOUT
Выпуск перестал работать после нескольких попыток Исчерпан лимит боевого каталога Let’s Encrypt. Перейдите на тестовый каталог и настройте на нём
Браузер ругается на цепочку В TLS_CERT_FILE только сертификат без промежуточных
Сертификат заменили, но отдаётся старый Файлы читаются при запуске — нужен gameapctl panel restart