Complete acme-dns Configuration with SSL Certificate Installation

For ssl.anytrust.ch on Ubuntu

This comprehensive guide covers the complete setup of acme-dns with proper SSL certificate installation, from DNS preparation through production deployment.

Prerequisites and DNS Setup

1. DNS Records Preparation

Before starting, ensure these DNS records are configured in your main domain's DNS zone (anytrust.ch):

# A record for your acme-dns server
ssl.anytrust.ch.     IN A     YOUR_SERVER_PUBLIC_IP

# NS record to delegate subdomain
ssl.anytrust.ch.     IN NS    ssl.anytrust.ch.

# Optional: IPv6 support
ssl.anytrust.ch.     IN AAAA  YOUR_IPv6_ADDRESS

Verify DNS propagation:

# Check A record
dig A ssl.anytrust.ch @8.8.8.8

# Check NS record
dig NS ssl.anytrust.ch @1.1.1.1

# Verify from multiple locations
host ssl.anytrust.ch
nslookup ssl.anytrust.ch

2. System Preparation

# Update system
sudo apt update && sudo apt upgrade -y

# Install required packages
sudo apt install -y \
    golang-go \
    git \
    certbot \
    python3-certbot \
    sqlite3 \
    dnsutils \
    net-tools \
    ufw \
    acl

# Check if port 53 is in use (common conflict with systemd-resolved)
sudo netstat -tulpn | grep :53

# If systemd-resolved is using port 53, disable it
sudo systemctl disable systemd-resolved
sudo systemctl stop systemd-resolved

# Alternative: modify systemd-resolved to not bind port 53
sudo sed -i 's/#DNSStubListener=yes/DNSStubListener=no/' /etc/systemd/resolved.conf
sudo systemctl restart systemd-resolved

acme-dns Installation

3. Build and Install acme-dns

# Create working directory
mkdir -p ~/build && cd ~/build

# Clone repository
git clone https://github.com/joohoi/acme-dns
cd acme-dns

# Build the binary
go build

# Install binary
sudo mv acme-dns /usr/local/bin/
sudo chmod +x /usr/local/bin/acme-dns

# Verify installation
/usr/local/bin/acme-dns -h

4. Create System User and Directories

# Create dedicated system user
sudo adduser --system --gecos "acme-dns Service" \
    --disabled-password --group --home /var/lib/acme-dns acme-dns

# Create required directories
sudo mkdir -p /etc/acme-dns
sudo mkdir -p /var/lib/acme-dns
sudo mkdir -p /var/lib/acme-dns/cert
sudo mkdir -p /var/log/acme-dns

# Set ownership
sudo chown -R acme-dns:acme-dns /var/lib/acme-dns
sudo chown -R acme-dns:acme-dns /var/log/acme-dns
sudo chown root:acme-dns /etc/acme-dns

SSL Certificate Acquisition

5. Initial Certificate Request with Certbot

Method A: Using HTTP-01 Challenge (Recommended for initial setup)

# Stop any service using port 80
sudo systemctl stop nginx apache2 2>/dev/null

# Request certificate using standalone mode
sudo certbot certonly \
    --standalone \
    --preferred-challenges http \
    -d ssl.anytrust.ch \
    --email admin@anytrust.ch \
    --agree-tos \
    --no-eff-email \
    --non-interactive

# Certificate will be saved to:
# /etc/letsencrypt/live/ssl.anytrust.ch/fullchain.pem
# /etc/letsencrypt/live/ssl.anytrust.ch/privkey.pem

Method B: Using DNS-01 Challenge (If port 80 is not available)

# Request certificate with manual DNS challenge
sudo certbot certonly \
    --manual \
    --preferred-challenges dns \
    -d ssl.anytrust.ch \
    --email admin@anytrust.ch \
    --agree-tos \
    --no-eff-email

# Follow the prompts to add TXT record to your DNS
# Add: _acme-challenge.ssl.anytrust.ch TXT "provided-value"
# Wait for DNS propagation before continuing

6. Verify Certificate Installation

# Check certificate details
sudo openssl x509 -in /etc/letsencrypt/live/ssl.anytrust.ch/fullchain.pem \
    -text -noout | grep -A 2 "Subject:"

# Verify certificate dates
sudo openssl x509 -in /etc/letsencrypt/live/ssl.anytrust.ch/fullchain.pem \
    -text -noout | grep -A 2 "Validity"

