OPNsense HA Umsetzung: Unterschied zwischen den Versionen

Aus Xinux Wiki
Zur Navigation springen Zur Suche springen
Zeile 1: Zeile 1:
=Plan=
+
== Plan ==
{{#drawio:ha-opnsense-kit}}
+
 
 +
{{#drawio:OPNsense Multiwan}}
 +
<!-- Grafik neu zeichnen: die Adressen im Bild (192.168.4.0/24, 172.30.34.0/24)
 +
    stimmen nicht mit der Konfiguration überein. -->
  
== Platzhalter in diesem Artikel ==
 
 
{| class="wikitable"
 
{| class="wikitable"
! Platzhalter !! Bedeutung !! Beispiel
+
! Rolle !! Interface !! Gerät !! Identifier !! IP-Adresse !! Provider-Gateway
 +
|-
 +
| Internes Netz || LAN || em0 || lan || ''LAN-Netz''/24 || –
 
|-
 
|-
| '''HS''' || Drittes Oktett des Schulungsnetzes (WAN), wird vom Trainer vorgegeben || 4
+
| Provider A || WAN1 || em1 || opt2 || 192.168.HS.2XX/24 || 192.168.HS.254
 
|-
 
|-
| '''X''' || Deine Teilnehmernummer, wird vom Trainer vorgegeben || 13
+
| Provider B || WAN2 || em4 || opt4 || 172.30.34.2XX/24 || 172.30.34.254
 
|}
 
|}
  
* Beispiel für X=13 und HS=4: WAN Master 192.168.4.53, WAN Backup 192.168.4.73, WAN-VIP 192.168.4.33, VHID 13
+
''Hinweis: Die Identifier (opt1, opt2, opt3 …) vergibt OPNsense in der Reihenfolge, in der die
* '''Alle Passwörter in diesem Artikel sind Laborwerte und dürfen so niemals in eine produktive Umgebung übernommen werden.'''
+
Interfaces angelegt werden. Sie müssen nicht fortlaufend zu den Gerätenamen passen – wichtig ist
 +
nur, dass sie in Gateways, DNS und Regeln konsistent referenziert werden.''
 +
 
 +
''In dieser Umsetzung ist '''WAN2 die primäre Leitung''' (Tier 1). WAN1 dient als Backup (Tier 2).''
  
=Wichtig=
+
== Was müssen wir tun? ==
* Die Netzwerkkarten für LAN und WAN müssen '''im Hypervisor''' in den Promiscuous-Modus geschaltet werden – nicht in OPNsense.
 
** VirtualBox: Maschine => Ändern => Netzwerk => Adapter => Erweitert => Promiscuous-Modus: '''Alle erlauben'''
 
** Proxmox: Bridge ohne MAC-Filter bzw. entsprechende Bridge-Einstellung
 
* Das gilt sowohl für den Master als auch für das Backup.
 
  
;Begründung
+
* 2 WAN-Interfaces anlegen
* CARP verwendet virtuelle MAC-Adressen für die gemeinsame VIP. In virtualisierten Umgebungen werden Frames mit diesen MAC-Adressen vom Hypervisor standardmäßig verworfen, da sie nicht der echten VM-NIC zugeordnet sind. Ohne aktivierten Promiscuous-Modus erreichen CARP-Advertisements den Partner nicht, was zu Fehldetektion, unerwünschtem Failover und HA-Inkonsistenzen führt.
+
* 2 Gateways definieren
 +
* Eine Gatewaygruppe erstellen
 +
* Die Internetleitungen überwachen (Healthcheck über Monitor-IP)
 +
* Eine Entscheidungsinstanz schaffen: die Gatewaygruppe entscheidet über Tier und Trigger Level
 +
* Zuordnung klären: Policy Routing über die Gateway-Angabe in der Firewallregel
 +
* DNS-Server pro Leitung zuordnen
 +
* Firewallregeln anpassen (Reihenfolge beachten!)
 +
* NAT-Regeln anpassen
 +
* Szenarien testen
  
= Vorbereitung =
+
== Konfiguration ==
* Zwei OPNsense-Installationen mit jeweils mind. 3 Netzwerkkarten
 
* Auf beiden Maschinen muss die '''gleiche OPNsense-Version''' laufen
 
* Die Anzahl der Netzwerkkarten muss auf beiden Maschinen gleich sein
 
* '''Die Reihenfolge und Anzahl der Netzwerkschnittstellen muss auf beiden Maschinen identisch sein!'''
 
* Empfehlung für beide Maschinen:
 
** em0: LAN
 
** em1: WAN
 
** em2: SYN
 
* Am Anfang sollten so wenige Dienste wie möglich laufen
 
  
== IP-Adressen der Master Firewall ==
+
=== Interface WAN1 ===
* em0 (LAN): 192.168.1.1/24
 
* em1 (WAN): 192.168.HS.X+40/24
 
* em2 (SYN): 100.64.64.1/30
 
  
== IP-Adressen der Backup Firewall ==
+
''Interfaces: [WAN1]''
* em0 (LAN): 192.168.1.2/24
 
* em1 (WAN): 192.168.HS.X+60/24
 
* em2 (SYN): 100.64.64.2/30
 
  
== Übersicht ==
 
 
{| class="wikitable"
 
{| class="wikitable"
! !! Master (opns-ha1) !! Backup (opns-ha2) !! VIP !! VHID
+
! Feld !! Wert
 
|-
 
|-
| LAN (em0) || 192.168.1.1 || 192.168.1.2 || 192.168.1.3 || 100
+
| Enable || aktiv
 
|-
 
|-
| WAN (em1) || 192.168.HS.X+40 || 192.168.HS.X+60 || 192.168.HS.X+20 || X
+
| Device || em1
|-
 
| SYN (em2) || 100.64.64.1 || 100.64.64.2 || – || –
 
|}
 
 
 
* Die VHID muss nur innerhalb einer Broadcast-Domäne eindeutig sein, der Wertebereich ist 1 bis 255.
 
* Da sich alle Teilnehmer das WAN-Segment teilen, wird dort die Teilnehmernummer X verwendet (1 bis 13).
 
* Das LAN ist pro Teilnehmer ein eigenes, isoliertes Segment. Dort steht deshalb bei allen Teilnehmern fest die 100. Der Abstand zum WAN-Bereich ist Absicht: dreistellig = LAN, zweistellig = WAN.
 
 
 
= Firewall Regeln (beide Firewalls) =
 
* Auf allen Schnittstellen '''außer''' dem SYN-Interface muss das Protokoll CARP akzeptiert werden
 
* Dazu muss im Menü '''Firewall => Rules => {WAN, LAN}''' je eine Allow-Regel erstellt werden, die auf das CARP-Protokoll matcht
 
* Für das SYN-Interface kann man eine Standard-Allow-Regel erstellen, die alles erlaubt
 
 
 
= Virtuelle IPs (Master Firewall) =
 
* Die virtuellen IPs werden von den Knoten des HA-Clusters geteilt, sobald ein Ausfall erkannt wird
 
* Somit wird dafür gesorgt, dass die virtuelle IP immer erreichbar ist
 
* Die virtuelle IP wird '''nur''' auf der Master Firewall eingestellt und an die Backups mitgeteilt
 
* Dazu muss man im Menü '''Interfaces => Virtual IPs => Settings''' an allen Schnittstellen bis auf das SYN-Interface die gewünschten IPs vergeben
 
* Über das '''[+]''' auf der rechten Seite muss man folgende Einträge machen:
 
 
 
== virtuelle WAN IP ==
 
{| class="wikitable"
 
! Parameter !! Wert
 
 
|-
 
|-
| Mode || CARP
+
| Description || WAN1
 
|-
 
|-
| Interface || WAN
+
| Block private networks || aus
 
|-
 
|-
| Address || 192.168.HS.X+20/24
+
| Block bogon networks || aus
 
|-
 
|-
| Virtual Password || radler
+
| IPv4 Configuration Type || Static IPv4
 
|-
 
|-
| VHID Group || X
+
| IPv6 Configuration Type || None
 
|-
 
|-
| Advertising Frequency || 1
+
| IPv4 address || 192.168.HS.2XX/24
 
|-
 
|-
| Description || Virtual WAN IP
+
| IPv4 Upstream Gateway || WAN1GW
 
|}
 
|}
  
== virtuelle LAN IP ==
+
'''Wichtig:''' Die Präfixlänge <code>/24</code> darf nicht fehlen, sonst wird das Interface mit /32
 +
angelegt und das Gateway ist nicht erreichbar.
 +
 
 +
=== Interface WAN2 ===
 +
 
 +
''Interfaces: [WAN2]''
 +
 
 
{| class="wikitable"
 
{| class="wikitable"
! Parameter !! Wert
+
! Feld !! Wert
 
|-
 
|-
| Mode || CARP
+
| Enable || aktiv
 
|-
 
|-
| Interface || LAN
+
| Device || em4
 +
|-
 +
| Description || WAN2
 +
|-
 +
| Block private networks || aus
 
|-
 
|-
| Address || 192.168.1.3/24
+
| Block bogon networks || aus
 
|-
 
|-
| Virtual Password || radler
+
| IPv4 Configuration Type || Static IPv4
 
|-
 
|-
| VHID Group || 100
+
| IPv6 Configuration Type || None
 
|-
 
|-
| Advertising Frequency || 1
+
| IPv4 address || 172.30.34.2XX/24
 
|-
 
|-
| Description || Virtual LAN IP
+
| IPv4 Upstream Gateway || WAN2GW
 
|}
 
|}
  
= Source NAT (Master Firewall) =
+
=== Einstellen der Gateways ===
* Da die virtuelle IP für ausgehende Verbindungen benutzt werden soll, muss die automatische Regelgenerierung ausgeschaltet werden
+
 
* Im Menü '''Firewall => NAT => Outbound''' muss die Option "Manual outbound NAT rule generation" ausgewählt werden
+
''System: Gateways: Configuration''
* Dann die folgende Regel erstellen:
 
** Interface: WAN
 
** Source address: LAN net
 
** Translation / target: '''Virtual WAN IP (192.168.HS.X+20)''' aus der Auswahlliste
 
;Achtung
 
* Als Ziel muss der VIP-Eintrag aus der Auswahlliste gewählt werden, nicht das Netz 192.168.HS.0/24. Trägt man ein ganzes Netz ein, baut OPNsense daraus einen NAT-Pool.
 
  
= High Availability Konfiguration (Master Firewall) =
 
* Die eigentliche HA-Einstellung erfolgt über das Menü '''System => High Availability => Settings''':
 
 
{| class="wikitable"
 
{| class="wikitable"
! Parameter !! Wert
+
! Feld !! GW1 !! GW2
 
|-
 
|-
| Synchronize all states via || SYN
+
| Name || WAN1GW || WAN2GW
 
|-
 
|-
| Sync compatibility || OPNsense 24.7 or above
+
| Interface || WAN1 || WAN2
 
|-
 
|-
| Synchronize Peer IP || 100.64.64.2
+
| Address Family || IPv4 || IPv4
 
|-
 
|-
| Synchronize Config || 100.64.64.2
+
| IP Address || 192.168.HS.254 || 172.30.34.254
 
|-
 
|-
| Verify peer || deaktiviert
+
| Upstream Gateway || '''aktiv''' || '''aktiv'''
 
|-
 
|-
| Remote System Username || root
+
| Far Gateway || aus || aus
 
|-
 
|-
| Remote System Password || 123Start$
+
| Disable Gateway Monitoring || aus || aus
 
|-
 
|-
| Services || Aliases, Firewall Rules, NAT, Virtual IPs
+
| Monitor IP || 9.9.9.9 || 208.67.222.222
 +
|-
 +
| Priority || 255 || 254
 
|}
 
|}
  
* "Verify peer" bleibt deaktiviert, weil die Web-GUI der Gegenstelle ein selbstsigniertes Zertifikat verwendet.
+
Drei Punkte, die häufig falsch gemacht werden:
 +
 
 +
* '''Upstream Gateway''' muss bei ''beiden'' Gateways gesetzt sein. Es kennzeichnet ein Gateway als
 +
  Internet-Ausgang; ist es nur bei einem gesetzt, verhält sich das Failover unvorhersehbar.
 +
* Die '''Monitor-IPs müssen bei verschiedenen Betreibern liegen''' und dürfen nicht mit den
 +
  DNS-Servern identisch sein. 8.8.8.8 und 8.8.4.4 gehören beide Google: fällt Google aus, werden
 +
  beide Leitungen als tot gemeldet. Für jede Monitor-IP legt OPNsense zusätzlich eine Hostroute über
 +
  das jeweilige Gateway an; benutzt man dieselbe IP auch als DNS-Server, überlagern sich Hostroute
 +
  und DNS-Zuordnung.
 +
* Die niedrigere '''Priority''' gewinnt bei der Wahl des '''Default-Gateways'''. Das Default-Gateway
 +
  bestimmt den Ausgang für den Eigenverkehr der Firewall (Updates, NTP, rekursiver Resolver) – es ist
 +
  unabhängig von der Gatewaygruppe. Damit die primäre Leitung WAN2 auch das Default-Gateway stellt,
 +
  bekommt '''WAN2GW die niedrigere Priority (254)''' und WAN1GW die höhere (255). Stünden beide gleich,
 +
  wäre die Wahl zufällig.
 +
 
 +
=== Einstellen der Gatewaygruppe ===
 +
 
 +
''System: Gateways: Group''
  
= High Availability Konfiguration (Backup Firewall) =
 
* Hier darf im Menü '''System => High Availability => Settings''' nur folgendes eingestellt werden:
 
 
{| class="wikitable"
 
{| class="wikitable"
! Parameter !! Wert
+
! Feld !! Wert
 
|-
 
|-
| Synchronize all states via || SYN
+
| Group Name || GW_GROUP
 
|-
 
|-
| Sync compatibility || OPNsense 24.7 or above
+
| Gateway Priority || WAN2GW = Tier 1, WAN1GW = Tier 2
 
|-
 
|-
| Synchronize Peer IP || 100.64.64.1
+
| Trigger Level || '''Member Down'''
 
|-
 
|-
| Synchronize Config || leer
+
| Pool Options || Default
 +
|}
 +
 
 +
{| class="wikitable"
 +
! Ziel !! Tier-Vergabe !! Trigger Level
 
|-
 
|-
| Verify peer || deaktiviert
+
| Failover (Standard hier) || WAN2GW = Tier 1, WAN1GW = Tier 2 || Member Down
 
|-
 
|-
| Remote System Username || leer
+
| Lastverteilung || beide Tier 1 || Packet Loss or High Latency
 +
|}
 +
 
 +
''Bei Lastverteilung zusätzlich'' ''Firewall: Settings: Advanced'' → ''Sticky connections''
 +
''aktivieren, sonst wechseln einzelne Verbindungen desselben Clients die Leitung.''
 +
 
 +
'''Merke:''' Tier steuert das Failover des '''Client-Verkehrs''' (über die Firewallregel mit
 +
GW_GROUP). Die Priority steuert das '''Default-Gateway''' (Eigenverkehr der Firewall). Beide müssen
 +
zusammenpassen – sonst laufen Nutzverkehr und DNS über verschiedene Leitungen, und das Verhalten wirkt
 +
widersprüchlich.
 +
 
 +
=== DNS pro Leitung ===
 +
 
 +
''System: Settings: General''
 +
 
 +
{| class="wikitable"
 +
! DNS Server !! Use gateway
 
|-
 
|-
| Remote System Password || leer
+
| 8.8.8.8 || WAN1GW
 
|-
 
|-
| Services || Nothing selected
+
| 1.1.1.1 || WAN2GW
 
|}
 
|}
  
* '''Synchronize Config''' muss auf dem Backup leer bleiben. Trägt man hier den Master ein, schieben sich beide Knoten gegenseitig ihre Konfiguration zu.
+
* ''Prefer IPv4 over IPv6'': aktiv
 +
* Die Zuordnung sorgt dafür, dass jeder DNS-Server über „seine“ Leitung befragt wird. Fällt eine
 +
  Leitung aus, bleibt der andere Resolver erreichbar.
 +
* '''Voraussetzung:''' Die „Use gateway“-Zuordnung greift nur, wenn Unbound im '''Forwarding-Modus'''
 +
  läuft (''Services: Unbound DNS: General'' → ''Enable Forwarding Mode''). Im Standard-Resolving-Modus
 +
  löst Unbound rekursiv selbst auf und geht dabei über das Default-Gateway – dann ist die Zuordnung
 +
  wirkungslos.
  
= Client im LAN =
+
=== NAT auf beiden WAN-Interfaces ===
* Der Windows-Client (192.168.1.50) muss als '''Gateway''' und als '''DNS-Server''' die LAN-VIP '''192.168.1.3''' erhalten – nicht die 192.168.1.1
 
* Wird die echte IP des Masters eingetragen, ist der Client beim Ausfall des Masters trotz funktionierendem Cluster offline
 
* Bei Verwendung eines DHCP-Servers muss dieser die VIP als Gateway und DNS verteilen
 
  
= Endergebnis =
+
''Firewall: NAT: Outbound'' – manuelle Regeln (Protokoll und Ports jeweils <code>*</code>, IPv4)
==Master==
 
* System
 
** High Availability
 
*** Status
 
* Hier müssen beide Spalten gefüllt sein und auf beiden Knoten die gleichen Dienste erscheinen:
 
  
 
{| class="wikitable"
 
{| class="wikitable"
! Service !! Description
+
! # !! Interface !! Source !! Destination !! Translate / target !! Beschreibung
 
|-
 
|-
| configd || System Configuration Daemon
+
| 1 || WAN1 || LAN network || * || Interface address || LAN ins Internet
 
|-
 
|-
| cron || Cron
+
| 2 || WAN1 || SERVER network || * || Interface address || SERVER ins Internet
 
|-
 
|-
| hostwatch || Host discovery service
+
| 3 || WAN1 || DMZ network || <code>! 10.88.0.0/16</code> || Interface address || DMZ ins Internet – kein NAT zu den anderen DMZs
 
|-
 
|-
| login || Users and Groups
+
| 4 || WAN2 || LAN network || * || Interface address || LAN ins Internet
 
|-
 
|-
| ntpd || Network Time Daemon
+
| 5 || WAN2 || SERVER network || * || Interface address || SERVER ins Internet
 
|-
 
|-
| openssh || Secure Shell Daemon
+
| 6 || WAN2 || DMZ network || <code>! 10.88.0.0/16</code> || Interface address || DMZ ins Internet – kein NAT zu den anderen DMZs
|-
 
| pf || Packet Filter
 
|-
 
| routing || System routing
 
|-
 
| sysctl || System tunables
 
|-
 
| syslog-ng || Syslog-ng Daemon
 
|-
 
| unbound || Unbound DNS
 
|-
 
| webgui || Web GUI
 
 
|}
 
|}
  
==Slave==
+
Das Ausrufezeichen vor dem Zielnetz invertiert die Bedingung: Die Regel greift für alle Ziele
* System
+
'''außer''' <code>10.88.0.0/16</code>. Verkehr aus der DMZ zu den übrigen internen Netzen wird
** High Availability
+
also nicht übersetzt und behält seine Quelladresse – nur so bleiben Logs und Firewallregeln
*** Status
+
auf den Zielsystemen auswertbar.
* Auf der Backup-Firewall erscheint hier die Warnung, dass die XMLRPC-Konfiguration unvollständig sei.
 
* Diese Meldung kann ignoriert werden: Das Backup empfängt nur passiv, deshalb sind die XMLRPC-Felder dort absichtlich leer und werden fälschlicherweise als "unvollständig" markiert. Solange die Master-Firewall auf Version 24.7 eingestellt ist und die Daten erfolgreich überträgt, arbeitet der Cluster technisch einwandfrei.
 
  
= Failover testen =
+
''Jede Regel existiert doppelt, einmal je WAN-Interface. Das ist bei Multiwan zwingend: Welche
* Auf dem Client einen Dauerping nach draußen starten:
+
Leitung genutzt wird, entscheidet das Policy Routing der Firewallregel; die passende NAT-Regel
ping -t 192.168.HS.254
+
muss auf beiden Wegen bereitstehen.''
* Auf dem '''Master''': System => High Availability => Status => '''Enter persistent CARP maintenance mode'''
 
* Erwartetes Verhalten:
 
** Das Backup wechselt für beide VHIDs von BACKUP auf MASTER
 
** Der Ping läuft weiter oder verliert maximal ein bis zwei Pakete
 
* Kontrolle auf beiden Knoten:
 
ifconfig em0 ; ifconfig em1
 
* Zurückschalten über '''Leave persistent CARP maintenance mode''' auf dem Master
 
* Zweiter Test: Master hart ausschalten (VM stoppen) und das gleiche Verhalten prüfen
 
  
=Debugging=
+
=== Firewallregeln mit Gateway-Gruppe ===
  
== Vorgehen ==
+
''Firewall: Rules: LAN'' '''die Reihenfolge ist entscheidend:'''
* Von unten nach oben prüfen: erst CARP (Layer 2/3), dann pfsync (States), dann XMLRPC (Konfiguration)
 
* Ein Cluster kann sauber synchronisieren und trotzdem kein Failover können und umgekehrt
 
  
== Schritt 1: CARP-Status ==
 
* Auf beiden Knoten:
 
ifconfig em0 ; ifconfig em1
 
* Erwartetes Bild:
 
 
{| class="wikitable"
 
{| class="wikitable"
! Knoten !! LAN (vhid 100) !! WAN (vhid X)
+
! # !! Action !! Source !! Destination !! Gateway !! Zweck
 +
|-
 +
| 1 || Pass || LAN net || This Firewall || ''leer (default)'' || DNS, NTP, Web-GUI
 
|-
 
|-
| Master || MASTER, advskew 0 || MASTER, advskew 0
+
| 2 || Pass || LAN net || Alias LOKALE_NETZE || ''leer (default)'' || interne Netze, DMZ, VPN
 
|-
 
|-
| Backup || BACKUP, advskew 100 || BACKUP, advskew 100
+
| 3 || Pass || LAN net || any || '''GW_GROUP''' || Internetverkehr über die Gruppe
 
|}
 
|}
* In der GUI: '''Interfaces => Virtual IPs => Status'''
 
* CARP global ein-/ausgeschaltet:
 
sysctl net.inet.carp.allow
 
* Ausführlichere CARP-Meldungen im Log einschalten:
 
sysctl net.inet.carp.log=2
 
  
== Schritt 2: Beide Knoten sind MASTER (Split Brain) ==
+
Regel 3 im Detail:
* Das häufigste Fehlerbild im Labor. Beide Knoten sehen den Partner nicht und übernehmen die VIP.
+
 
* Prüfen, ob die Advertisements des Partners überhaupt ankommen:
 
tcpdump -n -i em1 proto 112
 
tcpdump -n -i em0 proto 112
 
* Man muss die Pakete '''beider''' Knoten sehen (Quelle = jeweils die echte Interface-IP)
 
 
{| class="wikitable"
 
{| class="wikitable"
! Beobachtung !! Ursache
+
! Feld !! Wert
 +
|-
 +
| Action || Pass
 +
|-
 +
| Quick || aktiv
 +
|-
 +
| Interface || LAN
 
|-
 
|-
| Nur eigene Pakete sichtbar || Promiscuous-Modus im Hypervisor fehlt
+
| Direction || in
 
|-
 
|-
| Gar keine Pakete sichtbar || VIP nicht angelegt oder Interface down
+
| TCP/IP Version || IPv4
 
|-
 
|-
| Pakete kommen an, trotzdem beide MASTER || CARP-Allow-Regel auf dem Interface fehlt
+
| Protocol || any
 
|-
 
|-
| Pakete mit fremder VHID || Anderer Teilnehmer nutzt die gleiche VHID
+
| Source || LAN net
 +
|-
 +
| Destination || any
 +
|-
 +
| Description || LAN to any über Gateway-Gruppe
 +
|-
 +
| Gateway || GW_GROUP
 
|}
 
|}
* Weitere Ursachen bei Split Brain:
 
** Unterschiedliches '''Virtual Password''' auf den beiden Knoten
 
** Unterschiedliche '''VHID''' auf den beiden Knoten
 
** Unterschiedliche '''Advertising Frequency'''
 
  
== Schritt 3: Kein Failover trotz korrektem Status ==
+
'''Der klassische Fehler:''' Nur eine einzige Regel mit Gateway GW_GROUP. Eine Gateway-Angabe
* Demotion-Zähler prüfen ist er größer als 0, bleibt der Knoten absichtlich BACKUP:
+
erzwingt Policy Routing für ''alles'', was auf die Regel passt auch für Pakete an die DMZ, an
sysctl net.inet.carp.demotion
+
VPN-Gegenstellen und an die Firewall selbst. Diese Pakete werden dann in Richtung Internet
* Ursachen für einen erhöhten Zähler: ein Interface ist down, ein Dienst startet nicht sauber, der Knoten befindet sich noch im Maintenance Mode
+
geschickt und verschwinden. Deshalb müssen die Regeln 1 und 2 ''ohne'' Gateway-Angabe darüber
* Maintenance Mode verlassen: '''System => High Availability => Status => Leave persistent CARP maintenance mode'''
+
stehen.
  
== Schritt 4: Sicht des Clients ==
+
Der Alias <code>LOKALE_NETZE</code> (''Firewall: Aliases'', Typ Network) enthält alle eigenen
* Auf dem Windows-Client prüfen, welche MAC hinter dem Gateway steckt:
+
Netze, z. B. die LAN-, DMZ- und VPN-Bereiche.
arp -a
 
* Die LAN-VIP muss auf eine virtuelle MAC zeigen, nicht auf die echte NIC des Masters:
 
192.168.1.3    00-00-5e-00-01-64
 
* Das letzte Byte ist die VHID in hex – 0x64 = 100
 
* Steht dort eine 08:00:27:... Adresse, arbeitet der Client an CARP vorbei direkt mit einer echten Firewall-IP
 
* Nach einem Failover darf sich der ARP-Eintrag '''nicht''' ändern – genau das ist der Sinn der virtuellen MAC
 
  
== Schritt 5: Zustandssynchronisation (pfsync) ==
+
=== Firewall: Settings: Advanced ===
* Läuft der pfsync-Verkehr über das SYN-Netz?
 
tcpdump -n -i em2 proto 240
 
* Anzahl der States auf beiden Knoten vergleichen – die Werte müssen ähnlich sein:
 
pfctl -s state | wc -l
 
* Ist die Zahl auf dem Backup dauerhaft 0, überträgt pfsync nicht:
 
** '''Synchronize Peer IP''' zeigt auf die falsche Adresse
 
** Die Allow-Regel auf dem SYN-Interface fehlt
 
** SYN-Interface auf einem der Knoten nicht aktiviert
 
  
== Schritt 6: Konfigurationssynchronisation (XMLRPC) ==
 
* Auf der Master-Firewall: '''System => Log Files => General''', im Filter-Feld '''xmlrpc''' eingeben
 
* Gesucht wird ein Eintrag wie: '''[OK] Configuration synchronized to''' https://100.64.64.2:443
 
* Manuell anstoßen: '''System => High Availability => Status => Synchronize and reconfigure all (Push)'''
 
* Gleichzeitig auf dem Backup mitlesen:
 
tail -f /var/log/configd/latest.log
 
 
{| class="wikitable"
 
{| class="wikitable"
! Meldung !! Ursache
+
! Option !! Empfehlung !! Wirkung
 
|-
 
|-
| Connection refused || Web-GUI des Backups nicht erreichbar oder falscher Port
+
| Skip rules when gateway is down || aktiv || Bei totem Gateway wird die Regel entfernt statt auf das Default-Gateway zurückzufallen – verhindert stillen Rückfall auf die falsche Leitung
 
|-
 
|-
| Authentication failed || Falsches Passwort unter "Remote System Password"
+
| Allow default gateway switching || aktiv || Fällt das Default-Gateway (WAN2GW) aus, zieht OPNsense das Default automatisch auf WAN1GW – so folgt auch der Eigenverkehr der Firewall (inkl. rekursivem DNS) der aktiven Leitung
 
|-
 
|-
| Certificate verify failed || "Verify peer" ist aktiviert, Zertifikat ist selbstsigniert
+
| Sticky connections || nur bei Lastverteilung || hält alle Verbindungen eines Clients auf derselben Leitung
|-
 
| Endlose Sync-Schleife || Auf dem Backup ist "Synchronize Config" gefüllt – muss leer sein
 
 
|}
 
|}
  
== Schritt 7: Ausgehende Verbindungen ==
+
== Szenarien testen ==
* Prüfen, mit welcher Quelladresse der Client nach draußen geht:
+
 
  tcpdump -n -i em1 host 192.168.HS.254
+
Welche Public-IP je Leitung anliegt, prüft man direkt an den WAN-Geräten:
* Es muss die Virtual WAN IP (192.168.HS.X+20) erscheinen, nicht die echte IP des Masters
+
 
* Erscheint die echte IP: Outbound-NAT steht noch auf automatisch, oder in der manuellen Regel wurde als Target nicht die VIP gewählt
+
  curl -sS -4 --interface em1 ifconfig.co
 +
62.159.72.206
 +
curl -sS -4 --interface em4 ifconfig.co
 +
194.59.156.244
 +
 
 +
'''Zieladresse für den Traceroute-Test bewusst wählen:''' weder eine Monitor-IP (9.9.9.9,
 +
208.67.222.222) noch einen der konfigurierten DNS-Server (8.8.8.8, 1.1.1.1) nehmen. OPNsense legt
 +
für diese Adressen Hostrouten über eine feste Leitung an – dann misst man nicht die Gatewaygruppe,
 +
sondern die Hostroute.
  
== Nützliche Befehle im Überblick ==
 
 
{| class="wikitable"
 
{| class="wikitable"
! Befehl !! Zweck
+
! Szenario !! Vorgehen !! Erwartetes Ergebnis
|-
 
| ifconfig em0 ; ifconfig em1 || CARP-Rolle und VIPs anzeigen
 
|-
 
| tcpdump -n -i em1 proto 112 || CARP-Advertisements mitlesen
 
|-
 
| tcpdump -n -i em2 proto 240 || pfsync-Verkehr mitlesen
 
 
|-
 
|-
| pfctl -s state {{!}} wc -l || Anzahl der Firewall-States
+
| Normalbetrieb || <code>traceroute -n heise.de</code> von der Firewall || erster externer Hop 172.30.34.254 (WAN2GW, Tier 1)
 
|-
 
|-
| sysctl net.inet.carp.demotion || Demotion-Zähler
+
| Ausfall WAN2 || Kabel in VirtualBox trennen || Dashboard zeigt WAN2GW offline, Verkehr läuft über 192.168.HS.254 (WAN1GW)
 
|-
 
|-
| sysctl net.inet.carp.log=2 || Ausführliches CARP-Logging
+
| Rückkehr WAN2 || Kabel wieder verbinden || WAN2GW wieder online, neue Verbindungen laufen über WAN2
 
|-
 
|-
| tail -f /var/log/configd/latest.log || Konfigurationssync mitlesen
+
| DNS-Test || <code>dig @8.8.8.8</code> und <code>dig @1.1.1.1</code> || beide antworten, jeder über seine Leitung
 
|-
 
|-
| configctl filter reload || Regelwerk neu laden
+
| Zugriff intern || Ping in DMZ bei totem WAN2 || funktioniert weiter (Regel 2 ohne Gateway)
 
|}
 
|}
  
==Netzwerkschnittstellen==
+
'''Wer routet gerade wohin?''' Drei Instanzen entscheiden unabhängig und lassen sich getrennt ablesen:
=== Master ===
 
em0: flags=1008943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST,LOWER_UP> metric 0 mtu 1500
 
description: LAN (lan)
 
options=48500b8<VLAN_MTU,VLAN_HWTAGGING,JUMBO_MTU,VLAN_HWCSUM,VLAN_HWFILTER,VLAN_HWTSO,HWSTATS,MEXTPG>
 
ether 08:00:27:c4:a2:6f
 
inet 192.168.1.1 netmask 0xffffff00 broadcast 192.168.1.255
 
'''inet 192.168.1.3 netmask 0xffffff00 broadcast 192.168.1.255 vhid 100'''
 
'''carp: MASTER vhid 100 advbase 1 advskew 0'''
 
      '''peer 224.0.0.18 peer6 ff02::12'''
 
media: Ethernet autoselect (1000baseT <full-duplex>)
 
status: active
 
nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
 
  
em1: flags=1008943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST,LOWER_UP> metric 0 mtu 1500
+
* das '''Default-Gateway''' (Eigenverkehr der Firewall) unter ''Interfaces: Diagnostics: Routes''
description: WAN (wan)
+
* die '''States''' (welche Verbindung über welches Interface läuft) unter ''Firewall: Diagnostics: States''
options=48500b8<VLAN_MTU,VLAN_HWTAGGING,JUMBO_MTU,VLAN_HWCSUM,VLAN_HWFILTER,VLAN_HWTSO,HWSTATS,MEXTPG>
+
* das '''Policy Routing''' der Gruppe – Statuswechsel mit Zeitstempel im ''System: Gateways: Log File''
ether 08:00:27:61:6f:6d
 
inet 192.168.HS.X+40 netmask 0xffffff00 broadcast 192.168.HS.255
 
'''inet 192.168.HS.X+20 netmask 0xffffff00 broadcast 192.168.HS.255 vhid X'''
 
'''carp: MASTER vhid X advbase 1 advskew 0'''
 
      '''peer 224.0.0.18 peer6 ff02::12'''
 
media: Ethernet autoselect (1000baseT <full-duplex>)
 
status: active
 
nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
 
  
=== Backup ===
+
Nach einem Failover ist für ~10–20 s ein Mischbild normal: bestehende States bleiben auf der alten
em0: flags=1008943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST,LOWER_UP> metric 0 mtu 1500
+
Leitung, bis sie ablaufen; nur neue Verbindungen nehmen sofort den neuen Weg.
description: LAN (lan)
 
options=48500b8<VLAN_MTU,VLAN_HWTAGGING,JUMBO_MTU,VLAN_HWCSUM,VLAN_HWFILTER,VLAN_HWTSO,HWSTATS,MEXTPG>
 
ether 08:00:27:1c:44:8b
 
inet 192.168.1.2 netmask 0xffffff00 broadcast 192.168.1.255
 
'''inet 192.168.1.3 netmask 0xffffff00 broadcast 192.168.1.255 vhid 100'''
 
'''carp: BACKUP vhid 100 advbase 1 advskew 100'''
 
      '''peer 224.0.0.18 peer6 ff02::12'''
 
media: Ethernet autoselect (1000baseT <full-duplex>)
 
status: active
 
nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
 
  
em1: flags=1008943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST,LOWER_UP> metric 0 mtu 1500
+
Weitere Statusanzeige: ''Lobby: Dashboard'' (Widget Gateways).
description: WAN (wan)
 
options=48500b8<VLAN_MTU,VLAN_HWTAGGING,JUMBO_MTU,VLAN_HWCSUM,VLAN_HWFILTER,VLAN_HWTSO,HWSTATS,MEXTPG>
 
ether 08:00:27:95:9b:4b
 
inet 192.168.HS.X+60 netmask 0xffffff00 broadcast 192.168.HS.255
 
'''inet 192.168.HS.X+20 netmask 0xffffff00 broadcast 192.168.HS.255 vhid X'''
 
'''carp: BACKUP vhid X advbase 1 advskew 100'''
 
      '''peer 224.0.0.18 peer6 ff02::12'''
 
media: Ethernet autoselect (1000baseT <full-duplex>)
 
status: active
 
nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
 
  
* Der Master hat '''advskew 0''', das Backup '''advskew 100'''. Diesen Wert setzt OPNsense beim Sync automatisch – er wird nicht von Hand vergeben.
+
== Umsetzung ==
  
==Wird Synchronisiert?==
+
* https://docs.opnsense.org/manual/how-tos/multiwan.html
;Master
 
* System
 
** High Availability
 
*** Status
 
**** Synchronize and reconfigure all (Push)
 
;Backup
 
tail -f /var/log/configd/latest.log
 
* Hier sollte man die Übertragung sehen.
 

Version vom 3. September 2026, 14:48 Uhr

Plan

Rolle Interface Gerät Identifier IP-Adresse Provider-Gateway
Internes Netz LAN em0 lan LAN-Netz/24
Provider A WAN1 em1 opt2 192.168.HS.2XX/24 192.168.HS.254
Provider B WAN2 em4 opt4 172.30.34.2XX/24 172.30.34.254

Hinweis: Die Identifier (opt1, opt2, opt3 …) vergibt OPNsense in der Reihenfolge, in der die Interfaces angelegt werden. Sie müssen nicht fortlaufend zu den Gerätenamen passen – wichtig ist nur, dass sie in Gateways, DNS und Regeln konsistent referenziert werden.

In dieser Umsetzung ist WAN2 die primäre Leitung (Tier 1). WAN1 dient als Backup (Tier 2).

Was müssen wir tun?

  • 2 WAN-Interfaces anlegen
  • 2 Gateways definieren
  • Eine Gatewaygruppe erstellen
  • Die Internetleitungen überwachen (Healthcheck über Monitor-IP)
  • Eine Entscheidungsinstanz schaffen: die Gatewaygruppe entscheidet über Tier und Trigger Level
  • Zuordnung klären: Policy Routing über die Gateway-Angabe in der Firewallregel
  • DNS-Server pro Leitung zuordnen
  • Firewallregeln anpassen (Reihenfolge beachten!)
  • NAT-Regeln anpassen
  • Szenarien testen

Konfiguration

Interface WAN1

Interfaces: [WAN1]

Feld Wert
Enable aktiv
Device em1
Description WAN1
Block private networks aus
Block bogon networks aus
IPv4 Configuration Type Static IPv4
IPv6 Configuration Type None
IPv4 address 192.168.HS.2XX/24
IPv4 Upstream Gateway WAN1GW

Wichtig: Die Präfixlänge /24 darf nicht fehlen, sonst wird das Interface mit /32 angelegt und das Gateway ist nicht erreichbar.

Interface WAN2

Interfaces: [WAN2]

Feld Wert
Enable aktiv
Device em4
Description WAN2
Block private networks aus
Block bogon networks aus
IPv4 Configuration Type Static IPv4
IPv6 Configuration Type None
IPv4 address 172.30.34.2XX/24
IPv4 Upstream Gateway WAN2GW

Einstellen der Gateways

System: Gateways: Configuration

Feld GW1 GW2
Name WAN1GW WAN2GW
Interface WAN1 WAN2
Address Family IPv4 IPv4
IP Address 192.168.HS.254 172.30.34.254
Upstream Gateway aktiv aktiv
Far Gateway aus aus
Disable Gateway Monitoring aus aus
Monitor IP 9.9.9.9 208.67.222.222
Priority 255 254

Drei Punkte, die häufig falsch gemacht werden:

  • Upstream Gateway muss bei beiden Gateways gesetzt sein. Es kennzeichnet ein Gateway als
 Internet-Ausgang; ist es nur bei einem gesetzt, verhält sich das Failover unvorhersehbar.
  • Die Monitor-IPs müssen bei verschiedenen Betreibern liegen und dürfen nicht mit den
 DNS-Servern identisch sein. 8.8.8.8 und 8.8.4.4 gehören beide Google: fällt Google aus, werden
 beide Leitungen als tot gemeldet. Für jede Monitor-IP legt OPNsense zusätzlich eine Hostroute über
 das jeweilige Gateway an; benutzt man dieselbe IP auch als DNS-Server, überlagern sich Hostroute
 und DNS-Zuordnung.
  • Die niedrigere Priority gewinnt bei der Wahl des Default-Gateways. Das Default-Gateway
 bestimmt den Ausgang für den Eigenverkehr der Firewall (Updates, NTP, rekursiver Resolver) – es ist
 unabhängig von der Gatewaygruppe. Damit die primäre Leitung WAN2 auch das Default-Gateway stellt,
 bekommt WAN2GW die niedrigere Priority (254) und WAN1GW die höhere (255). Stünden beide gleich,
 wäre die Wahl zufällig.

Einstellen der Gatewaygruppe

System: Gateways: Group

Feld Wert
Group Name GW_GROUP
Gateway Priority WAN2GW = Tier 1, WAN1GW = Tier 2
Trigger Level Member Down
Pool Options Default
Ziel Tier-Vergabe Trigger Level
Failover (Standard hier) WAN2GW = Tier 1, WAN1GW = Tier 2 Member Down
Lastverteilung beide Tier 1 Packet Loss or High Latency

Bei Lastverteilung zusätzlich Firewall: Settings: AdvancedSticky connections aktivieren, sonst wechseln einzelne Verbindungen desselben Clients die Leitung.

Merke: Tier steuert das Failover des Client-Verkehrs (über die Firewallregel mit GW_GROUP). Die Priority steuert das Default-Gateway (Eigenverkehr der Firewall). Beide müssen zusammenpassen – sonst laufen Nutzverkehr und DNS über verschiedene Leitungen, und das Verhalten wirkt widersprüchlich.

DNS pro Leitung

System: Settings: General

DNS Server Use gateway
8.8.8.8 WAN1GW
1.1.1.1 WAN2GW
  • Prefer IPv4 over IPv6: aktiv
  • Die Zuordnung sorgt dafür, dass jeder DNS-Server über „seine“ Leitung befragt wird. Fällt eine
 Leitung aus, bleibt der andere Resolver erreichbar.
  • Voraussetzung: Die „Use gateway“-Zuordnung greift nur, wenn Unbound im Forwarding-Modus
 läuft (Services: Unbound DNS: GeneralEnable Forwarding Mode). Im Standard-Resolving-Modus
 löst Unbound rekursiv selbst auf und geht dabei über das Default-Gateway – dann ist die Zuordnung
 wirkungslos.

NAT auf beiden WAN-Interfaces

Firewall: NAT: Outbound – manuelle Regeln (Protokoll und Ports jeweils *, IPv4)

# Interface Source Destination Translate / target Beschreibung
1 WAN1 LAN network * Interface address LAN ins Internet
2 WAN1 SERVER network * Interface address SERVER ins Internet
3 WAN1 DMZ network ! 10.88.0.0/16 Interface address DMZ ins Internet – kein NAT zu den anderen DMZs
4 WAN2 LAN network * Interface address LAN ins Internet
5 WAN2 SERVER network * Interface address SERVER ins Internet
6 WAN2 DMZ network ! 10.88.0.0/16 Interface address DMZ ins Internet – kein NAT zu den anderen DMZs

Das Ausrufezeichen vor dem Zielnetz invertiert die Bedingung: Die Regel greift für alle Ziele außer 10.88.0.0/16. Verkehr aus der DMZ zu den übrigen internen Netzen wird also nicht übersetzt und behält seine Quelladresse – nur so bleiben Logs und Firewallregeln auf den Zielsystemen auswertbar.

Jede Regel existiert doppelt, einmal je WAN-Interface. Das ist bei Multiwan zwingend: Welche Leitung genutzt wird, entscheidet das Policy Routing der Firewallregel; die passende NAT-Regel muss auf beiden Wegen bereitstehen.

Firewallregeln mit Gateway-Gruppe

Firewall: Rules: LANdie Reihenfolge ist entscheidend:

# Action Source Destination Gateway Zweck
1 Pass LAN net This Firewall leer (default) DNS, NTP, Web-GUI
2 Pass LAN net Alias LOKALE_NETZE leer (default) interne Netze, DMZ, VPN
3 Pass LAN net any GW_GROUP Internetverkehr über die Gruppe

Regel 3 im Detail:

Feld Wert
Action Pass
Quick aktiv
Interface LAN
Direction in
TCP/IP Version IPv4
Protocol any
Source LAN net
Destination any
Description LAN to any über Gateway-Gruppe
Gateway GW_GROUP

Der klassische Fehler: Nur eine einzige Regel mit Gateway GW_GROUP. Eine Gateway-Angabe erzwingt Policy Routing für alles, was auf die Regel passt – auch für Pakete an die DMZ, an VPN-Gegenstellen und an die Firewall selbst. Diese Pakete werden dann in Richtung Internet geschickt und verschwinden. Deshalb müssen die Regeln 1 und 2 ohne Gateway-Angabe darüber stehen.

Der Alias LOKALE_NETZE (Firewall: Aliases, Typ Network) enthält alle eigenen Netze, z. B. die LAN-, DMZ- und VPN-Bereiche.

Firewall: Settings: Advanced

Option Empfehlung Wirkung
Skip rules when gateway is down aktiv Bei totem Gateway wird die Regel entfernt statt auf das Default-Gateway zurückzufallen – verhindert stillen Rückfall auf die falsche Leitung
Allow default gateway switching aktiv Fällt das Default-Gateway (WAN2GW) aus, zieht OPNsense das Default automatisch auf WAN1GW – so folgt auch der Eigenverkehr der Firewall (inkl. rekursivem DNS) der aktiven Leitung
Sticky connections nur bei Lastverteilung hält alle Verbindungen eines Clients auf derselben Leitung

Szenarien testen

Welche Public-IP je Leitung anliegt, prüft man direkt an den WAN-Geräten:

curl -sS -4 --interface em1 ifconfig.co
62.159.72.206
curl -sS -4 --interface em4 ifconfig.co
194.59.156.244

Zieladresse für den Traceroute-Test bewusst wählen: weder eine Monitor-IP (9.9.9.9, 208.67.222.222) noch einen der konfigurierten DNS-Server (8.8.8.8, 1.1.1.1) nehmen. OPNsense legt für diese Adressen Hostrouten über eine feste Leitung an – dann misst man nicht die Gatewaygruppe, sondern die Hostroute.

Szenario Vorgehen Erwartetes Ergebnis
Normalbetrieb traceroute -n heise.de von der Firewall erster externer Hop 172.30.34.254 (WAN2GW, Tier 1)
Ausfall WAN2 Kabel in VirtualBox trennen Dashboard zeigt WAN2GW offline, Verkehr läuft über 192.168.HS.254 (WAN1GW)
Rückkehr WAN2 Kabel wieder verbinden WAN2GW wieder online, neue Verbindungen laufen über WAN2
DNS-Test dig @8.8.8.8 und dig @1.1.1.1 beide antworten, jeder über seine Leitung
Zugriff intern Ping in DMZ bei totem WAN2 funktioniert weiter (Regel 2 ohne Gateway)

Wer routet gerade wohin? Drei Instanzen entscheiden unabhängig und lassen sich getrennt ablesen:

  • das Default-Gateway (Eigenverkehr der Firewall) unter Interfaces: Diagnostics: Routes
  • die States (welche Verbindung über welches Interface läuft) unter Firewall: Diagnostics: States
  • das Policy Routing der Gruppe – Statuswechsel mit Zeitstempel im System: Gateways: Log File

Nach einem Failover ist für ~10–20 s ein Mischbild normal: bestehende States bleiben auf der alten Leitung, bis sie ablaufen; nur neue Verbindungen nehmen sofort den neuen Weg.

Weitere Statusanzeige: Lobby: Dashboard (Widget Gateways).

Umsetzung