automate/acme-dns_nampcheap-systemd.md

286 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

### **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:
```bash
sudo nano /etc/systemd/system/acme-dns.service
```
Replace its content with this **(securityhardened 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 **oneliner** (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!
---
💚 **Youre now running a critical server with MINIMAL exposure!**
Port 53 is **only open for seconds** while Certbot runs drastically reducing your attack surface. 🎯