# Test certificate chain
sudo openssl verify -CAfile /etc/letsencrypt/live/ssl.anytrust.ch/chain.pem \
    /etc/letsencrypt/live/ssl.anytrust.ch/cert.pem

acme-dns Configuration with SSL

7. Create Configuration File

Create /etc/acme-dns/config.cfg:

[general]
# DNS interface settings
listen = ":53"
protocol = "both"
domain = "ssl.anytrust.ch"
nsname = "ssl.anytrust.ch"
nsadmin = "admin.anytrust.ch"
records = [
    "ssl.anytrust.ch. A YOUR_SERVER_PUBLIC_IP",
    "ssl.anytrust.ch. NS ssl.anytrust.ch.",
]
debug = false

[database]
# Database backend settings
engine = "sqlite3"
connection = "/var/lib/acme-dns/acme-dns.db"

[api]
# API interface settings with SSL
ip = "0.0.0.0"
port = "443"
# Direct TLS configuration using Let's Encrypt certificates
tls = "cert"
tls_cert_privkey = "/var/lib/acme-dns/cert/privkey.pem"
tls_cert_fullchain = "/var/lib/acme-dns/cert/fullchain.pem"
# API settings
corsorigins = ["*"]
use_header = false
header_name = "X-Forwarded-For"
disable_registration = false

[logconfig]
# Logging configuration
loglevel = "info"
logtype = "file"
logformat = "text"
logfile = "/var/log/acme-dns/acme-dns.log"

8. Set Up Certificate Management

Create certificate copy script for acme-dns access:

# Create certificate deployment script
sudo tee /usr/local/bin/deploy-acme-dns-certs.sh << 'EOF'
#!/bin/bash

# Certificate source and destination
CERT_SRC="/etc/letsencrypt/live/ssl.anytrust.ch"
CERT_DST="/var/lib/acme-dns/cert"

# Copy certificates
cp -L "$CERT_SRC/fullchain.pem" "$CERT_DST/fullchain.pem"
cp -L "$CERT_SRC/privkey.pem" "$CERT_DST/privkey.pem"

