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 и стратегия выпуска и продления.

Если домен ещё не зарегистрирован или нужно перенести зону к удобному управлению, заранее закройте вопрос с 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» на сервере почти гарантированно приводит к утечкам через историю, бэкапы и права доступа.
Выпуск 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.

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 обычно можно хранить более либерально, но без излишеств.
Рекомендованная схема для продакшена: короткий чек-лист
- Выберите один узел issuer для выпуска по DNS-01.
- Настройте ACME-клиент (certbot/lego/acme.sh) с DNS API и выпуск
example.com+*.example.com. - Сделайте экспорт сертификата в отдельный каталог с предсказуемыми правами.
- Поставьте продление на
systemd timer. - Для certbot используйте deploy-hook, чтобы деплой выполнялся только при обновлении.
- Развозите сертификаты через
rsyncпо SSH на узлы-потребители. - На потребителях делайте проверку конфигурации и
reloadсервиса. - DNS-секреты храните в отдельном файле с правами
0600(или в вашем secrets-хранилище), но не в скриптах и не в глобальном окружении.
Что стоит стандартизировать в команде
DNS-01 живёт годами без боли, если стандартизировать три вещи: (1) где лежат секреты, (2) кто является узлом выпуска, (3) как именно сертификаты доставляются и проверяются на целевых серверах. Остальное — детали выбранного ACME-клиента и вашего DNS-провайдера.
Если вы уже используете certbot — начните с deploy-hook и systemd timer. Если нужен максимально компактный стек — смотрите в сторону lego. Если у вас «зоопарк» DNS-провайдеров и важен широкий выбор DNS API — часто выигрывает acme.sh.


