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
- Certbot asks Let’s Encrypt for a certificate.
- Let’s Encrypt returns a token.
- You publish it as a TXT record at
_acme-challenge.example.com. - 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 viaissuewildif you use that tag). See CAA records. - Rate limits — test with
--dry-runor--stagingwhile 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.