
How to Acquire a Let’s Encrypt Certificate Using DNS Validation with ACME DNS Certbot on Ubuntu 24
In today’s security-conscious web environment, SSL/TLS certificates are absolutely essential for any serious web deployment. Let’s Encrypt revolutionized certificate management by providing free, automated certificates that are trusted by all major browsers. While HTTP validation is the most common method for obtaining these certificates, DNS validation offers distinct advantages for internal servers, wildcard certificates, and scenarios where port 80 isn’t accessible. This guide will walk you through implementing DNS validation using ACME DNS Certbot on Ubuntu 24, covering the complete setup process, troubleshooting common issues, and sharing real-world deployment strategies that actually work in production environments.
Understanding DNS Validation and ACME DNS
DNS validation works by having the ACME client create a specific TXT record in your domain’s DNS zone to prove domain ownership. Unlike HTTP validation, which requires your web server to be accessible on port 80, DNS validation can work regardless of server accessibility or firewall configurations.
ACME DNS is a simplified DNS server specifically designed for ACME DNS challenges. It acts as a limited DNS server that only handles TXT records for certificate validation, which means you don’t need to grant your certificate automation full access to your main DNS provider’s API.
Here’s how the process works:
- ACME DNS server provides you with subdomain credentials
- You create a CNAME record pointing from your domain’s validation record to the ACME DNS subdomain
- Certbot communicates with ACME DNS to create the required TXT records
- Let’s Encrypt validates the challenge and issues your certificate
This approach is particularly valuable when dealing with corporate DNS providers that don’t offer APIs, or when you need to limit access permissions for security reasons.
Setting Up ACME DNS Server
First, let’s install and configure the ACME DNS server. You can either use a public ACME DNS instance or run your own for maximum control.
Installing ACME DNS Server
# Update system packages
sudo apt update && sudo apt upgrade -y
# Install required dependencies
sudo apt install -y git golang-go sqlite3
# Clone the ACME DNS repository
git clone https://github.com/joohoi/acme-dns.git
cd acme-dns
# Build the application
go build
# Create system user for ACME DNS
sudo useradd --system --home-dir /var/lib/acme-dns --create-home acme-dns
# Copy binary to system location
sudo cp acme-dns /usr/local/bin/
sudo chown root:root /usr/local/bin/acme-dns
sudo chmod 755 /usr/local/bin/acme-dns
# Create configuration directory
sudo mkdir -p /etc/acme-dns
sudo chown acme-dns:acme-dns /etc/acme-dns
Configuring ACME DNS
Create the main configuration file:
sudo nano /etc/acme-dns/config.cfg
Add the following configuration:
[general]
listen = "0.0.0.0:53"
protocol = "both"
domain = "acme.yourdomain.com"
nsname = "acme.yourdomain.com"
nsadmin = "admin.yourdomain.com"
records = [
"acme.yourdomain.com. A YOUR_SERVER_IP",
"acme.yourdomain.com. NS acme.yourdomain.com.",
]
[database]
engine = "sqlite3"
connection = "/var/lib/acme-dns/acme-dns.db"
[api]
ip = "0.0.0.0"
port = "8080"
tls = "none"
corsorigins = [
"*"
]
[logconfig]
loglevel = "info"
logtype = "stdout"
Set proper permissions and ownership:
sudo chown acme-dns:acme-dns /etc/acme-dns/config.cfg
sudo chmod 640 /etc/acme-dns/config.cfg
Creating Systemd Service
sudo nano /etc/systemd/system/acme-dns.service
Add the service configuration:
[Unit]
Description=ACME DNS server
After=network.target
[Service]
Type=simple
User=acme-dns
Group=acme-dns
ExecStart=/usr/local/bin/acme-dns -c /etc/acme-dns/config.cfg
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
Enable and start the service:
sudo systemctl daemon-reload
sudo systemctl enable acme-dns
sudo systemctl start acme-dns
sudo systemctl status acme-dns
Installing and Configuring Certbot with ACME DNS Plugin
Now let’s set up Certbot with the ACME DNS plugin:
# Install certbot and the ACME DNS plugin
sudo apt install -y python3-pip
pip3 install certbot-dns-acmedns
# Alternatively, install via snap for the latest version
sudo snap install certbot --classic
sudo snap install certbot-dns-acmedns
# Create certbot configuration directory
sudo mkdir -p /etc/letsencrypt
sudo chmod 755 /etc/letsencrypt
Registering with ACME DNS
Register your domain with the ACME DNS server:
# Register a new account with ACME DNS
curl -X POST http://your-acme-dns-server:8080/register \
-H "Content-Type: application/json"
This will return credentials that look like this:
{
"username": "eabcdb41-d947-4c04-88d1-32464c53f666",
"password": "YourPasswordHere",
"fulldomain": "d420c923-bbd7-4056-acce-5e6439b566bb.acme.yourdomain.com",
"subdomain": "d420c923-bbd7-4056-acce-5e6439b566bb",
"allowfrom": []
}
Save these credentials securely – you’ll need them for the certbot configuration.
Creating DNS CNAME Records
For each domain you want to obtain certificates for, create a CNAME record in your main DNS zone:
# For example.com certificate:
_acme-challenge.example.com. IN CNAME d420c923-bbd7-4056-acce-5e6439b566bb.acme.yourdomain.com.
# For wildcard *.example.com certificate:
_acme-challenge.example.com. IN CNAME d420c923-bbd7-4056-acce-5e6439b566bb.acme.yourdomain.com.
Complete Step-by-Step Certificate Acquisition
Creating ACME DNS Credentials File
Create the credentials file for certbot:
sudo mkdir -p /etc/letsencrypt/acmedns
sudo nano /etc/letsencrypt/acmedns/acmedns.json
Add your ACME DNS credentials:
{
"example.com": {
"username": "eabcdb41-d947-4c04-88d1-32464c53f666",
"password": "YourPasswordHere",
"fulldomain": "d420c923-bbd7-4056-acce-5e6439b566bb.acme.yourdomain.com",
"subdomain": "d420c923-bbd7-4056-acce-5e6439b566bb",
"allowfrom": []
}
}
Secure the credentials file:
sudo chmod 600 /etc/letsencrypt/acmedns/acmedns.json
sudo chown root:root /etc/letsencrypt/acmedns/acmedns.json
Obtaining Your First Certificate
Now you can request certificates using DNS validation:
# For a single domain certificate
sudo certbot certonly \
--dns-acmedns \
--dns-acmedns-credentials /etc/letsencrypt/acmedns/acmedns.json \
-d example.com
# For a wildcard certificate
sudo certbot certonly \
--dns-acmedns \
--dns-acmedns-credentials /etc/letsencrypt/acmedns/acmedns.json \
-d example.com \
-d "*.example.com"
# For multiple domains
sudo certbot certonly \
--dns-acmedns \
--dns-acmedns-credentials /etc/letsencrypt/acmedns/acmedns.json \
-d example.com \
-d www.example.com \
-d api.example.com
Automating Certificate Renewal
Set up automatic renewal with a cron job:
# Test renewal first
sudo certbot renew --dry-run
# Create renewal script
sudo nano /usr/local/bin/renew-certificates.sh
Add the renewal script content:
#!/bin/bash
# Renew certificates
/usr/bin/certbot renew --quiet
# Reload web server if certificates were renewed
if [ $? -eq 0 ]; then
systemctl reload nginx 2>/dev/null || true
systemctl reload apache2 2>/dev/null || true
fi
# Log renewal attempt
echo "$(date): Certificate renewal completed" >> /var/log/certbot-renewal.log
Make it executable and add to cron:
sudo chmod +x /usr/local/bin/renew-certificates.sh
# Add to crontab (runs twice daily)
sudo crontab -e
# Add this line:
0 12,20 * * * /usr/local/bin/renew-certificates.sh
Real-World Use Cases and Examples
Enterprise Environment Setup
In enterprise environments, you often need certificates for internal services that aren’t publicly accessible. Here’s a complete example for an internal API server:
# Corporate internal API setup
sudo certbot certonly \
--dns-acmedns \
--dns-acmedns-credentials /etc/letsencrypt/acmedns/acmedns.json \
-d internal-api.company.com \
-d staging-api.company.com \
-d dev-api.company.com
# Configure nginx to use the certificates
sudo nano /etc/nginx/sites-available/internal-api
Nginx configuration:
server {
listen 443 ssl http2;
server_name internal-api.company.com;
ssl_certificate /etc/letsencrypt/live/internal-api.company.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/internal-api.company.com/privkey.pem;
# Modern SSL configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Development Environment with Wildcard Certificates
For development environments where you need certificates for multiple subdomains:
# Development wildcard certificate
sudo certbot certonly \
--dns-acmedns \
--dns-acmedns-credentials /etc/letsencrypt/acmedns/acmedns.json \
-d dev.company.com \
-d "*.dev.company.com"
# This covers: api.dev.company.com, staging.dev.company.com, test.dev.company.com, etc.
Comparison with Alternative Validation Methods
Validation Method | Pros | Cons | Best Use Case |
---|---|---|---|
HTTP Validation | Simple setup, no DNS changes needed | Requires port 80 access, no wildcard support | Public web servers |
DNS API Validation | Supports wildcards, works anywhere | Requires DNS provider API access | Cloud environments with API access |
ACME DNS Validation | Works with any DNS provider, secure credential isolation | Additional server setup required | Enterprise, mixed environments |
Manual DNS | Works everywhere, no automation needed | No automation, manual renewal required | One-time certificates, testing |
Troubleshooting Common Issues
DNS Propagation Problems
The most common issue is DNS propagation delays. Here’s how to diagnose and resolve them:
# Check if CNAME record is properly configured
dig _acme-challenge.example.com CNAME
# Check if ACME DNS server is responding
dig @your-acme-dns-server TXT d420c923-bbd7-4056-acce-5e6439b566bb.acme.yourdomain.com
# Test ACME DNS API directly
curl -X POST http://your-acme-dns-server:8080/update \
-H "X-Api-User: eabcdb41-d947-4c04-88d1-32464c53f666" \
-H "X-Api-Key: YourPasswordHere" \
-H "Content-Type: application/json" \
-d '{"subdomain": "d420c923-bbd7-4056-acce-5e6439b566bb", "txt": "test-record"}'
Permission and Configuration Issues
Common permission problems and their solutions:
# Fix certbot permissions
sudo chown -R root:root /etc/letsencrypt
sudo chmod -R 755 /etc/letsencrypt
sudo chmod 600 /etc/letsencrypt/acmedns/acmedns.json
# Check ACME DNS service status
sudo systemctl status acme-dns
sudo journalctl -u acme-dns -f
# Verify ACME DNS configuration
sudo -u acme-dns /usr/local/bin/acme-dns -c /etc/acme-dns/config.cfg -test
Certificate Installation Issues
When certificates aren’t properly recognized by web servers:
# Verify certificate chain
openssl x509 -in /etc/letsencrypt/live/example.com/fullchain.pem -text -noout
# Test SSL configuration
openssl s_client -connect example.com:443 -servername example.com
# Check certificate expiration
certbot certificates
Best Practices and Security Considerations
Security Hardening
- Credential isolation: Store ACME DNS credentials in separate files with restrictive permissions (600)
- Network security: Run ACME DNS server on a private network or with firewall restrictions
- Regular monitoring: Set up monitoring for certificate expiration and renewal failures
- Backup procedures: Regularly backup your ACME DNS database and certificate configurations
# Monitor certificate expiration
#!/bin/bash
# Add to /usr/local/bin/check-cert-expiry.sh
THRESHOLD=30 # Days before expiration to alert
certbot certificates | grep -E "Certificate Name|Expiry Date" | \
while read line; do
if [[ $line == *"Certificate Name"* ]]; then
cert_name=$(echo $line | cut -d: -f2 | xargs)
elif [[ $line == *"Expiry Date"* ]]; then
expiry_date=$(echo $line | cut -d: -f2- | xargs)
expiry_epoch=$(date -d "$expiry_date" +%s)
current_epoch=$(date +%s)
days_left=$(( (expiry_epoch - current_epoch) / 86400 ))
if [ $days_left -lt $THRESHOLD ]; then
echo "WARNING: Certificate $cert_name expires in $days_left days"
# Send alert notification here
fi
fi
done
Performance Optimization
For high-volume certificate management:
# Configure ACME DNS for better performance
[database]
engine = "postgres" # Use PostgreSQL for better performance
connection = "postgres://acmedns:password@localhost/acmedns?sslmode=disable"
[api]
ip = "127.0.0.1" # Bind to localhost only if behind reverse proxy
port = "8080"
tls = "letsencrypt" # Use TLS for API security
Monitoring and Alerting
Set up comprehensive monitoring:
# Create monitoring script
sudo nano /usr/local/bin/monitor-acme-dns.sh
#!/bin/bash
# Check ACME DNS service status
if ! systemctl is-active --quiet acme-dns; then
echo "ALERT: ACME DNS service is not running"
exit 1
fi
# Check API availability
if ! curl -f -s http://localhost:8080/health > /dev/null; then
echo "ALERT: ACME DNS API is not responding"
exit 1
fi
# Check certificate renewal status
if ! certbot renew --dry-run --quiet; then
echo "ALERT: Certificate renewal test failed"
exit 1
fi
echo "All checks passed"
Advanced Configuration and Integration
Multiple ACME DNS Instances
For redundancy and load distribution:
# Configure multiple ACME DNS servers in credentials file
{
"example.com": {
"username": "primary-username",
"password": "primary-password",
"fulldomain": "subdomain1.acme1.company.com",
"subdomain": "subdomain1",
"allowfrom": []
},
"backup.example.com": {
"username": "backup-username",
"password": "backup-password",
"fulldomain": "subdomain2.acme2.company.com",
"subdomain": "subdomain2",
"allowfrom": []
}
}
Integration with Configuration Management
Example Ansible playbook for automated deployment:
---
- name: Deploy ACME DNS and Certbot
hosts: certificate_servers
become: yes
tasks:
- name: Install required packages
apt:
name:
- golang-go
- sqlite3
- python3-pip
state: present
update_cache: yes
- name: Install certbot-dns-acmedns
pip:
name: certbot-dns-acmedns
state: present
- name: Create ACME DNS user
user:
name: acme-dns
system: yes
home: /var/lib/acme-dns
create_home: yes
- name: Deploy ACME DNS configuration
template:
src: acme-dns-config.j2
dest: /etc/acme-dns/config.cfg
owner: acme-dns
group: acme-dns
mode: '0640'
notify: restart acme-dns
This comprehensive approach to DNS validation with ACME DNS provides a robust, secure, and scalable solution for certificate management in complex environments. The combination of automated renewal, proper monitoring, and security best practices ensures reliable SSL/TLS certificate management that scales from development environments to enterprise production systems.
For additional information, consult the official ACME DNS documentation and the Certbot documentation for the latest updates and advanced configuration options.

This article incorporates information and material from various online sources. We acknowledge and appreciate the work of all original authors, publishers, and websites. While every effort has been made to appropriately credit the source material, any unintentional oversight or omission does not constitute a copyright infringement. All trademarks, logos, and images mentioned are the property of their respective owners. If you believe that any content used in this article infringes upon your copyright, please contact us immediately for review and prompt action.
This article is intended for informational and educational purposes only and does not infringe on the rights of the copyright owners. If any copyrighted material has been used without proper credit or in violation of copyright laws, it is unintentional and we will rectify it promptly upon notification. Please note that the republishing, redistribution, or reproduction of part or all of the contents in any form is prohibited without express written permission from the author and website owner. For permissions or further inquiries, please contact us.