Сайт четыре дня отдавал истёкший сертификат. Сервер работал, страницы собирались, проверка без строгой проверки сертификата получала 200. А посетитель вместо сайта видел во весь экран предупреждение браузера об опасном соединении. Заметили случайно, разбирая другую задачу.
Это девятая часть цикла «Сервер для WordPress».
Кто продлевается сам, а кто нет
- Let’s Encrypt через traefik продлевается сам — но не у всех сайтов. Для роутера с регулярным выражением в правиле (нужен для поддоменов городов) traefik не может вывести список имён и сертификат не выпустит. Опечатка в имени резолвера в метке — и сертификат не выпускается молча;
- покупные wildcard-сертификаты продлеваются только руками. Именно они и истекают.
Почему «напомнить за две недели» мало
Второй случай. Покупной сертификат: предупреждение за 12 дней, повторное за 6. Новый выпустили за четыре дня до срока, а до сервера он дошёл на следующий день после истечения. Сайт сутки отдавал истёкший сертификат — при том, что все знали.
Вывод: к порогу в две недели новый сертификат должен быть на руках, а не «заказан».
Проверять по сети, а не по файлам
Сертификат выбирается по имени, которое браузер передаёт при соединении (SNI). У одного сайта их бывает несколько:
- на одном сайте корень домена отдавал истёкший покупной wildcard, а
www.и тестовый поддомен — живые Let’s Encrypt. Проверка толькоwwwсказала бы «всё хорошо»; - на другом корень домена в один день отдавал Let’s Encrypt, через неделю — покупной wildcard. Полагаться на то, что «там же есть автоматический», нельзя;
- файл на диске и то, что реально отдаётся, могут не совпадать.
Обход раз в неделю — корень, www и поддомены каждого сайта:
for h in site.ru www.site.ru msk.site.ru; do
printf "%-24s " $h
echo | timeout 12 openssl s_client -connect $h:443 -servername $h 2>/dev/null \
| openssl x509 -noout -enddate -issuer 2>/dev/null | tr "\n" " "
curl -s -o /dev/null -w "curl=%{http_code}\n" --max-time 15 https://$h/
done
curl без -k — самый быстрый признак: 200 или 301 значит, сертификат принят; 000 — клиент его отверг.
Неполная цепочка: в браузере не видно
Сервер обязан отдавать не только свой сертификат, но и промежуточный. Браузеры часто достраивают цепочку сами, а curl, node и python — нет. Сайт открывается у всех, а интеграции, вебхуки и мониторинг падают.
echo | openssl s_client -connect site.ru:443 -servername site.ru -showcerts 2>/dev/null \
| grep -E '^ [0-9] s:|Verify return code'
# 0 s:CN = *.site.ru
# 1 s:CN = AlphaSSL CA ...
# Verify return code: 0 (ok) ← 10 — истёк, 20/21 — нет промежуточного
Установка покупного сертификата: три проверки
- промежуточный брать по ссылке из самого сертификата (поле CA Issuers), а не «тот же, что в прошлый раз». У нас новый выпуск пришёл от другого промежуточного центра — старый файл не подошёл бы;
- проверить, что ключ подходит: хэши модуля сертификата и ключа должны совпасть. Дважды выпуск оказывался под новый ключ, и ставить пришлось пару целиком;
- собрать fullchain: свой сертификат, затем промежуточный, и проверить
openssl verify.
openssl x509 -in leaf.pem -noout -text | grep 'CA Issuers' # откуда брать промежуточный
openssl x509 -in leaf.pem -noout -modulus | openssl sha256 # должен совпасть…
openssl rsa -in site.key -noout -modulus | openssl sha256 # …с этим
openssl verify -untrusted inter.pem leaf.pem # OK
cat leaf.pem inter.pem > fullchain.crt
Без перезапуска traefik
Перезапуск traefik — это несколько секунд недоступности всех сайтов сервера. Он не нужен: если сертификаты подключены файловым провайдером, достаточно заменить файлы и обновить время изменения его конфига. traefik перечитает его сам — у нас новый сертификат отдавался через 5 секунд.
cat fullchain.crt > /path/certs/site.crt # перезапись сохраняет владельца и права
touch /path/providers/certs.yml
Не знаете, когда истекают сертификаты ваших сайтов?
Пришлите список доменов — проверю все имена и поддомены и скажу, что и когда продлевать руками.
// загружаю комментарии…