Выберите продукт

Let’s Encrypt через DNS-01: wildcard, автоматизация продления и безопасные deploy-хуки

DNS-01 удобен для wildcard и закрытых сетей: владение доменом подтверждается TXT-записью в DNS. Разбираем выбор certbot/lego/acme.sh, выпуск и продление через systemd timer, deploy-hook только при обновлении и безопасный деплой на несколько серверов по SSH.
Let’s Encrypt через DNS-01: wildcard, автоматизация продления и безопасные deploy-хуки

DNS-01 — самый «админский» способ пройти проверку ACME у Let’s Encrypt: вы доказываете владение доменом через TXT-запись в DNS. Взамен получаете две ключевые возможности: выпуск wildcard (например, *.example.com) и независимость от веб-сервера и портов (не нужен входящий доступ на 80/443, меньше конфликтов с прокси и CDN).

Ниже — практическая схема «как в проде»: когда выбирать DNS-01, что именно проверяет ACME, какой клиент взять (certbot/lego/acme.sh), как поставить продление на systemd timer, подключить deploy-hook и безопасно развозить сертификаты по узлам через rsync по SSH, не размножая DNS API-токены.

Когда выбирать DNS-01, а когда проще HTTP-01

DNS-01 имеет смысл, если выполняется хотя бы один пункт:

  • нужен wildcard для множества поддоменов (мультисайты, динамические окружения, preview-стенды);
  • сервер в приватной сети, за NAT, или входящие 80/443 закрыты политиками;
  • на фронте стоит CDN/защитный прокси, который усложняет HTTP-01;
  • сертификат нужен не для веба (SMTP/IMAP, внутренние API, балансировщик), где HTTP-челлендж неуместен.

Минусы у DNS-01 тоже честные:

  • нужен доступ к управлению DNS и желательно API для полной автоматизации;
  • распространение DNS может замедлять выпуск и продление;
  • появляются секреты (API-токены), за которыми нужно следить.

Практическое правило: если у вас один сайт и открыты 80/443 — HTTP-01 часто проще. Если нужен wildcard или сеть «сложная» — DNS-01 почти всегда лучший выбор.

Как работает DNS-01: что именно проверяет ACME

Let’s Encrypt попросит создать TXT-запись вида:

_acme-challenge.example.comслучайная-строка

Для wildcard имя записи то же, но значение будет другим. ACME-клиент создаёт запись (через API или вручную), ждёт распространения DNS и только затем CA проверяет наличие TXT и выдаёт сертификат.

Из этого следуют две практические проверки, которые экономят время:

  • у зоны должны быть корректные SOA/NS, а домен реально делегирован на те NS, которые вы редактируете;
  • учитывайте TTL и кеширующие резолверы: «добавил TXT и сразу проверяю» часто ломается из-за кеша и негативного кеширования.

Если вы строите корпоративную схему (несколько сертификатов, лимиты, staging, отчётность), полезно заранее учесть политику CA: лимиты Let’s Encrypt и стратегия выпуска и продления.

Создание TXT-записи _acme-challenge для проверки DNS-01

Если домен ещё не зарегистрирован или нужно перенести зону к удобному управлению, заранее закройте вопрос с DNS: регистрация доменов помогает быстро оформить домен и дальше спокойно автоматизировать DNS-01.

Выбор клиента: certbot vs lego vs acme.sh

С точки зрения эксплуатации выбирать стоит не «самый модный», а тот, который лучше ложится в вашу операционку, мониторинг и подход к секретам.

Certbot: привычный стек и deploy-hook

certbot удобен, если он уже стандартизирован в инфраструктуре и вы хотите опираться на знакомые механики certbot renew и --deploy-hook. Для DNS-01 обычно используют DNS-плагины провайдера или сценарии через RFC2136/acme-dns.

