### **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, production‑ready 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: ```bash sudo nano /etc/systemd/system/acme-dns.service ``` Replace its content with this **(security‑hardened version)**: ```ini #/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`** ```bash 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: ```bash 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: ```bash sudo nano /etc/systemd/system/certbot-acme-dns.service ``` Paste the following **(replace `` with your domain)**: ```ini #/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`: ```bash sudo nano /etc/systemd/system/certbot-acme-dns.timer ``` ```ini #/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:** ```bash 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 ```bash systemctl status certbot-acme-dns.timer ``` #### 🔧 Dry-Run Renewal (NO real changes!) ```bash sudo certbot renew --dry-run ``` #### ▶️ Manually Trigger the Service (for testing) ```bash sudo systemctl start certbot-acme-dns.service ``` **Watch the logs:** ```bash 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: ```bash 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! ```bash 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`: ```ini [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 **one‑liner** (it auto-opens/closes port 53): ```bash sudo systemctl start certbot-acme-dns.service --no-block ``` Or create a helper script (`/usr/local/bin/certbot-with-acme-dns`): ```bash #!/usr/bin/env bash sudo systemctl start certbot-acme-dns.service --no-block "$@" ``` Make it executable: ```bash sudo chmod +x /usr/local/bin/certbot-with-acme-dns ``` Then run: ```bash 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! --- 💚 **You’re now running a critical server with MINIMAL exposure!** Port 53 is **only open for seconds** while Certbot runs — drastically reducing your attack surface. 🎯