30 Minuten kein Internet. Für alle Clients. Die pfSense-Weboberfläche funktioniert, SSH geht, aber kein einziger Client kommt ins Netz. Das Gateway-Failover auf WAN? Passiert nicht. Die Gateway-Group sagt: Tier 1 (NordVPN WireGuard) ist online.

Spoiler: War es nicht.


Das Setup

pfSense 2.8.1 mit NordVPN über WireGuard als primärer Internet-Gateway. Klassisches Homelab-Setup:

KomponenteKonfiguration
Tunneltun_wg0, NordVPN-Server
Tunnel-IP10.5.0.2
Gateway-GroupTier 1: NordVPN (tun_wg0), Tier 2: WAN
Failover-Triggerdownloss
ClientsMehrere Geräte hinter der pfSense

Die Idee: Normaler Traffic geht durch NordVPN. Fällt der Tunnel aus, failovert die Gateway-Group auf WAN. In der Theorie.


Pitfall 1: dpinger pingt sich selbst

Das Symptom

Gateway-Group zeigt NordVPN als “online”. Kein Failover. Aber der Tunnel ist offensichtlich tot — kein Client kommt raus.

Die Ursache

dpinger ist der Dienst der auf pfSense Gateway-Health überwacht. Er pingt ein Monitor-Target und entscheidet: Gateway up oder down.

Wenn du kein explizites Monitor-Target setzt, pingt dpinger die Interface-IP des Tunnels. Also 10.5.0.2. Das ist die eigene IP. Ein Self-Ping. Der ist natürlich immer erreichbar — das Interface existiert ja lokal.

dpinger Monitor: 10.5.0.2 (eigene IP) → immer erreichbar → Gateway "online"
                                       → kein Failover
                                       → alle Clients hängen

Das Fiese: pfSense resettet das Monitor-Target bei WireGuard-Änderungen. Du hattest es mal richtig konfiguriert? Nach dem nächsten Tunnel-Edit ist es wieder auf der Interface-IP.

Der Fix

Gateway → Edit → Monitor-IP auf das NordVPN-interne Gateway setzen:

Monitor IP: 10.5.0.1

10.5.0.1 ist das NordVPN-Gateway innerhalb des Tunnels. Erreichbar nur wenn der Tunnel tatsächlich steht und Traffic durchlässt. Fällt der Tunnel aus → dpinger kann 10.5.0.1 nicht mehr erreichen → Gateway “down” → Failover auf WAN.

Wichtig: Nach jeder WireGuard-Änderung prüfen ob das Monitor-Target noch stimmt. pfSense hat die Angewohnheit, es stillschweigend zurückzusetzen.


Pitfall 2: Subnetzmaske /32 statt /16

Das Symptom

WireGuard-Handshake ist erfolgreich. 10.5.0.1 antwortet auf Pings. Aber kein Internet-Traffic wird weitergeleitet. Clients hängen trotz aktivem Tunnel.

Die Ursache

NordVPN weist dir 10.5.0.2/16 zu — nicht /32. Das gesamte NordVPN-interne Netz ist 10.5.0.0/16. Wenn du den Tunnel in pfSense mit /32 konfigurierst, passiert folgendes:

  • Handshake funktioniert (Crypto-Layer, unabhängig von Routing)
  • Ping auf 10.5.0.1 funktioniert (direkt am Interface, im selben /32-Netz… nein, eigentlich nicht — aber pfSense routet es trotzdem über den Tunnel wegen der AllowedIPs)
  • Internet-Traffic wird vom NordVPN-Server verworfen

Der NordVPN-Server erwartet, dass dein Client sich als Teil des /16-Netzes meldet. Mit /32 sieht der Server Return-Traffic der nicht in dein Subnetz passt — und droppt ihn.

Der Fix

VPN → WireGuard → Tunnels → tun_wg0:

Interface Address: 10.5.0.2/16

Nicht /32. NordVPN nutzt intern ein /16-Netz. Die Tunnel-Adresse muss das reflektieren.

Wie du es prüfst

# Auf der pfSense-Shell:
ifconfig tun_wg0 | grep inet

Erwartete Ausgabe:

inet 10.5.0.2 netmask 0xffff0000

0xffff0000 = /16. Wenn da 0xffffffff steht (/32), ist es falsch.


Pitfall 3: NordVPN-Endpoint stirbt

Das Symptom

Tunnel war gestern noch stabil. Heute: kein Handshake, 0 Bytes empfangen. Gleicher Server, gleicher Key, gleiche Config.

Die Ursache

NordVPN rotiert Server. Ein Endpoint der gestern funktioniert hat, kann heute tot sein. Kein Announcement, kein Deprecation-Warning. Einfach weg.

Der Fix

Neuen Server finden und den WireGuard-Key neu registrieren. Das ist der Teil den NordVPN nicht dokumentiert.

Schritt 1: Neuen Server finden

# Auf einer beliebigen Linux-Maschine mit curl:
curl -s "https://api.nordvpn.com/v1/servers/recommendations?\
filters\[servers_groups\]\[identifier\]=legacy_standard&\
filters\[servers_technologies\]\[identifier\]=wireguard_udp&\
filters\[country_id\]=81&\
limit=5" | jq '.[].hostname'

country_id=81 = Deutschland. Die API gibt dir aktive Server mit WireGuard-Support.

Dann den Hostnamen auflösen:

