automate/acme-dns_nampcheap-systemd.md

7.1 KiB
Raw Permalink Blame History

Securing Your Critical Server: Starting/Stopping acme-dns & Opening/Closing Port 53 with Certbot

On a critical server, leaving port 53 (DNS) open unnecessarily is a security risk. DNS servers are frequent targets for attacks (e.g., DDoS amplification, DNS hijacking).

The best practice is to only open port 53 and run acme-dns while Certbot is executing a DNS challenge, then immediately close port 53 and stop acme-dns afterward.

Below is a complete, productionready solution using systemd to automate this safely.


Why Systemd?

Systemd allows you to define dependencies, pre/post actions, and clean lifecycle management — perfect for this use case!


Step-by-Step Implementation

1. Modify acme-dns.service (DO NOT enable it at boot!)

We disable acme-dns from starting automatically. It will only run when Certbot needs it.

Edit the service file:

sudo nano /etc/systemd/system/acme-dns.service

Replace its content with this (securityhardened version):

#/etc/systemd/system/acme-dns.service
[Unit]
Description=Limited DNS server for ACME DNS challenges
After=network.target
# ONLY start when explicitly requested (never at boot)
RefuseManualStart=no     # Allow manual start (for testing)
# DO NOT start on boot!
[Service]
# Run as a NON-ROOT user (HIGHLY RECOMMENDED!)
User=acme-dns            # Create this user first (see Step 2)
Group=acme-dns

# Prevent the service from gaining extra privileges
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=yes
NoNewPrivileges=yes
RestrictAddressFamilies=AF_INET AF_INET6  # Only allow IPv4/IPv6
# Bind to port 53 WITHOUT root (requires kernel >= 4.11)
AmbientCapabilities=CAP_NET_BIND_SERVICE

ExecStart=/usr/local/bin/acme-dns -c /etc/acme-dns/config.cfg

Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target   # BUT WE WILL DISABLE THIS!

⚠️ Critical: DO NOT enable this service!
Run: sudo systemctl disable acme-dns.service


2. Create a Dedicated Non-Root User for acme-dns

sudo useradd --system --no-create-home --shell /usr/sbin/nologin acme-dns
sudo mkdir -p /var/lib/acme-dns /etc/acme-dns
sudo chown -R acme-dns:acme-dns /var/lib/acme-dns /etc/acme-dns

Ensure your /etc/acme-dns/config.cfg has correct permissions:

sudo chown acme-dns:acme-dns /etc/acme-dns/config.cfg
sudo chmod 600 /etc/acme-dns/config.cfg

3. Create a NEW Systemd Service: certbot-acme-dns.service

This service orchestrates:

  1. Open UDP port 53 in ufw
  2. Start acme-dns.service
  3. Run Certbot
  4. Stop acme-dns.service
  5. Close UDP port 53

Create the file:

sudo nano /etc/systemd/system/certbot-acme-dns.service

Paste the following (replace <yoursite> with your domain):

#/etc/systemd/system/certbot-acme-dns.service
[Unit]
Description=Run Certbot with acme-dns (opens/closes port 53)
After=network.target network-online.target
Wants=network-online.target

# Start ONLY when triggered (by timer or manual)
RefuseManualStart=no

[Service]
# ----- OPEN PORT 53 & START acme-dns BEFORE Certbot -----
ExecStartPre=/usr/sbin/ufw allow 53/udp
ExecStartPre=/usr/bin/systemctl start acme-dns.service

# ----- RUN CERTBOT -----
#   • Use 'renew' for automatic renewals
#   • Add domains as needed
ExecStart=/usr/bin/certbot renew \
    --quiet \
    --post-hook "/usr/bin/systemctl restart nginx"   # <-- CHANGE "nginx" to "apache2" if you use Apache

# ----- STOP acme-dns & CLOSE PORT 53 AFTER Certbot FINISHES (EVEN ON FAILURE!) -----
ExecStopPost=/usr/bin/systemctl stop acme-dns.service
ExecStopPost=/usr/sbin/ufw delete allow 53/udp

# Critical: Clean up even if Certbot FAILS!
Restart=on-failure
RestartSec=10

# Never run this service manually! It's triggered by the timer.
RefuseManualStart=yes

[Install]
WantedBy=multi-user.target

ExecStopPost runs after the service stops — even if Certbot fails!
This guarantees port 53 is always closed.


4. Create a Timer to Run Renewals Weekly

Create /etc/systemd/system/certbot-acme-dns.timer:

sudo nano /etc/systemd/system/certbot-acme-dns.timer
#/etc/systemd/system/certbot-acme-dns.timer
[Unit]
Description=Weekly Certbot Renewal (with acme-dns)

[Timer]
# Wait 5 minutes after boot (to avoid race conditions)
OnBootSec=5min

# Run every week
OnUnitActiveSec=1w

# Randomize delay ±30 min to avoid "thundering herd"
RandomizedDelaySec=1800s

[Install]
WantedBy=timers.target

Enable & Start the Timer:

sudo systemctl enable --now certbot-acme-dns.timer

Now Certbot will run automatically every week — and port 53 is ONLY open for a few seconds!


5. Test It!

🔍 Check Timer Status

systemctl status certbot-acme-dns.timer

🔧 Dry-Run Renewal (NO real changes!)

sudo certbot renew --dry-run

▶️ Manually Trigger the Service (for testing)

sudo systemctl start certbot-acme-dns.service

Watch the logs:

journalctl -u certbot-acme-dns.service -f

You should see:

  1. ufw allow 53/udp
  2. systemctl start acme-dns.service
  3. Certbot running
  4. systemctl stop acme-dns.service
  5. ufw delete allow 53/udp

Port 53 is closed again!

Verify UFW after the run:

sudo ufw status verbose

You should NOT see 53/udp allowed.


📌 Additional Security Tips

  1. Firewall Lockdown
    Ensure no other service listens on port 53!

    sudo ss -tulpn | grep ':53'
    

    Only acme-dns should appear — and only when the service is running.

  2. acme-dns Configuration Hardening
    In /etc/acme-dns/config.cfg:

    [general]
    debug = false               # <<-- TURN OFF DEBUG IN PRODUCTION!
    listen = ":53"
    protocol = "udp"
    
    [api]
    disable_registration = true  # <<-- PREVENT NEW ACCOUNTS!
    tls = "none"                # API runs on localhost:8081 (safe)
    
  3. Backups
    Backup:

    • /etc/acme-dns/config.cfg
    • /var/lib/acme-dns/acme-dns.db
    • Your Let's Encrypt certificates (/etc/letsencrypt)

    Use cron to backup daily.


What About Manual Certificate Issuance (e.g., adding a new domain)?

Use this oneliner (it auto-opens/closes port 53):

sudo systemctl start certbot-acme-dns.service --no-block

Or create a helper script (/usr/local/bin/certbot-with-acme-dns):

#!/usr/bin/env bash
sudo systemctl start certbot-acme-dns.service --no-block "$@"

Make it executable:

sudo chmod +x /usr/local/bin/certbot-with-acme-dns

Then run:

sudo certbot-with-acme-dns certonly \
  -d newdomain.com \
  --manual \
  --manual-auth-hook /etc/letsencrypt/acme-dns-auth.py \
  --preferred-challenges dns

The script will handle opening/closing port 53 automatically!


💚 Youre now running a critical server with MINIMAL exposure!
Port 53 is only open for seconds while Certbot runs — drastically reducing your attack surface. 🎯