Wildcard-сертификат: когда он нужен, чем опасен и как выпустить через Let's Encrypt по DNS-01
15 мин чтения
Wildcard-сертификат: когда он нужен, чем опасен и как выпустить через Let's Encrypt по DNS-01

Wildcard-сертификат: когда он нужен, чем опасен и как выпустить через Let's Encrypt по DNS-01

Один сертификат на все поддомены звучит удобно, пока не выясняется, что он не покрывает сам домен и второй уровень вложенности, а при утечке единственного ключа менять придётся всё сразу. Разбираем по RFC 9525 и требованиям CA/Browser Forum, что закрывает звёздочка, когда выгоднее SAN, почему Let's Encrypt выдаёт wildcard только по DNS-01 и какие российские DNS поддержаны в acme.sh.

Wildcard-сертификат — TLS-сертификат, в котором имя записано со звёздочкой вместо первой метки (*.example.ru), и который поэтому подходит для любого поддомена ровно одного уровня: shop.example.ru, api.example.ru, любой-новый.example.ru. Он не покрывает сам example.ru (его добавляют в сертификат отдельным именем) и не покрывает поддомены глубже — a.b.example.ru под *.example.ru не подходит. Публичные wildcard-сертификаты подтверждаются только через DNS: УЦ требует доказать контроль над зоной, а не над одним веб-сервером.

Что покрывает *.example.ru, а что нет

Звёздочка заменяет ровно одну DNS-метку, и только самую левую. Так требует RFC 9525 (ноябрь 2023 года, заменил RFC 6125): в имени допустим один wildcard-символ, он должен быть целой левой меткой и совпадает только с одной меткой проверяемого имени. Всё остальное клиент обязан игнорировать.

На практике: apex под звёздочку не попадает — его добавляют отдельным SAN-именем; второй уровень вложенности не попадает — для *.dev.example.ru нужен отдельный wildcard; частичные шаблоны вроде f*.example.ru RFC 6125 ещё допускал, RFC 9525 объявил невалидными, а публичные УЦ их и раньше не выпускали — по Baseline Requirements Wildcard Domain Name это строго «*.» плюс полное имя.

Имя в браузере Покрыт сертификатом на *.example.ru? Почему
shop.example.ru Да Одна метка на месте звёздочки
www.example.ru Да www — обычная метка, исключений для неё нет
example.ru Нет Звёздочке нечего заменять; нужен отдельный SAN example.ru
a.b.example.ru Нет Wildcard совпадает только с одной меткой, здесь их две
api.dev.example.ru Нет Нужен второй wildcard *.dev.example.ru

Типовой состав wildcard-сертификата — два имени в SAN: DNS:*.example.ru, DNS:example.ru. В один сертификат Let's Encrypt помещает до 100 имён (профиль classic), так что несколько wildcard-имён — *.example.ru и *.stage.example.ru — укладываются свободно.

Wildcard, SAN или отдельные сертификаты: что выбрать

Wildcard оправдан, когда поддомены появляются без вашего участия: тенанты SaaS, превью-окружения на каждую ветку, стенды разработчиков. Если список хостов известен и меняется раз в месяц, SAN-сертификат даёт тот же один файл на всех серверах, но не вручает «мастер-ключ» от всей зоны. Отдельный сертификат на каждый хост — самый безопасный вариант; с ACME-клиентом разница в трудозатратах стремится к нулю, и решающим становится радиус поражения при утечке ключа.

Критерий Wildcard (*.example.ru + example.ru) SAN / multi-domain Отдельный на каждый хост
Поддомены неизвестны заранее Да, новый хост первого уровня работает сразу Нет, каждое новое имя — перевыпуск Нет, каждое новое имя — новый выпуск
Подтверждение в Let's Encrypt Только DNS-01 HTTP-01, TLS-ALPN-01 или DNS-01 HTTP-01, TLS-ALPN-01 или DNS-01
Стоимость В Let's Encrypt бесплатно; у коммерческих УЦ дороже одиночного Бесплатно, до 100 имён в сертификате Бесплатно, лимит 50 сертификатов на домен в неделю
Радиус поражения при утечке ключа Вся зона, включая будущие поддомены Все имена из списка Один хост
Отзыв Бьёт по всем сервисам сразу По всем именам в сертификате Локальный
EV-валидация Запрещена EV Guidelines Возможна у коммерческих УЦ Возможна у коммерческих УЦ

Правило: wildcard — для динамических поддоменов за одним TLS-терминатором, SAN — для фиксированного набора хостов на одном сервере, отдельные — для разных машин. Базовый выпуск по HTTP-01 разобран в статье про Let's Encrypt; дальше речь только о wildcard.