dig +short de1247.nordvpn.com
# → 89.46.11.118

Schritt 2: WireGuard-Key registrieren

Hier wird es hässlich. NordVPN hat eine API für Key-Registration — aber die ist hinter Cloudflare und blockiert direkte Aufrufe. Der einzige zuverlässige Weg: Die NordVPN CLI.

# Auf einer Linux-Maschine (kann ein LXC-Container sein):
apt install nordvpn   # oder snap install nordvpn

# Einloggen
nordvpn login

# Token im Browser bestätigen, dann:
nordvpn login --callback "nordvpn://login?action=login&exchange_token=<TOKEN>&status=done"

# WireGuard aktivieren + verbinden (registriert den Key)
nordvpn set technology nordlynx
nordvpn connect de

# Private Key extrahieren
sudo wg show nordlynx private-key
# → dein-base64-private-key=

nordvpn disconnect

Der Trick: nordvpn connect registriert den WireGuard-Key bei NordVPN. Ohne diesen Schritt kennt der neue Server deinen Key nicht und verwirft den Handshake.

Schritt 3: pfSense aktualisieren

VPN → WireGuard → Peers → NordVPN-Peer editieren:

Endpoint: 89.46.11.118
Port: 51820

VPN → WireGuard → Tunnels → tun_wg0:

Private Key: <der Key aus Schritt 2>

Falls du denselben Private Key auf der Linux-Maschine und in pfSense nutzt: Der Key muss nur einmal registriert werden. Du kannst den bestehenden pfSense-Key beibehalten — solange du ihn über die NordVPN CLI registrierst.

Dafür den Key aus pfSense exportieren und auf der Linux-Maschine in die NordVPN-Konfiguration injizieren:

# pfSense Private Key in NordVPN WireGuard-Config eintragen:
sudo bash -c 'echo "<PFSENSE-PRIVATE-KEY>" > /var/lib/nordvpn/nordlynx-private.key'

# Dann verbinden — NordVPN registriert diesen Key
nordvpn connect de
nordvpn disconnect

Bonus: Zabbix-Monitoring für WireGuard

Damit du das nächste Mal nicht 30 Minuten wartest bis jemand “Internet geht nicht” ruft:

# /usr/local/etc/zabbix6/zabbix_agentd.conf.d/wireguard.conf

UserParameter=custom.wireguard.handshake_age[*],/usr/local/bin/sudo /usr/local/bin/wg show $1 latest-handshakes | awk '{t=systime()-$$2; print (t<0?0:t)}'
UserParameter=custom.wireguard.transfer_rx[*],/usr/local/bin/sudo /usr/local/bin/wg show $1 transfer | awk '{print $$2}'
UserParameter=custom.wireguard.transfer_tx[*],/usr/local/bin/sudo /usr/local/bin/wg show $1 transfer | awk '{print $$3}'
UserParameter=custom.wireguard.endpoint[*],/usr/local/bin/sudo /usr/local/bin/wg show $1 endpoints | awk '{print $$2}'

sudoers-Eintrag nicht vergessen:

zabbix ALL=(ALL) NOPASSWD: /usr/local/bin/wg show *

Trigger-Empfehlung:

ItemTrigger
handshake_age[tun_wg0]> 300s → Warning (kein Handshake seit 5 Min)
transfer_rx[tun_wg0]nodata(10m) oder 0 über 10 Min → Problem

Verifikation

# Handshake aktiv?
wg show tun_wg0 latest-handshakes
# → Timestamp < 120 Sekunden

# Traffic fließt?
wg show tun_wg0 transfer
# → rx und tx steigen

# Internet über Tunnel?
curl --interface 10.5.0.2 https://ifconfig.me
# → NordVPN Exit-IP, nicht deine WAN-IP

# Gateway-Group korrekt?
# pfSense GUI → Status → Gateways → NordVPN-Gateway: Online, Delay/Loss sichtbar

Lessons Learned

  1. dpinger Monitor-Target explizit setzen — und nach jedem WireGuard-Edit prüfen. pfSense resettet es stillschweigend. Self-Ping = Gateway immer “online” = kein Failover = alle Clients tot.

  2. NordVPN Tunnel-Adresse ist /16, nicht /32. Handshake klappt mit beiden. Internet nur mit /16. Das macht die Fehlersuche besonders spaßig — “Tunnel steht, aber nichts geht” ist die frustrierendste Kategorie.

  3. NordVPN-Endpoints sterben ohne Vorwarnung. Kein Sunset, kein Redirect. Einfach weg. Monitoring (Zabbix handshake_age) ist Pflicht wenn du keinen manuellen Dead-Server-Check alle paar Tage machen willst.

  4. NordVPN Key-Registration geht nur über die CLI. Die API wird von Cloudflare geblockt. nordvpn connect de auf einer Linux-Maschine registriert den Key. Den Private Key kannst du zwischen pfSense und der CLI-Maschine teilen.

  5. Alle drei Pitfalls zusammen sind besonders gemein. dpinger sagt “online” (Self-Ping), der Tunnel hat Handshake (/32 reicht dafür), aber kein Traffic kommt durch. Du siehst: Gateway up, Tunnel up, Handshake recent — und trotzdem kein Internet. Erst die Kombination aus korrektem Monitor-Target, korrekter Subnetzmaske und lebendem Endpoint ergibt einen funktionierenden Tunnel.