A wildcard certificate covers every first-level subdomain — *.example.com matches app.example.com, mail.example.com and anything else you create later. Let’s Encrypt issues them for free, but only via the DNS-01 challenge: you prove control of the domain by creating a TXT record, rather than serving a file over HTTP.

When a wildcard makes sense

  • Many subdomains (per-customer subdomains, dynamic environments like pr-123.example.com).
  • Services that aren’t reachable on port 80 (internal tools, servers behind a VPN).
  • One certificate shared by a reverse proxy for many apps.

For a handful of fixed hostnames, normal certificates with HTTP validation are simpler. Note that *.example.com does not cover example.com itself, nor second-level names like a.b.example.com — request the bare domain alongside.

The challenge: DNS-01

  1. Certbot asks Let’s Encrypt for a certificate.
  2. Let’s Encrypt returns a token.
  3. You publish it as a TXT record at _acme-challenge.example.com.
  4. Let’s Encrypt checks DNS and issues the certificate.

Automation needs an API to edit DNS. Certbot has plugins for many providers.

Option 1: Cloudflare DNS plugin (automated)

Install the plugin:

sudo apt install -y certbot python3-certbot-dns-cloudflare

Create an API token in Cloudflare (My Profile → API Tokens → Create Token → “Edit zone DNS” template), limited to the one zone. Save it:

sudo mkdir -p /root/.secrets
sudo tee /root/.secrets/cloudflare.ini > /dev/null <<'EOF'
dns_cloudflare_api_token = YOUR_TOKEN_HERE
EOF
sudo chmod 600 /root/.secrets/cloudflare.ini

Request the certificate:

sudo certbot certonly \
  --dns-cloudflare \
  --dns-cloudflare-credentials /root/.secrets/cloudflare.ini \
  --dns-cloudflare-propagation-seconds 30 \
  -d example.com -d '*.example.com'

Quote '*.example.com' so the shell doesn’t expand the asterisk. The certificate lands in /etc/letsencrypt/live/example.com/.

Plugins exist for Route 53, DigitalOcean, Google Cloud DNS, OVH, Linode, RFC 2136 (BIND) and more (apt search python3-certbot-dns). For providers without a plugin, acme.sh supports well over a hundred DNS APIs — see acme.sh.

Option 2: manual mode (one-off, no renewal)

sudo certbot certonly --manual --preferred-challenges dns \
  -d example.com -d '*.example.com'

Certbot shows a TXT value; create the record at your DNS provider, wait until it’s visible:

dig +short TXT _acme-challenge.example.com @1.1.1.1

…then press Enter. For two names (bare + wildcard) you’ll add two TXT values at the same name — keep both.

Manual certificates can’t renew automatically — you’d repeat this every 60–90 days. Fine for a test; use a plugin for production.

Option 3: delegate _acme-challenge (keep your main DNS locked down)

If you don’t want an API token that can edit your whole zone, create a CNAME:

_acme-challenge.example.com.  CNAME  _acme-challenge.example.com.acme.yourdomain-dns.net.

pointing to a zone on a DNS service you can automate (or an acme-dns server). Certbot (with the acme-dns hook) or acme.sh then updates only that delegated record.

Install the certificate

certonly doesn’t touch your web server config. Point it at the files:

Nginx:

ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

Every server block for any subdomain can use the same two lines.

Apache:

SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem

Renewal

With a DNS plugin, the normal renewal timer handles it:

sudo certbot renew --dry-run

Add a deploy hook so the web server loads the renewed certificate:

sudo tee /etc/letsencrypt/renewal-hooks/deploy/reload.sh > /dev/null <<'EOF'
#!/bin/sh
systemctl reload nginx
EOF
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload.sh

Troubleshooting

  • Incorrect TXT record — DNS hadn’t propagated; raise --dns-cloudflare-propagation-seconds (60–120 for slow providers).
  • Error determining zone_id — the token lacks permission for that zone, or you used a Global API Key format with a token option.
  • CAA records — if your domain has CAA records, one must allow letsencrypt.org (and wildcard issuance via issuewild if you use that tag). See CAA records.
  • Rate limits — test with --dry-run or --staging while experimenting.

Security considerations

A wildcard’s private key is valuable: whoever has it can impersonate any subdomain. Keep it on as few servers as possible, protect /etc/letsencrypt (root-only), and scope the DNS API token to the single zone.

Related: Certbot with Nginx, Certbot with Apache and DNS records explained.

  • SSL
  • Let's Encrypt
  • DNS