Чем опасен wildcard: один ключ на всю зону

Главный риск — не сертификат, а закрытый ключ, который приходится копировать на каждый сервер зоны. Утечка с самого слабого из них (забытый стенд, сервер подрядчика, бэкап без шифрования) даёт злоумышленнику валидный TLS для любого имени зоны, включая хосты, которых у вас ещё нет. RFC 9525 предупреждает прямо: wildcard-сертификат «автоматически ручается за все хосты домена», и компрометация любого из них компрометирует остальные.

Второй риск — отзыв: при утечке недоступными становятся все сервисы сразу. Третий — ограничения снаружи. EV-сертификаты с wildcard не выпускаются в принципе: EV Guidelines CA/Browser Forum говорят, что «wildcard-символы в доменных именах не допускаются для EV TLS-сертификатов» (исключение только для .onion); Let's Encrypt EV и OV не выдаёт вообще. Отдельные старые клиенты и встроенные устройства не понимают звёздочку — при интеграциях это стоит проверить.

Wildcard не заменяет инвентаризацию поддоменов

Забытый поддомен со старым приложением останется «зелёным» в браузере и невидимым в CT-логах. Без отдельного списка хостов ни отзыв, ни ротация ключа не будут полными.

Почему Let's Encrypt выдаёт wildcard только по DNS-01

HTTP-01 доказывает контроль над одним веб-сервером на порту 80, а wildcard утверждает контроль над всеми будущими именами зоны. Документация Let's Encrypt формулирует жёстко: HTTP-01 «не может использоваться для выпуска wildcard-сертификатов», TLS-ALPN-01 — тоже, и только DNS-01 «позволяет выпускать сертификаты с wildcard-именами». Это общее правило: бюллетень SC45 CA/Browser Forum с 1 декабря 2021 года запретил HTTP-методы валидации для wildcard всем публичным УЦ.

Механика DNS-01: клиент получает от УЦ токен, вычисляет из него и ключа аккаунта значение и публикует его в TXT-записи _acme-challenge.example.ru. Для пары «*.example.ru + example.ru» нужны два разных TXT-значения на одном имени одновременно. CNAME с _acme-challenge на отдельную зону (например, acme-dns) — легальный способ не давать ACME-клиенту доступ к основной зоне; как устроены TXT и CNAME, напоминает статья о типах DNS-записей. Цена метода — ключи от DNS на сервере продления; Let's Encrypt называет это минусом прямо: «хранить учётные данные API на веб-сервере рискованно».

Какие DNS-провайдеры поддержаны в certbot и acme.sh

У certbot 13 официальных DNS-плагинов, и российских среди них нет: cloudflare, digitalocean, dnsimple, dnsmadeeasy, gehirn, google, linode, luadns, nsone, ovh, rfc2136, route53, sakuracloud. Для российских DNS основной инструмент — acme.sh: в его wiki dnsapi нумерация хуков на сентябрь 2026 года доходит до 228, среди них Selectel, Yandex Cloud, Timeweb Cloud, Reg.ru, Beget, NIC.RU и Yandex 360 (старый хук dns_yandex для pdd.yandex.ru не работает).

DNS-провайдер certbot acme.sh, хук Переменные окружения
Selectel Нет dns_selectel SL_Ver=v2, SL_Login_ID, SL_Project_Name, SL_Login_Name, SL_Pswd (v1 с SL_Key устарел)
Yandex Cloud DNS Нет dns_yc YC_Folder_ID, YC_SA_ID, YC_SA_Key_ID, YC_SA_Key_File_Path (роль dns.editor)
Timeweb Cloud Нет dns_timeweb TW_Token (JWT из панели)
Reg.ru Нет dns_regru REGRU_API_Username, REGRU_API_Password; IP сервера — в белый список API
Beget Нет dns_beget BEGET_User, BEGET_Password
NIC.RU Нет dns_nic NIC_ClientID, NIC_ClientSecret, NIC_Username, NIC_Password
Cloudflare certbot-dns-cloudflare dns_cf CF_Token с правом Zone:DNS:Edit на одну зону, CF_Account_ID

Если провайдера нет ни в одном списке (типично для DNS «в комплекте» с хостингом), варианта три: делегировать _acme-challenge через CNAME в зону с API, перенести зону целиком или обновлять TXT руками каждые 60 дней.

Как выпустить wildcard в certbot: ручной режим и DNS-плагин