Плюс certbot — в «ожидаемой» структуре каталогов: актуальные файлы доступны в /etc/letsencrypt/live/… (через симлинки), а deploy-hook запускается только при реальном обновлении сертификата.

Lego: минимализм и удобство для CI/контейнеров

lego — быстрый single-binary клиент. Хорошо подходит для контейнеров, CI/CD и «чистых» серверов, где не хочется тащить зависимости. Многие DNS-провайдеры поддерживаются через переменные окружения и понятные флаги.

На практике lego часто выбирают для выпуска wildcard и последующего деплоя на N узлов, потому что его легко «вшить» в systemd-юниты и простые скрипты.

acme.sh: максимум DNS API и гибкие хуки

acme.sh — shell-клиент с очень широким набором DNS API. У него своя логика установки, обновлений и экспорта сертификатов под разные сервисы.

Важный момент: заранее решите, где и как вы будете хранить DNS-секреты. Вариант «положить токен в .bashrc» на сервере почти гарантированно приводит к утечкам через историю, бэкапы и права доступа.

FastFox SSL
Надежные SSL-сертификаты
Мы предлагаем широкий спектр SSL-сертификатов от GlobalSign по самым низким ценам. Поможем с покупкой и установкой SSL бесплатно!

Выпуск wildcard через DNS-01: базовый шаблон

Цель типовая: закрыть корневой домен и все поддомены одним сертификатом. Стандартный набор имён:

  • example.com
  • *.example.com

Нюанс эксплуатации: один wildcard или несколько сертификатов

Здесь нет «единственно правильного» ответа — выбирайте по модели рисков и процессам:

  • Один wildcard на всё: меньше сущностей и проще сопровождение, но выше «радиус поражения» при компрометации ключа.
  • Несколько сертификатов по группам: сложнее управлять, но проще ротация и лучше сегментация доступа (особенно при деплое на разные узлы и команды).

Если сертификаты «разъезжаются» по нескольким серверам и окружениям, чаще выигрывает схема «несколько сертификатов по зонам ответственности», а не один wildcard «на всё».

Разбор практической автоматизации именно под wildcard и DNS-01 — в отдельной заметке: автоматизация wildcard через DNS-01.

Автопродление: почему systemd timer часто лучше cron

С DNS-01 критично, чтобы продление было «тихим» и наблюдаемым: с логами, понятными ошибками, предсказуемым расписанием и без зависимости от пользовательского окружения.

systemd timer обычно удобнее cron, потому что даёт:

  • журналирование в journald (быстрая отладка через journalctl);
  • гибкие расписания и случайный сдвиг (RandomizedDelaySec), чтобы не упираться в лимиты;
  • простую проверку статуса и последнего запуска.

Пример: systemd unit для renew + deploy

Идея: отдельный сервис, который запускает продление и затем выполняет деплой. Команды ниже — каркас; подставьте ваш клиент и пути.

[Unit]
Description=ACME renew and deploy certificates
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
User=root
Group=root
ExecStart=/usr/local/sbin/acme-renew.sh

Timer — ежедневно (или дважды в день) с рандомизацией:

[Unit]
Description=Run ACME renew daily

[Timer]  03:15:00
RandomizedDelaySec=45m
Persistent=true

[Install]
WantedBy=timers.target

Проверка состояния и логов:

systemctl daemon-reload
systemctl enable --now acme-renew.timer
systemctl list-timers --all | grep acme-renew
journalctl -u acme-renew.service -n 200 --no-pager

Certbot deploy-hook: правильная точка для reload и доставки

certbot --deploy-hook запускается только когда сертификат реально обновился. Это важнее, чем кажется: вы не хотите перезагружать nginx/postfix каждый день без смысла и уж тем более «пушить» одинаковые файлы на десяток серверов.

Типовой поток выглядит так:

  • по таймеру запускается certbot renew;
  • если есть обновление — срабатывает deploy-hook;
  • hook делает экспорт в отдельный каталог, проверку и доставку;
  • на целевых узлах выполняется мягкий reload сервиса.

