Проблемы с Let's Encrypt

Похоже, что с 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 и необходимость сбора и сохранения адреса электронной почты.

Я предполагаю, что то, что я сделал, будет перезаписано при следующем обновлении версий, и мне придётся повторять эти действия, если проблема не будет решена иначе.

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

1 лайк

Просто добавьте свой адрес электронной почты в файл конфигурации.

/var/discourse/containers/app.yml

## Если вы добавили шаблон Lets Encrypt, раскомментируйте строку ниже, чтобы получить бесплатный SSL-сертификат
 LETSENCRYPT_ACCOUNT_EMAIL: gavin@truecode.co.za

Выполните команду ./launcher rebuild app

после этого всё должно работать как надо.

Мы исправили это несколько недель назад. Вы пробовали выполнить пересборку?

3 лайка

Нет, не пробовал. Я использую сборку 2.8.0.beta4, и система сообщает, что у меня установлена актуальная версия. Нужно ли выполнять пересборку после обновлений, или какие-то компоненты загружаются динамически между обновлениями, что требует пересборки? У меня указан адрес электронной почты в переменной LETSENCRYPT_ACCOUNT_EMAIL.

Я могу выполнить пересборку. Мне сначала нужно будет восстановить исходную версию скрипта letsencrypt, или пересборка обновит его автоматически? Нужно ли выполнять пересборку после каждого обновления, или существует какой-то механизм уведомления о необходимости этого? До настоящего момента я ни разу не выполнял пересборку после первоначальной настройки сайта примерно шесть месяцев назад, хотя регулярно применял обновления.

Хотя вы можете обновлять приложение через веб-интерфейс, время от времени нам приходится выпускать обновления для базовой среды, в которой работает Discourse (образа контейнера). Такие обновления среды требуют пересборки.

Чтобы отменить ваши локальные изменения, вы можете временно сохранить их с помощью

cd /var/discourse
git stash
./launcher rebuild app
1 лайк

Это ли «обновления окружения» — те самые обновления «docker-manager», которые я вижу после нажатия на ссылку «выполнить обновления здесь» на странице настроек администратора? Казалось бы, я немного запутался: какие обновления мне нужно получать, откуда и когда следует выполнять пересборку. Хотя на той странице я вижу доступное обновление, на предыдущей странице всё ещё указано, что у меня установлена актуальная версия.

Нет, чтобы получить их, необходимо получить доступ к серверу через командную строку и выполнить команду rebuild.

Хорошо. Я выполнил пересборку, но не уверен, что она сработает через 90 дней, так как сертификат ещё не истёк, поэтому система не пытается получить новый. Я проверил скрипт letsencrypt: дата изменения указана сегодняшняя, но при сравнении с оригинальной версией скрипта (до моих правок) они идентичны. Я попытался запустить скрипт вручную из контейнера с флагом --force, как рекомендовано в одном из комментариев вывода, но это не помогло. Поэтому сейчас мне остаётся лишь надеяться, что при истечении срока действия сертификат обновится без проблем.