RU RU

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

  1. Log in to Cloudflare → API TokensCreate Token.
  2. Use the Edit zone DNS template with permissions:
    • Zone.DNS:Edit
    • Zone.Zone:Read
  3. Restrict the token to a specific zone.
  4. 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

CriterionCertbotacme.sh
LanguagePythonPOSIX sh
InstallationOS packages or snapOne script `curlsh`
DNS supportOfficial plugins~40 providers built-in
UpdatesVia package managerBuilt-in auto-update
Hooks and deployLimited hooksConvenient --reloadcmd, --deploy
DependenciesPython, certbot-* packagescurl, socat, openssl
ResourcesHeavier (Python)Lighter, minimalist
PopularityDe-facto standard, more documentationMore 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

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

apande · Configuring Nginx and OpenCart

A very powerful buyer

2024-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.

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

kireevk · Diagnosing Nginx Proxy Manager in a Docker container and resolving the issue

Settled-in customer

2024-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)

Need help?

Get in touch with me and I'll help solve the problem

Related Posts