# Set permissions
chown acme-dns:acme-dns "$CERT_DST"/*.pem
chmod 640 "$CERT_DST"/*.pem

# Restart acme-dns if running
if systemctl is-active --quiet acme-dns; then
    systemctl restart acme-dns
    echo "acme-dns restarted with new certificates"
fi

echo "Certificates deployed successfully"
EOF

# Make script executable
sudo chmod +x /usr/local/bin/deploy-acme-dns-certs.sh

# Run initial deployment
sudo /usr/local/bin/deploy-acme-dns-certs.sh

Set up automatic renewal hook:

# Create renewal hook for certbot
sudo tee /etc/letsencrypt/renewal-hooks/deploy/01-acme-dns.sh << 'EOF'
#!/bin/bash
# This script runs after successful certificate renewal

if [[ "$RENEWED_DOMAINS" == *"ssl.anytrust.ch"* ]]; then
    /usr/local/bin/deploy-acme-dns-certs.sh
    logger -t certbot-renewal "acme-dns certificates renewed and deployed"
fi
EOF

sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/01-acme-dns.sh

9. Configure Systemd Service

# Create systemd service file
sudo tee /etc/systemd/system/acme-dns.service << 'EOF'
[Unit]
Description=Limited DNS server with RESTful HTTP API for ACME challenges
Documentation=https://github.com/joohoi/acme-dns
After=network-online.target
Wants=network-online.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=5s

# Security hardening
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/lib/acme-dns /var/log/acme-dns
ReadOnlyPaths=/etc/acme-dns

# Network capabilities
AmbientCapabilities=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_BIND_SERVICE

# Resource limits
LimitNOFILE=65536
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
EOF

# Reload systemd
sudo systemctl daemon-reload

Firewall Configuration

10. Configure UFW Firewall

# Configure default policies
sudo ufw default deny incoming
sudo ufw default allow outgoing

# Allow SSH (adjust port if needed)
sudo ufw allow 22/tcp comment 'SSH'

# Allow DNS
sudo ufw allow 53/tcp comment 'DNS TCP'
sudo ufw allow 53/udp comment 'DNS UDP'

# Allow HTTPS for API
sudo ufw allow 443/tcp comment 'HTTPS API'

# Allow HTTP for certificate renewal
sudo ufw allow 80/tcp comment 'HTTP Certbot renewal'

# Enable firewall
sudo ufw --force enable

# Check status
sudo ufw status verbose

Service Startup and Testing

11. Start acme-dns Service

# Set correct permissions on config
sudo chmod 640 /etc/acme-dns/config.cfg
sudo chown root:acme-dns /etc/acme-dns/config.cfg

# Enable and start service
sudo systemctl enable acme-dns.service
sudo systemctl start acme-dns.service

# Check service status
sudo systemctl status acme-dns.service

# View logs
sudo journalctl -u acme-dns -f

12. Test SSL Connection

# Test HTTPS API endpoint
curl -v https://ssl.anytrust.ch/health

# Test SSL certificate
echo | openssl s_client -connect ssl.anytrust.ch:443 -servername ssl.anytrust.ch 2>/dev/null | \
    openssl x509 -noout -text | grep -A 2 "Subject:"

# Test with SSL Labs (optional)
echo "Visit: https://www.ssllabs.com/ssltest/analyze.html?d=ssl.anytrust.ch"

13. Test DNS Functionality

# Test DNS resolution
dig @ssl.anytrust.ch SOA ssl.anytrust.ch

# Register a test account
curl -X POST https://ssl.anytrust.ch/register \
    -H "Content-Type: application/json" | python3 -m json.tool

# Save the output! You'll get credentials like:
# {
#   "username": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
#   "password": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
#   "fulldomain": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.ssl.anytrust.ch",
#   "subdomain": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
# }

Certificate Renewal Automation

14. Set Up Automatic Renewal

# Test renewal process
sudo certbot renew --dry-run

# Check certbot timer is active
sudo systemctl status certbot.timer

# If timer doesn't exist, create cron job
echo "0 3 * * * /usr/bin/certbot renew --quiet --post-hook '/usr/local/bin/deploy-acme-dns-certs.sh'" | \
    sudo crontab -

# Manual renewal test
sudo certbot renew --force-renewal --cert-name ssl.anytrust.ch

Production Security Hardening

15. Security Enhancements

# After initial setup, disable public registration
sudo sed -i 's/disable_registration = false/disable_registration = true/' \
    /etc/acme-dns/config.cfg
sudo systemctl restart acme-dns

# Set up fail2ban for API protection (optional)
sudo apt install fail2ban

# Create fail2ban filter
sudo tee /etc/fail2ban/filter.d/acme-dns.conf << 'EOF'
[Definition]
failregex = ^.*Failed authentication attempt from <HOST>.*$
ignoreregex =
EOF

# Create jail configuration
sudo tee /etc/fail2ban/jail.d/acme-dns.conf << 'EOF'
[acme-dns]
enabled = true
port = 443
filter = acme-dns
logpath = /var/log/acme-dns/acme-dns.log
maxretry = 5
bantime = 3600
EOF

sudo systemctl restart fail2ban

16. Monitoring and Maintenance

# Create monitoring script
sudo tee /usr/local/bin/check-acme-dns.sh << 'EOF'
#!/bin/bash

# Check service status
if ! systemctl is-active --quiet acme-dns; then
    echo "CRITICAL: acme-dns service is not running"
    systemctl start acme-dns
    exit 2
fi

# Check API availability
if ! curl -sf https://ssl.anytrust.ch/health > /dev/null 2>&1; then
    echo "WARNING: acme-dns API not responding"
    exit 1
fi

# Check certificate expiry
CERT_FILE="/var/lib/acme-dns/cert/fullchain.pem"
EXPIRY_DATE=$(openssl x509 -in "$CERT_FILE" -noout -enddate | cut -d= -f2)
EXPIRY_EPOCH=$(date -d "$EXPIRY_DATE" +%s)
CURRENT_EPOCH=$(date +%s)
DAYS_LEFT=$(( ($EXPIRY_EPOCH - $CURRENT_EPOCH) / 86400 ))

if [ $DAYS_LEFT -lt 7 ]; then
    echo "WARNING: Certificate expires in $DAYS_LEFT days"
    exit 1
fi

echo "OK: acme-dns operational, cert valid for $DAYS_LEFT days"
exit 0
EOF

sudo chmod +x /usr/local/bin/check-acme-dns.sh

# Add to cron for regular checks
echo "*/5 * * * * /usr/local/bin/check-acme-dns.sh" | sudo crontab -l | sudo crontab -