Скелет deploy-hook: экспорт в отдельный каталог

В hook обычно приходят переменные окружения RENEWED_LINEAGE и RENEWED_DOMAINS. Логика простая: взять fullchain.pem и privkey.pem, сложить в отдельный каталог, выставить права, затем вызвать деплой.

#!/bin/sh
set -eu

LINEAGE="${RENEWED_LINEAGE:-}"
if [ -z "$LINEAGE" ]; then
  echo "RENEWED_LINEAGE is empty" 1>&2
  exit 1
fi

SRC_FULLCHAIN="$LINEAGE/fullchain.pem"
SRC_PRIVKEY="$LINEAGE/privkey.pem"

DST_DIR="/var/lib/acme/export/example"
install -d -m 0750 "$DST_DIR"
install -m 0644 "$SRC_FULLCHAIN" "$DST_DIR/fullchain.pem"
install -m 0600 "$SRC_PRIVKEY" "$DST_DIR/privkey.pem"

/usr/local/sbin/acme-push-rsync.sh "$DST_DIR"

Почему не копировать напрямую из /etc/letsencrypt/live на удалённые узлы? Потому что там симлинки, и при неудачном тайминге можно поймать состояние «между файлами». Экспорт в отдельный каталог проще сделать предсказуемым и проверяемым (и при желании — атомарным через staging-директорию и mv).

Деплой на несколько серверов: rsync по SSH без сюрпризов

Если фронтенд один — часто хватает локального reload. Но wildcard обычно нужен для нескольких узлов (балансировка, отдельные сервисы, разные окружения). Практичная модель: один узел выпуска (issuer), много узлов потребления (consumers).

Идея: один узел выпуска, токены DNS только там

Выпускайте сертификаты на одном защищённом узле, где лежат DNS API-токены. Дальше раскатывайте сертификаты на потребителей по SSH. Так вы минимизируете число мест, где хранится доступ к DNS-зоне.

Пример rsync по SSH с отдельным ключом

На issuer заведите отдельный SSH-ключ только для доставки. На стороне получателя лучше использовать отдельного пользователя (например, acme) и ограничить его права на запись конкретным каталогом.

rsync -a --delete -e "ssh -i /root/.ssh/acme_deploy -o IdentitiesOnly=yes" /var/lib/acme/export/example/ acme@web-01:/etc/ssl/acme/example/
rsync -a --delete -e "ssh -i /root/.ssh/acme_deploy -o IdentitiesOnly=yes" /var/lib/acme/export/example/ acme@web-02:/etc/ssl/acme/example/

На получателях после доставки — проверка и мягкий reload. Для nginx это обычно так:

nginx -t
systemctl reload nginx

Если вы разворачиваете веб-проекты на виртуальном хостинге, чаще проще использовать встроенную инфраструктуру управления сертификатами. А когда у вас несколько ролей и нод и нужны свои хуки — удобнее схема с отдельным issuer на VDS.

Деплой сертификатов на несколько серверов через rsync по SSH

Secret management: где хранить DNS-токены и ключи деплоя

Главная ошибка в DNS-01 — «токен лежит в скрипте» или «токен глобально в переменных окружения». В проде это часто заканчивается утечками через бэкапы, историю shell или неаккуратные права.

Минимально безопасный уровень (подходит большинству небольших проектов)

  • по возможности выделите отдельного системного пользователя под ACME-операции;
  • храните секреты в отдельном файле с правами 0600 и владельцем root;
  • подключайте секреты в systemd через EnvironmentFile;
  • SSH-ключ для деплоя держите отдельным и не используйте для интерактивного входа.

Пример: EnvironmentFile для systemd

Файл /etc/acme/acme.env (права 0600):

DNS_API_TOKEN=change_me
DNS_API_SECRET=change_me

Подключение в unit:

