Похоже, что с 1 августа в сервисе Let’s Encrypt произошли некоторые изменения. Мой сертификат истекал только сегодня, поэтому я столкнулся с последствиями этих изменений лишь сегодня. Скрипты, которые использует Discourse для управления сервисом Let’s Encrypt, были обновлены так, чтобы по умолчанию использовать новый сервис ZeroSSL вместо Let’s Encrypt. К сожалению, ZeroSSL, судя по всему, требует регистрации с указанием адреса электронной почты перед тем, как начать работать, поэтому сегодня утром, когда мой существующий сертификат истёк, сайт перестал работать.
После довольно тщательного расследования я понял, в чём проблема. Хотя мне удалось как-то обойти её, я не считаю, что моё решение является «правильным». Сначала приведу сообщения об ошибках, которые я видел в логе:
[Wed 01 Sep 2021 05:33:58 PM UTC] Reload error for :
[Wed 01 Sep 2021 05:34:03 PM UTC] Using CA: https://acme.zerossl.com/v2/DV90
[Wed 01 Sep 2021 05:34:04 PM UTC] No EAB credentials found for ZeroSSL, let's get one
[Wed 01 Sep 2021 05:34:04 PM UTC] acme.sh is using ZeroSSL as default CA now.
[Wed 01 Sep 2021 05:34:04 PM UTC] Please update your account with an email address first.
[Wed 01 Sep 2021 05:34:04 PM UTC] acme.sh --register-account -m my@example.com
[Wed 01 Sep 2021 05:34:04 PM UTC] See: https://github.com/acmesh-official/acme.sh/wiki/ZeroSSL.com-CA
[Wed 01 Sep 2021 05:34:04 PM UTC] Please check log file for more details: /shared/letsencrypt/acme.sh.log
Я попытался вручную зарегистрировать учётную запись внутри контейнера, и хотя система сообщила об успешной регистрации, после перезапуска контейнера ошибка повторилась. Тогда я нашёл соответствующие скрипты; тот, который отвечает за эту процедуру, находится внутри контейнера по пути /etc/runit/1.d/letsencrypt. Вот исходный скрипт:
#!/bin/bash
/usr/sbin/nginx -c /etc/nginx/letsencrypt.conf
issue_cert() {
LE_WORKING_DIR="${LETSENCRYPT_DIR}" /shared/letsencrypt/acme.sh --issue $2 -d mudtoemanor.baronshire.org --keylength $1 -w /var/www/discourse/public
}
cert_exists() {
[[ "$(cd /shared/letsencrypt/mudtoemanor.baronshire.org$1 && openssl verify -CAfile ca.cer fullchain.cer | grep "OK")" ]]
}
########################################################
# RSA cert
########################################################
issue_cert "4096"
if ! cert_exists ""; then
# Try to issue the cert again if something goes wrong
issue_cert "4096" "--force"
fi
LE_WORKING_DIR="${LETSENCRYPT_DIR}" /shared/letsencrypt/acme.sh \
--installcert \
-d mudtoemanor.baronshire.org \
--fullchainpath /shared/ssl/mudtoemanor.baronshire.org.cer \
--keypath /shared/ssl/mudtoemanor.baronshire.org.key \
--reloadcmd "sv reload nginx"
########################################################
# ECDSA cert
########################################################
issue_cert "ec-256"
if ! cert_exists "_ecc"; then
# Try to issue the cert again if something goes wrong
issue_cert "ec-256" "--force"
fi
LE_WORKING_DIR="${LETSENCRYPT_DIR}" /shared/letsencrypt/acme.sh \
--installcert --ecc \
-d mudtoemanor.baronshire.org \
--fullchainpath /shared/ssl/mudtoemanor.baronshire.org_ecc.cer \
--keypath /shared/ssl/mudtoemanor.baronshire.org_ecc.key \
--reloadcmd "sv reload nginx"
if cert_exists "" || cert_exists "_ecc"; then
grep -q 'force_https' "/var/www/discourse/config/discourse.conf" || echo "force_https = 'true'" >> "/var/www/discourse/config/discourse.conf"
fi
/usr/sbin/nginx -c /etc/nginx/letsencrypt.conf -s stop
Поскольку регистрация по электронной почте не сработала, я решил добавить опцию, чтобы скрипт acme.sh возвращался к использованию оригинального Let’s Encrypt вместо ZeroSSL. Инструкция о том, как это сделать, была предоставлена на этом сайте: https://community.letsencrypt.org/t/the-acme-sh-will-change-default-ca-to-zerossl-on-august-1st-2021/144052
Сначала я попробовал добавить эту строку третьей в скрипт, сразу после команды “/usr/sbin/nginx -c /etc/nginx/letsencrypt.conf”:
/shared/letsencrypt/acme.sh --set-default-ca --server letsencrypt
В логе появилось сообщение об изменении значения по умолчанию, но сразу после этого я получил ту же ошибку об отсутствии зарегистрированного email для ZeroSSL. Между этим сообщением и сообщениями об ошибках в логе была задержка около 6 секунд, что заставляет меня предположить, что скрипт acme.sh хранит информацию о состоянии через переменные окружения, и последующие вызовы команды выполнялись в другом контексте, из-за чего переменная терялась. В итоге мне пришлось изменить все вызовы acme.sh в скрипте letsencrypt, добавив к команде аргумент “–server letsencrypt”. Когда я сделал это и перезапустил контейнер, новый сертификат был сгенерирован Let’s Encrypt вместо ZeroSSL, и сайт снова заработал.
Вот модифицированная версия скрипта letsencrypt, которую я использовал:
#!/bin/bash
/usr/sbin/nginx -c /etc/nginx/letsencrypt.conf
/shared/letsencrypt/acme.sh --set-default-ca --server letsencrypt
issue_cert() {
LE_WORKING_DIR="${LETSENCRYPT_DIR}" /shared/letsencrypt/acme.sh --server letsencrypt --issue $2 -d mudtoemanor.baronshire.org --keylength $1 -w /var/www/discourse/public
}
cert_exists() {
[[ "$(cd /shared/letsencrypt/mudtoemanor.baronshire.org$1 && openssl verify -CAfile ca.cer fullchain.cer | grep "OK")" ]]
}
########################################################
# RSA cert
########################################################
issue_cert "4096"
if ! cert_exists ""; then
# Try to issue the cert again if something goes wrong
issue_cert "4096" "--force"
fi
LE_WORKING_DIR="${LETSENCRYPT_DIR}" /shared/letsencrypt/acme.sh \
--installcert \
-d mudtoemanor.baronshire.org \
--fullchainpath /shared/ssl/mudtoemanor.baronshire.org.cer \
--keypath /shared/ssl/mudtoemanor.baronshire.org.key \
--server letsencrypt \
--reloadcmd "sv reload nginx"
########################################################
# ECDSA cert
########################################################
issue_cert "ec-256"
if ! cert_exists "_ecc"; then
# Try to issue the cert again if something goes wrong
issue_cert "ec-256" "--force"
fi
LE_WORKING_DIR="${LETSENCRYPT_DIR}" /shared/letsencrypt/acme.sh \
--installcert --ecc \
-d mudtoemanor.baronshire.org \
--fullchainpath /shared/ssl/mudtoemanor.baronshire.org_ecc.cer \
--keypath /shared/ssl/mudtoemanor.baronshire.org_ecc.key \
--server letsencrypt \
--reloadcmd "sv reload nginx"
if cert_exists "" || cert_exists "_ecc"; then
grep -q 'force_https' "/var/www/discourse/config/discourse.conf" || echo "force_https = 'true'" >> "/var/www/discourse/config/discourse.conf"
fi
/usr/sbin/nginx -c /etc/nginx/letsencrypt.conf -s stop
Я также оставил исходную команду, которую я вставил для попытки установки сервиса по умолчанию, на всякий случай, хотя она может быть и не нужна.
Итак, что необходимо сделать: этот скрипт нужно изменить либо так, чтобы явно указывать сервис Let’s Encrypt для всех вызовов acme.sh, либо разобраться, как acme.sh сохраняет информацию о состоянии, чтобы один вызов команды установки по умолчанию работал корректно, либо, в третьем варианте, добавить поддержку ZeroSSL и необходимость сбора и сохранения адреса электронной почты.
Я предполагаю, что то, что я сделал, будет перезаписано при следующем обновлении версий, и мне придётся повторять эти действия, если проблема не будет решена иначе.
Если я что-то упустил или если это каким-то образом было решено другим способом, не требующим изменения скриптов, пожалуйста, дайте знать.