Use Cloudflare 1.1.1.1/cdn-cgi/trace as primary IP source (fixed IP, no resolver dependency — survives AdGuard/upstream DNS outages). Add calibre to DNS_RECORDS: its A record points at the dynamic WAN IP but was not guarded, so it would go stale on the next WAN change.
6.2 KiB
WAN IP Guard
Bewaakt het publieke WAN IP en update automatisch DNS records bij wijziging, plus WhatsApp notificatie.
Wat doet het?
- Controleert elke 5 minuten het publieke WAN IP
- Bij wijziging:
- Updatet A-records via de DirectAdmin API
- Stuurt een WhatsApp notificatie naar de admin
- Draait als systemd timer
Installatie
1. Clone op je server
cd ~
git clone <jouw-repo-url> wan-ip-guard
cd wan-ip-guard
2. Configureer
# .env naar /etc (nodig vanwege systemd beperkingen op nieuwere Fedora)
sudo mkdir -p /etc/wan-ip-guard
sudo cp .env.example /etc/wan-ip-guard/.env
sudo nano /etc/wan-ip-guard/.env
3. Installeer dependencies
npm install --omit=dev
4. Systemd setup
# State directory
sudo mkdir -p /var/lib/wan-ip-guard
sudo chown $USER:$USER /var/lib/wan-ip-guard
# Pas de paden in systemd/*.service aan naar jouw setup
# (gebruiker, WorkingDirectory, ExecStart)
# Systemd units
sudo cp systemd/wan-ip-guard.service /etc/systemd/system/
sudo cp systemd/wan-ip-guard.timer /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now wan-ip-guard.timer
Configuratie (.env)
| Variabele | Beschrijving | Voorbeeld |
|---|---|---|
DA_LOGIN_KEY |
DirectAdmin Login Key | your_login_key |
DA_USERNAME |
DirectAdmin gebruiker | your_username |
DA_BASE_URL |
DirectAdmin base URL | https://panel.example.com:2222 |
DA_DOMAIN |
Domeinnaam | example.com |
WHATSAPP_API_ENDPOINT |
wwebjs-api URL | http://localhost:3001 |
WHATSAPP_SESSION |
WhatsApp sessie naam | your_session |
ADMIN_PHONE |
Admin telefoonnummer | 31600000000 |
MATRIX_API_ENDPOINT |
Matrix homeserver API | https://whatsed.eddydevink.nl |
MATRIX_TOKEN_FILE |
Bestand met Sherpa compat-token | /home/aiaiaiaiagent/whatsed-new/secrets/sherpa-token |
MATRIX_ROOM_FILE |
Bestand met DM-room voor Eddy | /home/aiaiaiaiagent/whatsed-new/secrets/eddy-report-room |
DNS_RECORDS |
Komma-gescheiden records | example.com,git,www,whatsed,auth.whatsed,calibre |
EURODYNDNS_USER |
EuroDNS site-login (dyndns2) | your_login |
EURODYNDNS_PASS |
EuroDNS site-password (dyndns2) | your_password |
EURODYNDNS_HOSTS |
EuroDynDNS-hostnames (domeinen in EuroDNS-zone) | eddydev.ink,www.eddydev.ink |
STATE_FILE |
Pad naar state file | /var/lib/wan-ip-guard/current_ip |
WAN IP Guard verstuurt het rapport naast WhatsApp ook via de Matrix-bot @sherpa:whatsed.eddydevink.nl naar de bestaande DM-room met @eddy:whatsed.eddydevink.nl. Het compat-token en room-ID staan uitsluitend in de aangegeven bestanden en worden niet in de repository opgeslagen.
DirectAdmin Login Key aanmaken
- Log in op het DirectAdmin panel
- Ga naar Accountbeheer → Login Keys
- Maak een nieuwe key aan met rechten voor DNS Control
- Sla de key op (het wordt maar één keer getoond)
Beheer
# Timer status
systemctl status wan-ip-guard.timer
# Logs volgen
journalctl -u wan-ip-guard -f
# Handmatig draaien
cd ~/wan-ip-guard && node index.js
# Timer herstarten
sudo systemctl restart wan-ip-guard.timer
# State bestand resetten (forceer update bij volgende run)
rm /var/lib/wan-ip-guard/current_ip
Probleemoplossing
"Failed to load environment files: Permission denied"
Systemd (met name versie 259+ op Fedora 44) kan soms geen EnvironmentFile lezen vanuit een user home directory met beperkte rechten (drwx------).
Symptoom: Timer is actief, maar de service faalt elke run met:
wan-ip-guard.service: Failed to load environment files: Permission denied
wan-ip-guard.service: Failed to spawn 'start' task: Permission denied
Oplossing: Verplaats .env naar /etc/wan-ip-guard/.env (zoals de installatie instructies voorschrijven). Systemd kan bestanden in /etc altijd lezen ongeacht user-rechten.
Hoe het werkt
- IP detectie: Haalt het WAN IP op via
https://1.1.1.1/cdn-cgi/trace(Cloudflare, DNS-vrij — werkt als de lokale resolver uitvalt) met fallback naarifconfig.me,api.ipify.orgenicanhazip.com - State vergelijking: Vergelijkt met het laatst opgeslagen IP in de state file
- DNS update: Voor elke record worden eerst alle bestaande A-records met de exacte oude waarde verwijderd en daarna één nieuw A-record toegevoegd via DirectAdmin API. De delete-aanroep gebruikt
action=selecten een URL-gecodeerde waardename=<recordnaam>&value=<oude-ip>in parameterarecs0. De waarde moet dus nietrecordnaam=ipzijn. - EuroDynDNS: Hostnames in
EURODYNDNS_HOSTS(domeinen die in de EuroDNS-zone staan, bv.eddydev.ink) worden bij een IP-wijziging via de EuroDynDNS-update-URL bijgewerkt:https://update.eurodyndns.org/update/?hostname=<fqdn>&myip=<ip>met HTTP Basic auth (EURODYNDNS_USER/EURODYNDNS_PASS, de EuroDNS site-login/password). Een antwoordgood/nochgtelt als succes; een foutcode (badauth,!yours,notfqdn, …) als mislukking. - State persist: Het nieuwe IP wordt pas opgeslagen als alle DNS-updates (DirectAdmin én EuroDynDNS) gelukt zijn. Bij gedeeltelijke mislukking retried de volgende timer-run.
- Notificatie: Stuurt WhatsApp bericht met oud/nieuw IP en status per record.
DirectAdmin A-record verwijderen
De bewezen API-vorm voor één exact A-record is:
CMD_API_DNS_CONTROL?domain=eddydevink.nl&action=select&arecs0=<urlencoded name=<recordnaam>&value=<oude-ip>>
Voorbeeld vóór URL-encoding:
name=changeme&value=94.157.123.170
Encodeer het volledige name=...&value=...-paar. Controleer na de API-call de zone opnieuw; een API-antwoord Records verwijderd is onvoldoende bewijs wanneer het oude record nog in de zone staat.
Files
wan-ip-guard/
├── index.js # Hoofdscript
├── package.json
├── .env.example # Config template
├── deploy.sh # Deployment script
├── systemd/
│ ├── wan-ip-guard.service
│ └── wan-ip-guard.timer
Serverstructuur (nextcloud)
/etc/wan-ip-guard/
├── .env # Config (door root beheerd)
/var/lib/wan-ip-guard/
├── current_ip # Huidig opgeslagen IP
/home/aiaiaiaiagent/wan-ip-guard/
├── index.js # Broncode
├── node_modules/
└── ...