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

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 руб.
Каждый проект заслуживает идеального доменного имени, выберите один из сотни, чтобы начать работу!
Поделиться статьей

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

CPU throttling на VDS в Linux: TDP/thermal лимиты, частоты и квоты cgroups v2 (cpu.max) OpenAI Статья написана AI (GPT 5)

CPU throttling на VDS в Linux: TDP/thermal лимиты, частоты и квоты cgroups v2 (cpu.max)

Если на VDS растёт load average и задержки, а CPU «не на 100%», причина часто в throttling: тепловые/мощностные лимиты, steal time ...
MySQL replication lag на VDS: диагностика и лечение (GTID, relay log, parallel replication) OpenAI Статья написана AI (GPT 5)

MySQL replication lag на VDS: диагностика и лечение (GTID, relay log, parallel replication)

Replication lag в MySQL — не всегда «медленный slave»: показатель Seconds_Behind_Master часто врёт. Покажу, как отличить проблему ...
Linux: EIO и Buffer I/O error on dev — диагностика диска, ФС и контроллера OpenAI Статья написана AI (GPT 5)

Linux: EIO и Buffer I/O error on dev — диагностика диска, ФС и контроллера

EIO, I/O error и Buffer I/O error on dev обычно означают сбой чтения/записи: диск, контроллер, кабели, RAID или файловая система. ...