Ручной режим (--manual) годится для первого выпуска, но не продлевается сам: по документации certbot такие сертификаты «не поддерживают автоматическое продление без скрипта аутентификации» (--manual-auth-hook). Wildcard в certbot поддерживается с версии 0.22.0 — с марта 2018 года, когда Let's Encrypt запустил ACMEv2.

# Ручной режим: certbot попросит создать TXT-записи и подождёт
sudo certbot certonly --manual --preferred-challenges dns \
  -d '*.example.ru' -d example.ru

# пример вывода (сокращён)
Please deploy a DNS TXT record under the name:
_acme-challenge.example.ru.
with the following value:
Kq3nT9xY0cJ2mVb8fH1rWZa6LpUeD4sG7oNiB5tRkXw
Before continuing, verify the TXT record has been deployed.

# Второе имя даст второе значение для ТОГО ЖЕ имени — обе записи
# должны существовать одновременно. Проверить перед Enter:
dig +short TXT _acme-challenge.example.ru @ns1.example-dns.ru

Автоматический путь — DNS-плагин. Для Cloudflare это пакет certbot-dns-cloudflare: файл с токеном обязан иметь права 600, а пауза на распространение записи по умолчанию 10 секунд — для медленных зон её поднимают до 60–120.

# Токен Cloudflare с правом Zone:DNS:Edit на одну зону
printf 'dns_cloudflare_api_token = <токен>\n' \
  | sudo tee /root/.secrets/certbot/cloudflare.ini
sudo chmod 600 /root/.secrets/certbot/cloudflare.ini

sudo certbot certonly --dns-cloudflare \
  --dns-cloudflare-credentials /root/.secrets/certbot/cloudflare.ini \
  --dns-cloudflare-propagation-seconds 60 \
  -d '*.example.ru' -d example.ru \
  --deploy-hook 'systemctl reload nginx'

Перезагрузку nginx вешают на --deploy-hook, а не на код выхода: certbot renew возвращает 0 и тогда, когда продлевать было нечего.

Как выпустить wildcard в acme.sh с российским DNS

acme.sh — shell-скрипт без зависимостей, хуки под Selectel, Yandex Cloud и Timeweb идут в комплекте. Две вещи, о которые спотыкаются: по умолчанию acme.sh (версия 3.1.6 на сентябрь 2026 года) заказывает сертификат у ZeroSSL, поэтому Let's Encrypt указывают явно через --server letsencrypt; учётные данные нужны только при первом выпуске — скрипт сохраняет их в ~/.acme.sh/account.conf.

# Установка (ставит cron-задачу на ежедневную проверку продлений)
curl https://get.acme.sh | sh -s email=admin@example.ru

# Selectel, API v2: сервисный пользователь проекта
export SL_Ver="v2" SL_Login_ID="123456" SL_Project_Name="dns-acme"
export SL_Login_Name="acme-user" SL_Pswd="<пароль>"
acme.sh --issue --server letsencrypt --dns dns_selectel \
  -d example.ru -d '*.example.ru'

# Yandex Cloud DNS: сервисный аккаунт с ролью dns.editor
export YC_Folder_ID="b1g..." YC_SA_ID="aje..." YC_SA_Key_ID="ajk..."
export YC_SA_Key_File_Path="/root/.yc/private.key"
acme.sh --issue --server letsencrypt --dns dns_yc \
  -d example.ru -d '*.example.ru'

# Timeweb: export TW_Token="..." и --dns dns_timeweb по той же схеме,
# Cloudflare: CF_Token, CF_Account_ID и --dns dns_cf

# Положить файлы в nginx и перезагружать его после каждого продления
acme.sh --install-cert -d example.ru \
  --key-file       /etc/nginx/ssl/example.ru.key \
  --fullchain-file /etc/nginx/ssl/example.ru.crt \
  --reloadcmd      "systemctl reload nginx"

Если серверы провайдера обновляются медленно и проверка падает на TXT-записи, добавьте --dnssleep 120: acme.sh не будет опрашивать публичные резолверы, а просто подождёт указанное число секунд.

Зачем wildcard-домену запись CAA

CAA — DNS-запись со списком удостоверяющих центров, которым разрешено выпускать сертификаты на домен; Let's Encrypt проверяет её перед каждым выпуском. Для wildcard есть отдельный тег issuewild: если он задан, для *.example.ru действует он, а не issue — так можно разрешить wildcard только одному УЦ и только по DNS-01.

; Зона example.ru
example.ru.  CAA 0 issue     "letsencrypt.org"
example.ru.  CAA 0 issuewild "letsencrypt.org; validationmethods=dns-01"
example.ru.  CAA 0 iodef     "mailto:security@example.ru"

# Проверить, что записи видны снаружи
dig +short CAA example.ru

