Skip to content

Automate Let's Encrypt Wildcard Certs with Certbot and DNS-01 Challenges

Wildcard SSL covers every subdomain under one certificate. Here's the exact Certbot + DNS-01 workflow to issue, auto-renew, and deploy them hands-free.

Written by AISali·August 5, 2026·5 min read
Automate Let's Encrypt Wildcard Certs with Certbot and DNS-01 Challenges

Why Wildcard Certs Beat Per-Subdomain SSL#

If you're running shared hosting or managing dozens of customer sites, juggling individual Let's Encrypt certificates for every subdomain is a maintenance headache. A single wildcard certificate (*.example.com) covers www, mail, cpanel, staging, and every other subdomain your customers dream up — all under one renewal cycle.

The catch: Let's Encrypt only issues wildcards via the DNS-01 challenge, not the HTTP-01 method most one-click installers use. That means your server needs to prove domain ownership by creating a specific TXT record in DNS. Done manually, this is tedious. Automated properly, it's a set-and-forget pipeline.

This guide walks through the exact steps to issue and auto-renew wildcard certs using Certbot and a DNS provider API — no browser clicks, no 90-day panic.

Prerequisites#

Before you start, make sure you have:

  • A Linux server (Ubuntu 22.04/24.04 or Debian 12 recommended)
  • Certbot 2.0+ installed (apt install certbot or via snap)
  • A DNS provider with an API — Cloudflare, DigitalOcean, Hetzner DNS, Route 53, or similar
  • An API token from your DNS provider with permission to create TXT records
  • Root or sudo access on the server

If you're using cPanel or a hosting control panel that manages DNS zones, make sure the domain's authoritative nameservers point to the DNS provider you'll automate against — not to your server's built-in DNS.

Step 1: Install the Certbot DNS Plugin#

Certbot uses provider-specific plugins to handle DNS-01 challenges. Install the one matching your DNS host.

For Cloudflare:

bash
apt install python3-certbot-dns-cloudflare

For DigitalOcean:

bash
apt install python3-certbot-dns-digitalocean

For Hetzner DNS (increasingly popular with EU-based hosts):

bash
pip install certbot-dns-hetzner

For Route 53:

bash
pip install certbot-dns-route53

Verify the plugin loaded:

bash
certbot plugins

You should see your DNS plugin listed in the output.

Step 2: Store Your API Credentials Securely#

Create a credentials file that Certbot will read during challenges. The format varies slightly by provider.

Cloudflare — create /etc/letsencrypt/cloudflare.ini:

ini
dns_cloudflare_api_token = YOUR_API_TOKEN_HERE

DigitalOcean — create /etc/letsencrypt/digitalocean.ini:

ini
dns_digitalocean_token = YOUR_DO_TOKEN_HERE

Hetzner DNS — create /etc/letsencrypt/hetzner.ini:

ini
dns_hetzner_api_token = YOUR_HETZNER_TOKEN

Lock down the file permissions so only root can read it:

bash
chmod 600 /etc/letsencrypt/cloudflare.ini

This is critical. The token grants zone-edit access to your entire DNS account. Treat it like a root password.

Step 3: Issue the Wildcard Certificate#

Now run the actual issuance command. The pattern is the same across providers — just swap the plugin name and credentials path.

For Cloudflare:

bash
certbot certonly \
  --dns-cloudflare \
  --dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
  -d "example.com" \
  -d "*.example.com" \
  --preferred-challenges dns-01

Key details:

  • *Include both `example.com` and `.example.com`** — the wildcard doesn't cover the bare domain.
  • --preferred-challenges dns-01 forces DNS validation. Without it, Certbot may default to HTTP.
  • Certbot will create the _acme-challenge TXT record automatically, wait for DNS propagation, verify, then delete the record.

On success, certificates land in /etc/letsencrypt/live/example.com/. You'll get:

  • fullchain.pem — certificate + intermediates
  • privkey.pem — private key
  • cert.pem and chain.pem — individual pieces

Step 4: Verify Auto-Renewal Is Wired Up#

Certbot installs a systemd timer or cron job by default that attempts renewal twice daily. Confirm it's active:

bash
systemctl status certbot.timer

Test the renewal logic without actually renewing:

bash
certbot renew --dry-run

If this completes without errors, your wildcard cert will auto-renew before the 90-day expiry. The DNS plugin handles the TXT record creation and cleanup each time.

What If You Use a Non-Standard DNS Provider?#

If no official Certbot plugin exists for your DNS provider, use the `certbot-dns-multi` plugin or acme.sh (a Bash-based ACME client with broader DNS API support). The acme.sh approach:

bash
acme.sh --issue -d example.com -d '*.example.com' --dns dns_cf

acme.sh stores credentials in ~/.acme.sh/account.conf and handles renewal via its own cron entry. It supports 100+ DNS APIs out of the box, including many regional providers Certbot doesn't cover.

Step 5: Deploy the Certificate to Your Web Server#

Having the cert on disk is half the job. Your web server needs to load it.

Nginx — point to the cert paths:

nginx
server {
    listen 443 ssl;
    server_name example.com *.example.com;
    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
}

Reload Nginx after changes:

bash
nginx -t && systemctl reload nginx

Apache — the equivalent:

apache
<VirtualHost *:443>
    ServerName example.com
    ServerAlias *.example.com
    SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
</VirtualHost>

Automating the reload after renewal: Add a deploy hook. Create /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh:

bash
#!/bin/bash
nginx -t && systemctl reload nginx
bash
chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh

Certbot runs this script after every successful renewal.

Step 6: Handle Multi-Domain Wildcards#

If you manage hosting for multiple domains, you need a wildcard cert per domain. Script it:

bash
DOMAINS=("site1.com" "site2.com" "site3.com")

for domain in "${DOMAINS[@]}"; do
  certbot certonly \
    --dns-cloudflare \
    --dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
    -d "$domain" -d "*.$domain" \
    --preferred-challenges dns-01 \
    --non-interactive --agree-tos \
    -m [email protected]
done

Run this as a provisioning step whenever a new customer domain goes live. Pair it with your billing or provisioning API — tools like Salieno Core can trigger certificate issuance as part of account creation, tying SSL into the same automated pipeline that handles DNS zone setup and account provisioning.

Common Pitfalls#

  • DNS propagation delays: Some providers propagate slowly. Add --dns-cloudflare-propagation-seconds 30 (or similar flag) if you see timeout failures.
  • Rate limits: Let's Encrypt allows 50 wildcard certs per registered domain per week. Not usually a problem for resellers, but worth knowing.
  • Stale TXT records: If a previous challenge left a _acme-challenge record behind, delete it before re-issuing. Conflicting TXT records cause validation failures.
  • Mixed wildcard + non-wildcard on the same domain: Works fine — just make sure your Nginx/Apache server_name directives don't overlap in ways that cause SNI mismatches.

Conclusion#

Wildcard SSL eliminates the per-subdomain certificate chase that plagues shared hosting providers and resellers. With Certbot's DNS plugins and a one-time credentials setup, issuance and renewal become fully automated — no manual DNS edits, no expired certs waking you up at 3 AM. The DNS-01 challenge adds a small setup step compared to HTTP-01, but the payoff is a single cert that covers every subdomain your customers will ever create. Pair the automation with your provisioning workflow and you've removed SSL from your operational to-do list permanently.

Share

0 comments

Loading comments…

More from the blog

Automate Wildcard SSL with Certbot DNS-01 Challenges · Salieno Blog