SSL certificates via DNS: automating Let’s Encrypt issuance
Published on 2025-10-06
SSL certificates via DNS: automating Let’s Encrypt issuance
Introduction
Let’s Encrypt is the standard for obtaining free TLS certificates. Most often certificates are issued via the HTTP-01 method, which requires a reachable web server on port 80. However, for internal services or wildcard certificates (for example, *.example.com
) it is more convenient to use DNS-01, which verifies domain ownership via TXT records in DNS and does not require open ports.
This article covers:
- Issuing certificates via the Cloudflare API,
- Issuing certificates via Amazon Route 53 (AWS),
- Integration with web servers Nginx, HAProxy and Traefik,
- Automation of certificate renewal.
Note: Instructions are relevant for Certbot 2.x, acme.sh 3.x, Nginx 1.18+, HAProxy 2.4+, Traefik 2.x on Linux (Ubuntu/Debian). For other OSes or tool versions adjustments may be required.
Cloudflare
1. Create an API token
- Log in to Cloudflare → API Tokens → Create Token.
- Use the Edit zone DNS template with permissions:
Zone.DNS:Edit
Zone.Zone:Read
- Restrict the token to a specific zone.
- Store the token in a secure place (CI/CD secrets, environment variables).
⚠️ Token leakage gives full control over the DNS zone.
2. Install Certbot and the plugin
Ubuntu/Debian:
sudo apt-get update
sudo apt-get install -y certbot python3-certbot-dns-cloudflare
CentOS/Fedora:
sudo dnf install -y certbot python3-certbot-dns-cloudflare
Via snap:
sudo snap install --classic certbot
sudo snap install certbot-dns-cloudflare
3. Configure the token
File /etc/letsencrypt/cloudflare.ini
:
dns_cloudflare_api_token = YOUR_CF_API_TOKEN
Permissions:
sudo chown root:root /etc/letsencrypt/cloudflare.ini
sudo chmod 600 /etc/letsencrypt/cloudflare.ini
4. Issue the certificate
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
-d example.com -d '*.example.com' \
--non-interactive
AWS Route 53
1. Configure IAM permissions
Create a policy with minimal permissions for the specific zone:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"route53:ChangeResourceRecordSets",
"route53:ListHostedZones",
"route53:ListResourceRecordSets"
],
"Resource": "arn:aws:route53:::hostedzone/<YOUR_HOSTED_ZONE_ID>"
}
]
}
Set up an AWS CLI profile:
aws configure --profile certbot
Provide AWS_ACCESS_KEY_ID
, AWS_SECRET_ACCESS_KEY
and a region (for example, us-east-1
).
2. Install the plugin
Ubuntu/Debian:
sudo apt-get install -y certbot python3-certbot-dns-route53
CentOS/Fedora:
sudo dnf install -y certbot python3-certbot-dns-route53
3. Issue the certificate
AWS_PROFILE=certbot \
sudo certbot certonly \
--dns-route53 \
-d example.com -d '*.example.com' \
--non-interactive
Note: you can use environment variables instead of a profile (
AWS_ACCESS_KEY_ID
,AWS_SECRET_ACCESS_KEY
).
Integration with web servers
Nginx
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
location / {
proxy_pass http://127.0.0.1:8080;
}
}
Hook to reload /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
:
#!/bin/sh
if nginx -t; then
systemctl reload nginx
else
echo "Nginx configuration test failed"
exit 1
fi
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
HAProxy
Combine certificate and key:
cat /etc/letsencrypt/live/example.com/fullchain.pem \
/etc/letsencrypt/live/example.com/privkey.pem \
| tee /etc/haproxy/certs/example.com.pem >/dev/null
Config snippet:
frontend https-in
bind *:443 ssl crt /etc/haproxy/certs/example.com.pem
default_backend web-backend
Traefik
File /etc/traefik/dynamic.yml
:
tls:
certificates:
- certFile: /etc/letsencrypt/live/example.com/fullchain.pem
keyFile: /etc/letsencrypt/live/example.com/privkey.pem
traefik.yml
:
providers:
file:
filename: /etc/traefik/dynamic.yml
If Traefik runs in Docker:
-v /etc/letsencrypt:/etc/letsencrypt:ro
Renewal automation
Certbot
Cron job:
sudo crontab -e
0 0,12 * * * certbot renew --quiet --deploy-hook /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
Error logs: /var/log/letsencrypt/letsencrypt.log
.
acme.sh
When installed acme.sh sets up a cron job itself. Check:
crontab -l | grep acme.sh
Alternative: acme.sh
Install:
curl https://get.acme.sh | sh
Cloudflare:
export CF_Token="YOUR_CF_API_TOKEN"
~/.acme.sh/acme.sh --issue --dns dns_cf -d example.com -d '*.example.com'
AWS Route 53:
export AWS_ACCESS_KEY_ID="AKIA..."
export AWS_SECRET_ACCESS_KEY="..."
export AWS_REGION="us-east-1"
~/.acme.sh/acme.sh --issue --dns dns_aws -d example.com -d '*.example.com'
Install certificate:
~/.acme.sh/acme.sh --install-cert -d example.com \
--key-file /etc/ssl/example.com/privkey.pem \
--fullchain-file /etc/ssl/example.com/fullchain.pem \
--reloadcmd "systemctl reload nginx"
Certbot vs acme.sh
Criterion | Certbot | acme.sh | |
---|---|---|---|
Language | Python | POSIX sh | |
Installation | OS packages or snap | One script `curl | sh` |
DNS support | Official plugins | ~40 providers built-in | |
Updates | Via package manager | Built-in auto-update | |
Hooks and deploy | Limited hooks | Convenient --reloadcmd , --deploy | |
Dependencies | Python, certbot-* packages | curl , socat , openssl | |
Resources | Heavier (Python) | Lighter, minimalist | |
Popularity | De-facto standard, more documentation | More convenient for CI/CD |
When to choose Certbot:
- if you need official Let’s Encrypt support,
- if installing packages via
apt
/yum
is convenient, - if priority is the standard ecosystem.
When to choose acme.sh:
- if you have a minimal environment without Python,
- if issuance needs to be integrated into a CI/CD pipeline,
- if the DNS provider is supported directly in acme.sh.
Limitations and risks
- API token leakage = full control over the DNS zone.
- Let’s Encrypt limits: up to 50 certificates per week per domain.
- DNS propagation: delay from seconds to minutes.
- Renewal failures: incorrect hooks can lead to expiration.
Tip: add monitoring (Zabbix, Prometheus, Nagios) to track certificate expiry dates.
Conclusion
DNS validation allows you to:
- automate issuance and renewal of SSL,
- use wildcard certificates,
- not depend on open ports.
Cloudflare and AWS Route 53 provide APIs for full automation. Integration with Nginx, HAProxy and Traefik takes only a few lines of configuration. Automatic renewal and monitoring are essential steps for reliable operation.
Related reviews
Thanks to Mikhail for his responsiveness. We spoke by phone; he explained how I could do it myself. This is my second time reaching out — everything’s great and prompt.