УЦ ищет CAA снизу вверх — от запрошенного имени к родительским — и останавливается на первой найденной записи, поэтому CAA на example.ru покрывает и *.example.ru, и поддомены без собственной записи.

Сколько живёт сертификат и когда продлевать

Wildcard от Let's Encrypt живёт 90 дней в профиле classic, 45 дней в tlsserver и 160 часов в shortlived — столько же, сколько обычный сертификат. Let's Encrypt рекомендует продлевать, когда осталась треть срока, то есть на 60-й день; клиенты с поддержкой ARI (RFC 9773; в acme.sh включена без флагов) получают окно продления от самого УЦ.

У коммерческих УЦ сроки сокращаются по расписанию бюллетеня SC-081v3 CA/Browser Forum (принят в апреле 2025 года): 398 дней до 15 марта 2026 года, затем 200, с 15 марта 2027 года — 100, с 15 марта 2029 года — 47 дней. Параллельно сокращается срок переиспользования подтверждения контроля над доменом: 200, 100 и 10 дней. При 10 днях ручной wildcard практически невозможен.

Кто и когда Максимальный срок Переиспользование DNS-валидации Что это значит для wildcard
Let's Encrypt, classic 90 дней Авторизация — 30 дней Продление на 60-й день; в ручном режиме — 6 раз в год руками
Let's Encrypt, shortlived 160 часов Авторизация — 7 часов Продление каждые 3 дня; такому сертификату по BR не нужна информация об отзыве
Коммерческие УЦ с 15.03.2026 (сейчас) 200 дней 200 дней Два выпуска в год вместо одного (398 дней до этой даты)
С 15.03.2027 100 дней 100 дней Четыре выпуска в год, каждый с новой DNS-валидацией
С 15.03.2029 47 дней 10 дней Только полная автоматизация DNS-01

Что ломается при смене DNS-провайдера

Продление wildcard зависит не от веб-сервера, а от API DNS, поэтому переезд зоны ломает его тихо: сертификат работает ещё до 60 дней, cron запускается и падает на TXT-записи, а заметно это становится по истечении срока. Типовой сценарий — сменили регистратора или хостинг, переключили NS, а в ~/.acme.sh/account.conf или /root/.secrets остались токены старого провайдера.

Чек-лист переезда: перенести CAA-записи (новые панели часто их не импортируют, и выпуск падает с ошибкой CAA), переписать хук и учётные данные, перевыпустить сертификат сразу после переключения NS, убрать старые TXT _acme-challenge — Let's Encrypt советует чистить их, чтобы ответ не разрастался. Если _acme-challenge делегирован через CNAME в отдельную зону, переезд основной зоны его не затрагивает — главный аргумент за такую схему.

Где хранить один ключ на много серверов

Одна пара «ключ + цепочка» должна оказаться на всех серверах зоны и обновляться там каждые 60 дней синхронно. Чем меньше копий ключа, тем меньше радиус поражения — лучшее место для wildcard-ключа то, откуда его не нужно копировать.

Схема Копий ключа Как доставляется продление Когда подходит
Выпуск на каждом сервере независимо По одной на сервер, ключи разные Каждый сервер сам ходит в DNS API и ACME 2–5 серверов; токен DNS на каждом, лимит 5 дубликатов в неделю
Выпуск на одной машине, копирование по SSH N + 1 --deploy-hook или --reloadcmd с rsync и reload на приёмниках Небольшой парк с единым SSH-доступом; токен DNS на одной машине
Центральный TLS-терминатор (nginx, HAProxy, Envoy) 1–2 Продление только на терминаторах; бэкенды — по HTTP или внутреннему CA Основной вариант: ключ не покидает периметр
Управляемый балансировщик или CDN с ACME 0 у вас Провайдер выпускает и продлевает сам Когда допустимо доверить ключ провайдеру

Как проверить, что wildcard отдаётся правильно

Проверять нужно каждый поддомен с указанием SNI: без -servername сервер может отдать сертификат по умолчанию. Смотрите на Subject Alternative Name (там должны быть и *.example.ru, и example.ru) и на Verify return code.

# Какой сертификат отдаётся для конкретного поддомена
openssl s_client -servername shop.example.ru \
  -connect shop.example.ru:443 </dev/null 2>/dev/null \
  | openssl x509 -noout -dates -ext subjectAltName
# пример вывода
notBefore=Sep  2 07:14:51 2026 GMT
notAfter=Dec  1 07:14:50 2026 GMT
X509v3 Subject Alternative Name:
    DNS:*.example.ru, DNS:example.ru

