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
Проверить автообновление¶
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:
Плейбук копирует 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
Добавить новый домен¶
- Добавить A-запись в DNS, указывающую на
212.70.189.60 - Добавить server block в Nginx с поддержкой ACME challenge
- Выпустить сертификат:
- Настроить 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