[Service]
Type=oneshot
EnvironmentFile=/etc/acme/acme.env
ExecStart=/usr/local/sbin/acme-renew.sh

Если вы деплоите сертификаты на несколько машин, не размножайте DNS API-токены. Пусть токен будет только на узле выпуска, а на потребителях — только файлы сертификата и приватный ключ.

Проверки и отладка: где чаще всего ломается DNS-01

TXT появился не там

Проверьте, что запись создаётся именно для _acme-challenge нужного домена, и что вы меняете зону, которая реально делегирована. Типичная ошибка — когда «DNS у регистратора» и «внешний DNS» используются параллельно.

Не дождались распространения DNS

Даже при маленьком TTL кеш резолверов и негативное кеширование могут мешать. В клиентах часто есть параметр ожидания. Если пишете свои хуки — закладывайте паузу и контроль наличия TXT перед продолжением.

Слишком частые попытки и лимиты

У Let’s Encrypt есть лимиты на выпуск. Для тестов используйте staging-режим вашего клиента. В проде не дергайте выпуск «каждую минуту»: лучше аккуратный таймер и деплой только по факту обновления.

Неправильные права на ключи после деплоя

После rsync легко случайно сделать приватный ключ читаемым лишними пользователями. Держите privkey.pem с правами 0600 и владельцем root. Цепочку fullchain.pem обычно можно хранить более либерально, но без излишеств.

Рекомендованная схема для продакшена: короткий чек-лист

  1. Выберите один узел issuer для выпуска по DNS-01.
  2. Настройте ACME-клиент (certbot/lego/acme.sh) с DNS API и выпуск example.com + *.example.com.
  3. Сделайте экспорт сертификата в отдельный каталог с предсказуемыми правами.
  4. Поставьте продление на systemd timer.
  5. Для certbot используйте deploy-hook, чтобы деплой выполнялся только при обновлении.
  6. Развозите сертификаты через rsync по SSH на узлы-потребители.
  7. На потребителях делайте проверку конфигурации и reload сервиса.
  8. DNS-секреты храните в отдельном файле с правами 0600 (или в вашем secrets-хранилище), но не в скриптах и не в глобальном окружении.

Что стоит стандартизировать в команде

DNS-01 живёт годами без боли, если стандартизировать три вещи: (1) где лежат секреты, (2) кто является узлом выпуска, (3) как именно сертификаты доставляются и проверяются на целевых серверах. Остальное — детали выбранного ACME-клиента и вашего DNS-провайдера.

Если вы уже используете certbot — начните с deploy-hook и systemd timer. Если нужен максимально компактный стек — смотрите в сторону lego. Если у вас «зоопарк» DNS-провайдеров и важен широкий выбор DNS API — часто выигрывает acme.sh.

FastFox VDS
Регистрация доменов от 99 руб.
Каждый проект заслуживает идеального доменного имени, выберите один из сотни, чтобы начать работу!
Поделиться статьей

Вам будет интересно

Debian/Ubuntu: mount: wrong fs type, bad option, bad superblock — как быстро найти и исправить причину OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: mount: wrong fs type, bad option, bad superblock — как быстро найти и исправить причину

Ошибка mount: wrong fs type, bad option, bad superblock в Debian/Ubuntu может означать и простую опечатку в имени раздела, и пробл ...
Debian/Ubuntu: XFS metadata corruption и emergency read-only — пошаговое восстановление OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: XFS metadata corruption и emergency read-only — пошаговое восстановление

Если XFS-раздел внезапно стал доступен только для чтения, а сервер ушёл в emergency mode, главное — не спешить. Разберём безопасны ...
Debian/Ubuntu: как исправить Failed to fetch при apt update OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: как исправить Failed to fetch при apt update

Ошибка Failed to fetch при apt update в Debian и Ubuntu обычно связана не с самим APT, а с DNS, сетью, зеркалом, прокси, временем ...