Firewall Updates leicht gemacht

  • Hallo zusammen,

    ich bin ein Rückkehrer nach längerer Zeit bei einem anderen Anbieter. Dort war ich es gewohnt, alles zu automatisieren, was ich für den täglichen Betrieb brauche – besonders die Firewall-Regeln. Ihr kennt das bestimmt: man sitzt hinter einem ISP mit dynamischer IP, und alle paar Tage muss man wieder die Adresse aktualisieren, um überhaupt auf den Server zu kommen. Nervig. Und SSH dauerhaft offen lassen will ja auch keiner.

    Zum Glück bietet Netcup mit der SCP-API genau das, was man dafür braucht. Also hab ich mir ein kleines Tool gebaut: netcup-autofirewall.

    Was es macht:

    Bei jedem Lauf ermittelt es deine aktuelle öffentliche IPv4/IPv6, schreibt sie in eine Firewall-Policy namens ssh-autofirewall und hängt die an das Interface deines Servers – zusätzlich zu allem, was da schon dran hängt, nichts wird überschrieben. Die Policy selbst besteht aus drei Regeln: ACCEPT für deine aktuelle IPv4, ACCEPT für deine IPv6, DROP für den Rest. Läuft die IP-Adresse dir weg, wird beim nächsten Aufruf einfach dieselbe Policy aktualisiert statt eine neue anzulegen – da sammelt sich also nichts an.

    Ein Punkt, der mir persönlich wichtig war: die IP-Erkennung läuft komplett selbst gehostet. Es gibt einen kleinen echo-server, den man auf einer eigenen Maschine laufen lässt (bei mir läuft er hinter Cloudflare), und der beantwortet nur die Frage "was ist meine IP". Kein Drittanbieter-Dienst sieht deine Adresse.

    Außerdem dabei:

    • Optional --cf, um zusätzlich HTTPS von Cloudflares Edge-Ranges freizugeben (praktisch, wenn der Server hinter Cloudflare-Proxy läuft)
    • Optional --wg für WireGuard auf UDP 51820
    • Ein eingebauter Scheduler (run), der sich selbst per Cron-Ausdruck immer wieder neu anwendet – man braucht also nicht mal Host-Cron dafür
    • Beide Binaries (CLI + echo-server) gibt's als schlanke Container-Images

    Login läuft über den OAuth2 Device Flow, danach genügt für den Alltag nur noch netcup-autofirewall apply --yes bzw. der Daemon-Modus.

    Ist noch recht frisch, daher: Feedback, Issues und PRs sind willkommen. Falls jemand ähnliche Bedürfnisse hatte und selbst was gebaut hat, würde mich auch interessieren, wie ihr das gelöst habt.

    Ein Wort der Warnung, falls jemand es ausprobiert: Serial/VNC-Konsole griffbereit halten, bis ihr sicher seid, dass es funktioniert. Lockout ist bei sowas immer ein Thema.

    Viele Grüße
    hra42

  • Immer schön, solche Lösungen zu sehen. Ich habe mich mit dem Thema auch schon beschäftigt, daher ein paar Anregungen:

    • Einen eigenen "Echo-Server" betreibe ich nicht. Es bestehen ohnehin DynDNS-Einträge (die u. a. für VPN-Verbindungen benötigt werden), die für diesen Zweck mitbenutzt werden können. Statt des "Echo-Servers" sollte man daher auch einen DynDNS-Namen verwenden können.
    • Für IPv6 öffne ich die Firewall für das jeweils gültige Präfix::/64, damit von unterschiedlichen Hosts aus zugegriffen werden kann. Das entspricht dann dem Verhalten wie bei IPv4, bei dem ja die IP-Adresse des Routers verwendet wird und alle Geräte dahinter öffentlich mit der gleichen IPv4-Adresse auftreten. Will man das Ganze eher restriktiv behandeln, dann ist ein einzelner IPv6-Host vermutlich zu bevorzugen, aber für IPv4 wird ja dennoch das gesamte "Heimnetz" freigegeben.
    • Für Anwender mit DS-Lite könnte vielleicht ein "IPv6 only"-Modus relevant sein.
    • Als Alternative zu WireGuard könnte auch OpenVPN zum Einsatz kommen. Letztlich müsste die Portnummer konfigurierbar sein um verschiedene VPN-Protokolle unterstützen zu können oder eben eine zusätzliche Option implementiert werden für OpenVPN.
    • Wenn ich das beim Überfliegen deiner Lösung richtig gesehen habe, öffnest Du die netcup-Firewall für WireGuard nur eingehend. Da die netcup-Firewall bei UDP nicht stateful ist, wird in einem Szenario, bei dem keine implizite OUTGOING UDP ACCEPT ALL-Regel vorhanden ist, auch eine explizite ACCEPT-Regel für die entsprechende Portnummer UDP OUTGOING benötigt.
  • Zierleiste
    Danke für das ausführliche Feedback, genau sowas hilft mir. Hab alle fünf Punkte umgesetzt: https://github.com/hra42/netcup-autofirewall/pull/1

    Kurz zu den Details:

    DynDNS statt Echo-Server: --dns-hostname home.example.org reicht jetzt, dann wird der Name aufgelöst statt der eigene Echo-Server gefragt. Nicht-routbare Antworten (also z.B. wenn der Router seine LAN-Adresse meldet) werden verworfen – so was darf nie in einer Firewall-Regel landen. Falls euer Resolver länger cached als euer Apply-Intervall, gibt's --dns-server, um direkt eine Nameserver-Adresse anzufragen.

    IPv6-Präfix: Standardmäßig bleibt's bei /128, aber mit --ipv6-prefix 64 wird auf's Präfix erweitert und die Host-Bits genullt – genau wie du's beschrieben hast, analog zu IPv4, wo ja eh das ganze Heimnetz hinter einer Adresse steckt. Ich hab den Default bewusst bei /128 gelassen, damit ein Update nicht stillschweigend die Freigabe aufweitet.

    DS-Lite: --ip-mode mit dual (Standard), v6only, v4only, auto. Vorher war IPv4 hart verdrahtet, jetzt läuft's auch ohne.

    OpenVPN: eigene Policy, eigener Port, TCP oder UDP wählbar, läuft neben WireGuard. Ist mir aufgefallen, dass der WireGuard-Port bisher auch gar nicht konfigurierbar war – hab ich gleich mit nachgezogen.

    Egress-Regeln fürs VPN: Das war tatsächlich der kniffligste Teil. Die netcup-Firewall ist bei UDP nicht stateful, du hattest also komplett recht. Aber es gab dabei eine Falle, auf die ich erst beim Testen gegen die echte API gestoßen bin: sobald man irgendeine Egress-Regel anhängt, kippt die implizite Egress-Regel des Interfaces von ACCEPT_ALL auf DROP_ALL. Eine UDP-Egress-Regel bedingungslos zu setzen hätte also nebenbei den kompletten ausgehenden TCP-Verkehr blockiert – und das Tückische daran: man merkt's nicht sofort, weil das VPN selbst ja weiterläuft.

    Nochmal danke, ohne den Hinweis zu IPv6 und Egress hätte ich das vermutlich erst live gemerkt.

    Einmal editiert, zuletzt von hra42 (18. Juli 2026 um 14:16)

  • Hab alle fünf Punkte umgesetzt:

    Hey super - die Lösung mit der Option --ipv6-prefix ist elegant.

    Hast Du das netcup-autofirewall-Tool eigentlich auf der netcup-VM selbst laufen (also verfügt diese VM über die SCP-Zugangsdaten) oder steuerst Du die netcup-Firewall von einer externen Instanz aus an?

  • und

    Klingt irgendwie nach Bock als Gärtner

    Niemand ist gezwungen das auch hinter Cloudflare zu setzen. Ich habe ein Enterprise Agreement mit Cloudflare und bin happy damit. Das ist das schöne wenn du die Quelle hast, hoste es selbst oder passe den Code an, tu was du willst damit :)

  • Hey super - die Lösung mit der Option --ipv6-prefix ist elegant.

    Hast Du das netcup-autofirewall-Tool eigentlich auf der netcup-VM selbst laufen (also verfügt diese VM über die SCP-Zugangsdaten) oder steuerst Du die netcup-Firewall von einer externen Instanz aus an?

    bei mir läuft das aus meinem HomeLab auf einem Rock 5T von Radxa. Du kannst das aber auf jedem beliebigen Computer hosten.

  • Niemand ist gezwungen das auch hinter Cloudflare zu setzen.

    Das habe ich auch nicht bezweifelt.

    Ich schmunzle nur über den Widerspruch deiner Aussage.

    Abgesehn davon: Ich würde einem deutschen (oder eu) Dienst wie wieistmeineip.de 10 mal mehr vertrauen, als einem amerikanischen Datensammler...

  • Danke für das Tool und teilen des Quell-Codes! Ich selbst benötige es aktuell zwar nicht, weil ich u. a. SSH nur via IPv6 verwende und sich mein IPv6-Präfix i. d. R. nicht ändert. Aber es ist immer interessant zu sehen, wie sowas umgesetzt wurde und kann ja evtl. auch mal als Inspiration für eigene Implementierungen dienen. :)

    Hier ist übrigens etwas Ähnliches zu finden: Firewallregeln mit dynamischer Home-IP über API updaten

    Eine kleine Anmerkung zur Doku:

    Zitat

    By default IPv4 is required and IPv6 is a bonus. That fails outright on a DS-Lite connection, which has no public IPv4 at all.

    Bei einem DS-Lite-Anschluss hat man auch eine öffentliche IPv4-Adresse (sonst wäre es ja kein Dual-Stack). Man teilt sich diese Adresse aber mit anderen Kunden des ISP (via CGNAT). Daher würde ich es eher als Empfehlung formulieren, in diesem Fall nur IPv6 zu verwenden und beschreiben, warum es ggf. sinnvoll ist.

  • Danke für das Tool und teilen des Quell-Codes! Ich selbst benötige es aktuell zwar nicht, weil ich u. a. SSH nur via IPv6 verwende und sich mein IPv6-Präfix i. d. R. nicht ändert. Aber es ist immer interessant zu sehen, wie sowas umgesetzt wurde und kann ja evtl. auch mal als Inspiration für eigene Implementierungen dienen. :)

    Hier ist übrigens etwas Ähnliches zu finden: Firewallregeln mit dynamischer Home-IP über API updaten

    Eine kleine Anmerkung zur Doku:

    Bei einem DS-Lite-Anschluss hat man auch eine öffentliche IPv4-Adresse (sonst wäre es ja kein Dual-Stack). Man teilt sich diese Adresse aber mit anderen Kunden des ISP (via CGNAT). Daher würde ich es eher als Empfehlung formulieren, in diesem Fall nur IPv6 zu verwenden und beschreiben, warum es ggf. sinnvoll ist.

    Danke für die Anmerkung zur Doku. Ich habe das eben angepasst :)