kireevk · Consultation on Nginx Proxy Manager and Portainer
A customer who has settled in2025-02-25 · ⭐ 5/5
Thanks to Mikhail for his responsiveness. We had a call; he explained how I could do it myself. This is my second time contacting him; everything is great and prompt.
I want to express my deep gratitude to the specialist who set up SEO-friendly URLs for me on OpenCart. Configuring them turned out to be easy and simple, and I'm glad I finally found a professional who did everything well and without unnecessary complications. Before this I went through four specialists, and each time there were issues with the setup, but this person handled the task perfectly.

apande · Configuring Nginx and OpenCart
A very powerful buyer2024-09-07 · ⭐ 5/5
I want to express my great gratitude to the specialist who configured SEO-friendly URLs for me on OpenCart. Setting up the URLs turned out to be easy and simple, and I'm glad that I finally found a professional who did everything efficiently and without unnecessary complications. Before that I changed four specialists, and each time there were problems with the configuration, but this person handled the task perfectly.
Excellent work — this isn't the first time I've used them; they find solutions to complex problems. I recommend.

Evgeni8j · Nginx rate limit
Pro-Expert Buyer2024-05-10 · ⭐ 5/5
Excellent work, this isn't my first time contacting them; they find solutions to complex problems. I recommend.
Excellent work! He completed the assigned task on time and without errors. It was a pleasure to work with him; I recommend him.

Evgeni8j · Nginx configuration
Expert buyer2024-05-03 · ⭐ 5/5
Great job! Completed the assigned task on time and without errors. It was a pleasure to work together, I recommend.
Excellent specialist — he delved into the problem, figured it out, and fixed it. I recommend him.

Evgeni8j · Fixing a regex in an Nginx location block
Expert buyer2024-03-21 · ⭐ 5/5
Excellent specialist, delved into the problem, figured it out, and fixed it. I recommend.
I needed to resolve an SSL certificate issue on a server where the certificate had been issued through Nginx Proxy Manager. Mikhail clarified all the details of my setup and requested access to assess the feasibility of solving the issue, since he hadn't worked with that service before. He quickly figured it out and fixed my problem. Perfect cooperation)

kireevk · Diagnosing Nginx Proxy Manager in a Docker container and resolving the issue
Settled-in customer2024-03-15 · ⭐ 5/5
I needed to solve an issue with an SSL certificate on the server that was issued through Ngnix Proxy manager. Mikhail clarified all the details of how everything is set up for me, asked for access to assess the feasibility of solving the issue, since he had not encountered such a service before. He quickly figured it out and solved my problem. Perfect cooperation)
Related Posts
107 | Battle for Security — FTPS vs SFTP
2025-09-24
104 | Real-Time Revolution: Diving into the World of WebSockets and Long Polling
2025-09-12
010 | Setting Up DNS for Mail and Website: Part 3 — How to Configure and Verify
2025-05-31
009 | DNS Setup for Mail and Website Part 2 — Mail Protection (SPF, DKIM, DMARC)
2025-05-30