### **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 `<yoursite>` 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. 🎯