Backup Configuration

17. Set Up Backups

# Create backup script
sudo tee /usr/local/bin/backup-acme-dns.sh << 'EOF'
#!/bin/bash

BACKUP_DIR="/var/backups/acme-dns"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)

# Create backup directory
mkdir -p "$BACKUP_DIR"

# Backup database
sqlite3 /var/lib/acme-dns/acme-dns.db \
    ".backup $BACKUP_DIR/acme-dns-$TIMESTAMP.db"

# Backup configuration
tar czf "$BACKUP_DIR/config-$TIMESTAMP.tar.gz" \
    /etc/acme-dns/ \
    /var/lib/acme-dns/cert/

# Keep only last 30 days
find "$BACKUP_DIR" -type f -mtime +30 -delete

echo "Backup completed: $BACKUP_DIR/*-$TIMESTAMP.*"
EOF

sudo chmod +x /usr/local/bin/backup-acme-dns.sh

# Schedule daily backups
echo "0 2 * * * /usr/local/bin/backup-acme-dns.sh" | sudo crontab -l | sudo crontab -

Client Configuration

18. Configure ACME Clients to Use acme-dns

For domains using this acme-dns server:

  1. Register with acme-dns:
curl -X POST https://ssl.anytrust.ch/register

  1. Create CNAME record in your domain's DNS:
_acme-challenge.yourdomain.com. CNAME xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.ssl.anytrust.ch.

  1. Use with certbot:
# Install acme-dns authenticator
wget https://github.com/joohoi/acme-dns-certbot-joohoi/raw/master/acme-dns-auth.py
chmod +x acme-dns-auth.py

# Request certificate
certbot certonly --manual \
    --manual-auth-hook ./acme-dns-auth.py \
    --preferred-challenges dns \
    --debug-challenges \
    -d yourdomain.com

Troubleshooting

19. Common Issues and Solutions

Port 53 Already in Use:

# Find what's using port 53
sudo lsof -i :53
sudo netstat -tulpn | grep :53

# If systemd-resolved, disable DNS stub
sudo systemctl stop systemd-resolved
sudo rm /etc/resolv.conf
echo "nameserver 8.8.8.8" | sudo tee /etc/resolv.conf

SSL Certificate Issues:

# Check certificate permissions
ls -la /var/lib/acme-dns/cert/

# Verify certificate readability
sudo -u acme-dns openssl x509 -in /var/lib/acme-dns/cert/fullchain.pem -text -noout

# Check service logs
sudo journalctl -u acme-dns --since "1 hour ago"

API Not Accessible:

# Check if service is listening
sudo ss -tulpn | grep 443

# Test local connection
curl -k https://localhost/health

# Check firewall
sudo ufw status numbered

DNS Resolution Failures:

# Test DNS server directly
dig @localhost ssl.anytrust.ch
dig @ssl.anytrust.ch test.ssl.anytrust.ch TXT

# Check zone delegation
dig +trace ssl.anytrust.ch

20. Verification Checklist

  • DNS A and NS records properly configured
  • SSL certificate obtained and valid
  • acme-dns service running on ports 53 and 443
  • Firewall rules configured
  • API accessible via HTTPS
  • Certificate auto-renewal configured
  • Monitoring and backups in place
  • Test registration successful
  • DNS queries responding correctly

Maintenance Commands Reference

# Service management
sudo systemctl status/start/stop/restart acme-dns

# View logs
sudo journalctl -u acme-dns -f
tail -f /var/log/acme-dns/acme-dns.log

# Certificate management
sudo certbot certificates
sudo certbot renew --dry-run
sudo /usr/local/bin/deploy-acme-dns-certs.sh

# Test endpoints
curl https://ssl.anytrust.ch/health
dig @ssl.anytrust.ch test.ssl.anytrust.ch

# Backup
sudo /usr/local/bin/backup-acme-dns.sh

# Monitoring
sudo /usr/local/bin/check-acme-dns.sh

This completes the comprehensive setup of acme-dns with SSL on ssl.anytrust.ch. The service is now ready for production use with automated certificate management, monitoring, and backup systems in place.