# Имя второго уровня wildcard не покроет — это ожидаемая ошибка
openssl s_client -servername a.b.example.ru -connect example.ru:443 \
  -verify_hostname a.b.example.ru </dev/null 2>/dev/null \
  | grep 'Verify return code'
# пример вывода
Verify return code: 62 (hostname mismatch)

Полный разбор ручной проверки — в статье как проверить SSL-сертификат сайта. В nginx один wildcard-сертификат обслуживает сколько угодно server-блоков, а поддомены в server_name можно задать регулярным выражением:

# /etc/nginx/conf.d/example.ru.conf
server {
    listen 443 ssl;
    http2 on;
    # поддомены — регулярным выражением, apex и www — в своём блоке
    server_name ~^(?<tenant>[a-z0-9-]+)\.example\.ru$;
    ssl_certificate     /etc/nginx/ssl/example.ru.crt;
    ssl_certificate_key /etc/nginx/ssl/example.ru.key;
    root /var/www/tenants/$tenant;
}

nginx -t && systemctl reload nginx

Как выпустить wildcard через certbot и DNS-01

  1. Убедитесь, что у DNS-провайдера есть API и под него есть плагин certbot или хук acme.sh; если нет — делегируйте _acme-challenge.example.ru через CNAME в зону с API.
  2. Создайте токен с минимальными правами: только редактирование DNS одной зоны (в Cloudflare — Zone:DNS:Edit, в Yandex Cloud — сервисный аккаунт с ролью dns.editor).
  3. Добавьте в зону CAA-записи issue и issuewild с letsencrypt.org, чтобы никакой другой УЦ не мог выпустить wildcard на ваш домен.
  4. Установите certbot и DNS-плагин (например, python3-certbot-dns-cloudflare), положите учётные данные в файл с правами 600.
  5. Запустите certbot certonly с плагином и двумя именами: -d '*.example.ru' -d example.ru; для медленного DNS поднимите --dns-*-propagation-seconds до 60–120.
  6. Проверьте результат: openssl x509 -ext subjectAltName на /etc/letsencrypt/live/example.ru/fullchain.pem покажет оба имени.
  7. Подключите сертификат в nginx, добавьте --deploy-hook 'systemctl reload nginx' и выполните certbot renew --dry-run — продление должно пройти без человека.
  8. Поставьте внешний мониторинг срока действия на каждый публичный поддомен: продление могло пройти, а копия на одном из серверов — нет.

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

Один сертификат — много точек отказа

Пруфен выполняет SSL- и DNS-проверки из 20 точек мониторинга в России, Беларуси, Казахстане и Испании и уведомляет в Email, Telegram или Макс, когда сертификат на любом из поддоменов подходит к концу срока или перестал проходить проверку; если ресурс так и не поднялся, подключается голосовой звонок. Бесплатного плана на 5 проверок хватает на основной домен и четыре поддомена.

Частые вопросы

Покрывает ли wildcard сам домен второго уровня, то есть example.ru?

Нет. По RFC 9525 звёздочка должна заменить ровно одну метку, а у example.ru слева от зоны меток нет. Поэтому wildcard почти всегда выпускают с двумя именами в SAN: *.example.ru и example.ru — в certbot и acme.sh это два флага -d в одной команде.

Можно ли одним wildcard закрыть несколько уровней поддоменов?

Нет: *.example.ru совпадает только с одной меткой, а a.b.example.ru содержит две. Двойная звёздочка (*.*.example.ru) стандартом запрещена. Решение — добавить в тот же сертификат второй wildcard, например *.dev.example.ru: каждое wildcard-имя считается одним из 100 допустимых.

Как получить wildcard бесплатно?

Через Let's Encrypt по DNS-01: нужен DNS-провайдер с API и клиент под него — certbot с DNS-плагином или acme.sh с хуком (Selectel, Yandex Cloud, Timeweb, Reg.ru, Beget, NIC.RU). Сертификат живёт 90 дней и продлевается автоматически; без API его выдадут и в ручном режиме, но TXT-записи придётся обновлять руками каждые 60 дней.

Почему wildcard продлевался год, а после переезда DNS перестал?

Потому что продление по DNS-01 обращается к API старого провайдера, чьи токены остались в конфигурации клиента, а зона теперь у другого; ошибка не проявляется до планового продления. После переезда перепишите хук, проверьте CAA у нового провайдера и сразу выполните принудительное продление: certbot renew --force-renewal или acme.sh --renew -d example.ru --force.

Была ли статья полезна?

Начните мониторинг прямо сейчас

Бесплатный тариф — до 5 проверок. 150 ₽ на баланс при регистрации.

Создать аккаунт