Перейти к содержанию

SSL-сертификаты

Как это работает

Все публичные домены обслуживаются через сервер 212.70.189.60 (Nginx). SSL-сертификаты выпускаются через Let's Encrypt с помощью certbot (webroot challenge).

Certbot установлен на хосте 212.70.189.61 (GitLab Runner / dev-сервер). Для сервисов на 212.70.189.60 — certbot запускается на самом хосте.

Сертификаты хранятся в /etc/letsencrypt/live/<domain>/ и монтируются в Nginx-контейнеры.

Автообновление: certbot.timer (systemd), запускается 2 раза в сутки. После обновления hook автоматически перезагружает Nginx.

Проверить срок действия сертификата

# Через HTTPS (быстро, без SSH)
echo | openssl s_client -connect <domain>:443 -servername <domain> 2>/dev/null \
  | openssl x509 -noout -dates

# На хосте напрямую
openssl x509 -noout -dates -in /etc/letsencrypt/live/<domain>/fullchain.pem

# Все сертификаты через certbot
certbot certificates

Ручное обновление

# Обновить конкретный домен
certbot renew --cert-name <domain>

# Dry-run (проверить без реального обновления)
certbot renew --dry-run --cert-name <domain>

# Перезагрузить Nginx после обновления (если hook не сработал)
nginx -s reload
# или в контейнере:
docker exec <nginx-container> nginx -s reload

Проверить автообновление

systemctl status certbot.timer
journalctl -u certbot.service --since "7 days ago"

XUI Panel SSL (внутренний CA)

VPN-серверы используют leaf-сертификат от внутреннего CA ShivaVPN.

Файл Путь
Leaf cert ansible/shiva-ansible/CA/xui_all.crt
Leaf key ansible/shiva-ansible/CA/xui_all.key
CA cert ansible/shiva-ansible/CA/selfsigned-ca.crt
CA key ansible/shiva-ansible/CA/selfsigned-ca.key

CA действует до 2045 года. Backend доверяет внутреннему CA через /tmp/ca.crt внутри контейнера (config: xray.ssl.keystore.path).

Деплой через Ansible:

ansible-playbook -i inventory/servers.ini playbooks/xui-ssl.yml --vault-password-file .vault_pass

Плейбук копирует cert/key, обновляет SQLite настройки x-ui, перезапускает контейнер.

Ручное исправление (если Ansible недоступен):

# 1. Остановить контейнер
docker stop x-ui

# 2. Обновить SQLite настройки
sqlite3 /path/to/x-ui.db "DELETE FROM settings WHERE key IN ('webCertFile', 'webKeyFile');"
sqlite3 /path/to/x-ui.db "INSERT INTO settings (key, value) VALUES ('webCertFile', '/path/to/cert.crt');"
sqlite3 /path/to/x-ui.db "INSERT INTO settings (key, value) VALUES ('webKeyFile', '/path/to/key.key');"

# 3. Запустить контейнер
docker start x-ui

Pitfalls с SQLite

  • key в таблице settings не является уникальным — всегда DELETE+INSERT, не REPLACE
  • Multi-statement в sqlite3 может завершиться молча — выполнять по одному INSERT

Скрипты верификации:

  • scripts/verify_all_layers.py — 18-уровневая проверка (включая SSL/Reality параметры)
  • scripts/verify_transport_params.py — быстрая проверка MySQL transport_params vs X-UI SQLite

Подробнее: docs/guides/KNOWLEDGE-BASE-INDEX.md → раздел "3.9 XUI Panel SSL"

# Деплой сертификата на новый сервер (через Ansible)
ansible-playbook -i inventory/servers.ini playbooks/vpn.yml --tags ssl --vault-password-file .vault_pass

Добавить новый домен

  1. Добавить A-запись в DNS, указывающую на 212.70.189.60
  2. Добавить server block в Nginx с поддержкой ACME challenge
  3. Выпустить сертификат:
    certbot certonly --webroot -w /var/www/certbot -d <new-domain>
    
  4. Настроить HTTPS в Nginx и перезагрузить

Важные пути

Путь Описание
/etc/letsencrypt/live/<domain>/ сертификаты (symlinks)
/etc/letsencrypt/archive/<domain>/ реальные файлы сертификатов
/etc/letsencrypt/renewal/<domain>.conf конфиг renewal
/etc/letsencrypt/renewal-hooks/deploy/ post-renewal hooks

См. также: Ansible · Секреты · DevOps скрипты → verify_transport_params