Шаблон проверки DNS для LetsEncrypt с использованием Cloudflare

Привет, @LotusJeff,

Да, валидация через DNS по-прежнему работает, но, пожалуйста, больше не используйте шаблон из моего первого поста. Он устарел по сравнению с текущей версией discourse_docker:

  • Проверка cert_exists в нём не проходит с текущей цепочкой Let’s Encrypt, поэтому он принудительно запрашивает новые сертификаты при каждом запуске контейнера, что может привести к достижению лимита на дублирование сертификатов.
  • Шаги replace для nginx нацелены на строки, которые переместились, а шаг с add_header теперь перезаписывает несвязанный заголовок ETag.

Теперь вам не нужен пользовательский шаблон. Оставьте стандартный шаблон Let’s Encrypt и переключите его на валидацию через DNS в app.yml:

templates:
  # ...
  - "templates/web.ssl.template.yml"
  - "templates/web.letsencrypt.ssl.template.yml"

env:
  # ...
  CF_Token: "YOUR_TOKEN"        # API-токен Cloudflare с правами Zone > DNS > Edit для этой зоны
  CF_Zone_ID: "YOUR_ZONE_ID"

run:
  - exec:
      cmd:
        - mkdir -p /opt/dnsapi
        - curl -fsSL https://raw.githubusercontent.com/acmesh-official/acme.sh/3.0.6/dnsapi/dns_cf.sh -o /opt/dnsapi/dns_cf.sh
  - replace:
      filename: /usr/local/bin/letsencrypt
      from: "-w /var/www/discourse/public"
      to: "--dns dns_cf"

Что это делает:

  • Стандартный шаблон загружает только основной скрипт acme.sh без плагинов для DNS. Шаг exec добавляет плагин Cloudflare, а стандартный скрипт запуска копирует его в /shared/letsencrypt/dnsapi/. Убедитесь, что версия в URL совпадает с версией acme.sh, указанной в templates/web.letsencrypt.ssl.template.yml (на данный момент это 3.0.6).
  • Секция run: выполняется после применения шаблонов, поэтому replace переключает стандартный скрипт запуска с HTTP-валидации на DNS-валидацию.
  • При валидации acme.sh читает CF_Token и CF_Zone_ID из окружения и сохраняет их вместе с сертификатом. Ежедневная задача cron не видит окружение контейнера, поэтому при обновлении сертификатов используется эта сохраненная копия.

Если вы использовали мой старый шаблон, удалите его строку из секции templates: и переименуйте переменные LETSENCRYPT_CF_TOKEN и LETSENCRYPT_CF_ZONE_ID в CF_Token и CF_Zone_ID.

Если у вас уже есть сертификаты (полученные через HTTP-валидацию или с помощью моего старого шаблона), переместите старую папку acme.sh в сторону перед пересборкой:

cd /var/discourse
mv shared/standalone/letsencrypt shared/standalone/letsencrypt.old
./launcher rebuild app

Без этого acme.sh может пропустить шаг с DNS (он сохраняет старый метод до тех пор, пока не наступит срок обновления, а Let’s Encrypt может повторно использовать недавнюю валидацию). В таком случае токен никогда не сохраняется, и первое обновление по cron завершается ошибкой. При использовании чистой папки acme.sh регистрирует новый аккаунт и выполняет реальную DNS-валидацию, поэтому первый запуск займет примерно на минуту больше.

Не удаляйте папку .old, пока новые сертификаты не заработают корректно. Если шаг с DNS завершится ошибкой, скрипт запуска все равно перезапишет файлы в shared/ssl, и nginx не запустится.

acme.sh сохраняет токен в виде простого текста в папке shared/standalone/letsencrypt/, поэтому выдавайте токену только необходимые разрешения.

Протестировано с discourse_docker и Discourse latest по состоянию на ноябрь 2026 года.