Звичайний HTTP-challenge для Let's Encrypt не підтримує Wildcard-сертифікати (*.example.com). Для Wildcard потрібен DNS-01 challenge — підтвердження через TXT-запис у DNS.
Як працює DNS-01 challenge
- Certbot запитує сертифікат у Let's Encrypt
- Let's Encrypt видає випадковий токен
- Certbot просить додати TXT-запис:
_acme-challenge.example.com - Let's Encrypt перевіряє TXT-запис через DNS
- Сертифікат видається
Вручну через certbot
# Запит Wildcard-сертифіката
certbot certonly --manual --preferred-challenges dns -d "*.example.com" -d "example.com"
# Certbot покаже TXT-запис для додавання:
# _acme-challenge.example.com. 300 IN TXT "TOKEN"
# Додайте запис у DNS, потім натисніть Enter
# Сертифікат буде в /etc/letsencrypt/live/example.com/
Автоматично через acme.sh + Cloudflare API
># Встановлення acme.sh
curl https://get.acme.sh | sh
# Налаштування Cloudflare API
export CF_Token="YOUR_CLOUDFLARE_API_TOKEN"
export CF_Account_ID="YOUR_ACCOUNT_ID"
# Випуск Wildcard-сертифіката
~/.acme.sh/acme.sh --issue --dns dns_cf -d "*.example.com" -d "example.com" --keylength ec-256
# Встановлення в Nginx
~/.acme.sh/acme.sh --install-cert -d "*.example.com" --key-file /etc/nginx/ssl/example.key --fullchain-file /etc/nginx/ssl/example.crt --reloadcmd "systemctl reload nginx"
Підтримувані DNS-провайдери в acme.sh
acme.sh підтримує автоматичне оновлення через API понад 100 DNS-провайдерів: Cloudflare, Route 53, DigitalOcean, Namecheap, Google Cloud DNS та інші.
Альтернатива acme.sh: certbot із плагіном certbot-dns-cloudflare
Якщо звичніше працювати через certbot, а не через acme.sh, DNS-01 для Cloudflare доступний через офіційний плагін — не потрібно вручну писати скрипт із curl-запитами до API.
# Встановлення плагіна
apt install python3-certbot-dns-cloudflare -y
# Файл із токеном, права мають бути 600
echo "dns_cloudflare_api_token = YOUR_TOKEN" > /root/.secrets/cloudflare.ini
chmod 600 /root/.secrets/cloudflare.ini
# Випуск Wildcard-сертифіката
certbot certonly --dns-cloudflare \
--dns-cloudflare-credentials /root/.secrets/cloudflare.ini \
-d "*.example.com" -d "example.com"
certbot сам додає і видаляє TXT-запис через API, чекає поширення і вміє продовжувати сертифікат по cron без додаткових скриптів поверх acme.sh.
Типові помилки DNS-01 challenge
| Повідомлення | Причина |
|---|---|
| DNS problem: NXDOMAIN looking up TXT | TXT-запис не додано взагалі або додано в зоні іншого домену чи піддомену |
| DNS problem: query timed out | Занадто великий TTL у зоні або локальний резолвер ще не побачив зміну — потрібно почекати поширення запису |
| CF_Token: command not found | Змінні середовища CF_Token і CF_Account_ID не експортовані в поточній сесії — забутий export або скрипт запущено з cron без них |
| Multiple validation errors: unauthorized | Стара TXT-запис від попередньої спроби не видалена; DNS повернув одразу кілька записів _acme-challenge, а Let's Encrypt перевіряє лише один |
| Verify error при коректному TXT-записі | Запис ще не розійшовся по всіх авторитетних NS-серверах — acme.sh не почекав достатньо, потрібно збільшити --dnssleep |
Коли DNS-challenge не підходить
- Потрібен сертифікат на один конкретний піддомен без wildcard — звичайний HTTP-01 challenge через certbot --nginx простіший і не потребує доступу до DNS API
- DNS керується реєстратором без API або API недоступне в acme.sh — вручну оновлювати TXT-запис перед кожним продовженням непрактично і ризикує пропустити строк
- Сертифікат потрібно отримати миттєво, за секунди — DNS-01 завжди чекає поширення запису, щонайменше десятки секунд, а часто і хвилини
- Потрібен сертифікат для голої IP-адреси — Let's Encrypt не видає сертифікати на IP ні через HTTP-, ні через DNS-challenge
Перевірка результату
Перш ніж натискати Enter у certbot або чекати на відповідь acme.sh, переконайтеся, що запис справді видно публічному DNS — це заощаджує час на повторні спроби. Деталі продовження і автопролонгації — у статтях про налаштування certbot для wildcard та про автопролонгацію Let's Encrypt.
# Перевірити, що TXT-запис справді видно публічному DNS
dig +short TXT _acme-challenge.example.com @8.8.8.8
# Перевірити термін дії вже виданого сертифіката
openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -noout -enddate