VPNSmith
self-host-vpnINFO

Linux VPN Kill Switch mit iptables und systemd (2026)

Netfilter-Kill-Switch, der allen WireGuard-Verkehr außerhalb des Tunnels blockiert. Geordneter systemd-Dienst, VPN-Schnittstellenausnahme, Wiederverbindungstest. Null-Leckage garantiert.

Von Eric Gerard · Fondateur · VPNSmith — Spécialiste self-host VPN & VPS GDPR9 Min. LesezeitPhoto via Unsplash

Sie nutzen ein selbst gehostetes VPN. Sie fragen sich, was passiert, wenn der Tunnel während eines sensiblen Uploads für 12 Sekunden abbricht. In den meisten Standard-Linux-Konfigurationen: fließt der Verkehr unverschlüsselt über Ihre Standardroute, ohne sichtbare Anzeichen. Lokale DNS-Lecks, die echte IP erscheint in den Protokollen des entfernten Servers. Ein App-basierter Kill-Switch wird Sie nicht retten — dies muss auf Kernel-Ebene blockiert werden.

Diese Anleitung richtet einen iptables + systemd Kill-Switch ein, der garantiert, dass nichts unverschlüsselt Ihre Maschine verlässt, selbst während der 50 ms Lücke zwischen zwei WireGuard-Handshakes.

Warum ein Netfilter-Kill-Switch die einzige ernsthafte Garantie ist

Die kommerzielle VPN-Branche spricht seit sieben Jahren über "Kill-Switches", aber die meisten Implementierungen sind fragil, da sie auf Anwendungsebene arbeiten: Die NordVPN- oder ExpressVPN-App erkennt einen Tunnelabbruch und unterbricht den Verkehr, indem sie die Routing-Tabelle manipuliert. Das Problem: Während der 200 bis 800 Millisekunden, die die Anwendung benötigt, um den Abbruch zu erkennen und zu reagieren, verlassen Pakete unverschlüsselt über die Standard-Schnittstelle. Das reicht aus, damit eine aktive BitTorrent-Verbindung Ihre echte IP an den Tracker preisgibt oder ein laufender Multipart-S3-Upload Ihren geografischen Ursprung offenbart.

Der Netfilter-Kill-Switch (iptables oder nftables) umgeht dieses Problem, indem er die Filterregel direkt im Linux-Kernel platziert, nicht in einem Benutzermodus-Prozess. Pakete durchlaufen das Netfilter-Subsystem bei jedem send/sendmsg/sendto-Systemaufruf — es gibt kein Anwendungs-Latenzfenster. Wenn WireGuard abstürzt, werden Pakete weiterhin von Netfilter gedroppt, bis der Tunnel zurückkommt, unabhängig vom Zustand des WireGuard-Prozesses. Deshalb empfiehlt Mullvad Netfilter als zweite Schicht zusätzlich zu ihrer App, und warum Tor-Projektanleitungen den Netfilter-Kill-Switch ausdrücklich für Hosts erwähnen, die Relays betreiben.

Unsere Wahl für iptables statt nftables liegt an der Unterstützung: Ubuntu Server 22.04 LTS und Debian 12 haben iptables immer noch als De-facto-Tool, obwohl das Backend unter der Haube nftables ist. iptables-Befehle sind aus jedem Dokument der letzten 10 Jahre kopierbar, was das Risiko von Tippfehlern reduziert und die Wartung erleichtert. Wenn Sie 2026 auf einem neuen Host neu anfangen und nftables kennen, gehen Sie direkt mit nftables — die Syntax ist sauberer und die Reihenfolge der Ketten ist explizit.

Das Modell, das wir bauen

Die Kernidee in 3 Sätzen:

  1. Alle OUTPUT-Verkehr wird standardmäßig gedroppt, es sei denn, er verlässt die Maschine über die VPN-Schnittstelle (wg0).
  2. Ausnahme: Die UDP-Verbindung zum VPN-Server (Handshake) bleibt erlaubt — ohne sie kann der Tunnel nach einem Abbruch nicht wiederhergestellt werden.
  3. systemd stellt sicher, dass diese iptables-Regeln vor WireGuard angewendet werden und Tunnelneustarts überleben.

Ergebnis: Wenn WireGuard abstürzt, kann Ihre Maschine buchstäblich nichts senden außer dem VPN-Handshake. Sie sehen "keine Verbindung" im Browser, aber es gibt keine Paketlecks.

Vorbereitung

Auf Ubuntu/Debian (getestet auf Ubuntu 22.04 und 24.04, Kernel 5.15+):

sudo apt update
sudo apt install -y iptables iptables-persistent
# Bei der netfilter-persistent-Abfrage: JA für IPv4 und IPv6

Beachten Sie diese Punkte, bevor Sie fortfahren:

  • Die öffentliche VPN-IP: nslookup vpn.example.com oder überprüfen Sie die Endpoint-Zeile in wg0.conf.
  • Der VPN-UDP-Port: normalerweise 51820 für WireGuard.
  • Die VPN-Schnittstelle: standardmäßig wg0, kann bei mehreren Tunneln wg1 sein.
  • Das lokale LAN-Subnetz, das erreichbar bleiben soll (192.168.1.0/24, 10.0.0.0/8, etc.) — damit Drucker und NAS nicht ausfallen.

IPv4 iptables-Regeln

Erstellen Sie /etc/iptables/rules.v4 mit diesem Inhalt (angepasste Werte in Klammern):

*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]

# Loopback immer erlaubt
-A INPUT  -i lo -j ACCEPT
-A OUTPUT -o lo -j ACCEPT

# Bereits hergestellte Verbindungen (VPN-Handshake-Antworten, etc.)
-A INPUT  -m state --state ESTABLISHED,RELATED -j ACCEPT
-A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# Eingehendes SSH (wenn Sie remote verwalten — andernfalls diese 2 Zeilen löschen)
-A INPUT  -p tcp --dport 22 -m state --state NEW -j ACCEPT

# Ausgehender VPN-Handshake: nur Verkehr außerhalb des Tunnels erlaubt
-A OUTPUT -p udp -d 1.2.3.4 --dport 51820 -j ACCEPT

# Lokales LAN-DNS (Pi-hole, Router) — optional
-A OUTPUT -d 192.168.1.0/24 -j ACCEPT

# Alles andere OUTPUT geht über die VPN-Schnittstelle
-A OUTPUT -o wg0 -j ACCEPT

# Eingehendes auf wg0 erlauben
-A INPUT  -i wg0 -j ACCEPT

COMMIT

Ersetzen Sie:

  • 1.2.3.4 durch die tatsächliche öffentliche IP Ihres VPN-Servers
  • 51820 durch Ihren WireGuard-Port
  • 192.168.1.0/24 durch Ihr LAN-Subnetz
  • Entfernen Sie die --dport 22-Zeile, wenn Sie keinen eingehenden SSH-Admin benötigen

Laden Sie die Regeln:

sudo iptables-restore < /etc/iptables/rules.v4
sudo iptables -L -v -n
# Bestätigen Sie, dass die DROP-Kettenzähler bei 0 sind

ip6tables-Regeln (KRITISCH)

Ohne explizit blockiertes IPv6 aktivieren viele Distributionen es standardmäßig und der Verkehr leckt. Erstellen Sie /etc/iptables/rules.v6:

*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]

-A INPUT  -i lo -j ACCEPT
-A OUTPUT -o lo -j ACCEPT

-A INPUT  -m state --state ESTABLISHED,RELATED -j ACCEPT
-A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# Wenn Ihr VPN IPv6 unterstützt (selten bei selbst gehosteten):
# -A OUTPUT -p udp -d 2001:db8::1 --dport 51820 -j ACCEPT
# -A OUTPUT -o wg0 -j ACCEPT
# -A INPUT  -i wg0 -j ACCEPT

# Andernfalls wird alles IPv6 außerhalb des Loopbacks gedroppt

COMMIT

Laden:

sudo ip6tables-restore < /etc/iptables/rules.v6

An diesem Punkt können Sie testen: Ohne den WireGuard-Tunnel passiert kein Ping ins Internet. Erwartet.

systemd-Dienstreihenfolge für WireGuard nach iptables

Server-Racks in Blau beleuchtet in einem Rechenzentrum
Server-Racks in Blau beleuchtet in einem Rechenzentrum

Standardproblem: wg-quick@wg0 kann vor netfilter-persistent starten. Während dieses Fensters (~1-3 Sekunden) ist der Tunnel UP, aber die iptables-Regeln sind nicht geladen → mögliches Leck.

Lösung: systemd-Override, der die Reihenfolge erzwingt.

Erstellen Sie /etc/systemd/system/wg-quick@wg0.service.d/killswitch.conf:

sudo mkdir -p /etc/systemd/system/wg-quick@wg0.service.d
sudo nano /etc/systemd/system/wg-quick@wg0.service.d/killswitch.conf

Inhalt:

[Unit]
After=netfilter-persistent.service
Wants=netfilter-persistent.service
Requires=netfilter-persistent.service

[Service]
# Wenn wg-quick abstürzt, erzwinge OUTPUT DROP, um Lecks zu verhindern
ExecStopPost=/sbin/iptables -P OUTPUT DROP
ExecStopPost=/sbin/ip6tables -P OUTPUT DROP

Systemd neu laden:

sudo systemctl daemon-reload
sudo systemctl enable wg-quick@wg0
sudo systemctl enable netfilter-persistent
sudo systemctl restart netfilter-persistent
sudo systemctl restart wg-quick@wg0

Bei jedem Start startet systemd netfilter-persistent zuerst (iptables geladen), dann wg-quick@wg0 (Tunnel up). Kein Leckfenster.

Validierungstests

Test 1 — Tunnel fallen lassen, Stille überprüfen

# Tunnel up
sudo wg show
# Muss einen aktuellen Handshake anzeigen

# Internetzugang testen
curl -s -m 5 https://ifconfig.me
# Muss VPS-IP zurückgeben

# Tunnel fallen lassen
sudo wg-quick down wg0

# Erneut testen
curl -s -m 5 https://ifconfig.me
# Muss ohne Antwort ablaufen — KILL SWITCH AKTIV

Wenn Sie bei dem zweiten Befehl eine IP sehen → Leck, iptables-Regeln sind nicht angewendet. Überprüfen Sie sudo iptables -L -v -n und bestätigen Sie, dass OUTPUT standardmäßig DROP ist.

Test 2 — Einen WireGuard-Absturz simulieren

# Tunnel up
sudo wg-quick up wg0
ping -c 2 1.1.1.1
# Muss OK pingen

# Brutales Beenden des WireGuard-Prozesses (Absturz simulieren)
sudo pkill -9 wg
sudo ip link delete wg0 2>/dev/null

# Erneut testen
ping -c 2 1.1.1.1
# Muss fehlschlagen "Operation nicht erlaubt"

Der Kernel verweigert den Ping, da keine Route mehr erlaubt ist. Ohne ExecStopPost im systemd-Drop-in lassen einige Distributionen ein Leckfenster nach dem Absturz — diese Zeile ist wichtig.

Test 3 — DNS-Leck

# Tunnel UP
dig @9.9.9.9 ifconfig.me +short
# Muss VPS-IP zurückgeben

# Tunnel fallen lassen
sudo wg-quick down wg0

# Erneut testen
dig @9.9.9.9 ifconfig.me +short
# Muss ablaufen / "keine Server konnten erreicht werden"

Selbst DNS wird außerhalb des Tunnels blockiert. Ziel erreicht.

Sonderfälle

Sie betreiben mehrere Tunnel (wg0 + wg1)

Duplizieren Sie die OUTPUT-Ausnahme:

-A OUTPUT -p udp -d 1.2.3.4 --dport 51820 -j ACCEPT  # Haupttunnel
-A OUTPUT -p udp -d 5.6.7.8 --dport 51820 -j ACCEPT  # Sekundärtunnel
-A OUTPUT -o wg0 -j ACCEPT
-A OUTPUT -o wg1 -j ACCEPT

Tailscale parallel betreiben

Tailscale verwendet standardmäßig UDP 41641. Hinzufügen:

-A OUTPUT -p udp --dport 41641 -j ACCEPT
-A OUTPUT -o tailscale0 -j ACCEPT

Lokales LAN erreichbar halten (NAS, Drucker)

Die Vorlagenregel -A OUTPUT -d 192.168.1.0/24 -j ACCEPT tut dies bereits. Passen Sie das Subnetz an.

Sie möchten keinen eingehenden SSH (mobiler Arbeitsplatz)

Löschen Sie die Zeile --dport 22 -m state --state NEW -j ACCEPT. Bestehende (ESTABLISHED) Verbindung bleibt OK.

Protokollierung gedropter Pakete (Debug)

Um zu sehen, was ohne den Kill-Switch geleckt hätte:

sudo iptables -I OUTPUT 1 -j LOG --log-prefix "OUTPUT-DROP: " --log-level 4

Dann:

sudo journalctl -k -f | grep "OUTPUT-DROP"

Sie sehen jedes Paket, das Ihr Betriebssystem versucht, unverschlüsselt zu senden, wenn der Tunnel unten ist (Apple DNS, NTP, Spotify-Heartbeat, etc.). Lehrreich.

Sobald das Debugging abgeschlossen ist, entfernen Sie die LOG-Regel (sonst füllt sich journalctl):

sudo iptables -D OUTPUT -j LOG --log-prefix "OUTPUT-DROP: " --log-level 4

Bonus: Kill-Switch direkt in wg0.conf

Wenn Sie iptables nicht separat verwalten möchten, akzeptiert WireGuard PostUp/PreDown, die die gleiche Aufgabe erfüllen:

[Interface]
# ...
PostUp = iptables -I OUTPUT ! -o %i -m mark ! --mark $(wg show %i fwmark) -m addrtype ! --dst-type LOCAL -j REJECT
PostUp = ip6tables -I OUTPUT ! -o %i -m mark ! --mark $(wg show %i fwmark) -m addrtype ! --dst-type LOCAL -j REJECT
PreDown = iptables -D OUTPUT ! -o %i -m mark ! --mark $(wg show %i fwmark) -m addrtype ! --dst-type LOCAL -j REJECT
PreDown = ip6tables -D OUTPUT ! -o %i -m mark ! --mark $(wg show %i fwmark) -m addrtype ! --dst-type LOCAL -j REJECT

Pro: keine zusätzliche Datei. Contra: Regeln verschwinden, wenn WireGuard abstürzt, ohne PreDown aufzurufen (Kernel-Panik, OOM-Kill). Der oben beschriebene systemd-Ansatz ist robuster für den langfristigen Einsatz.

Siehe auch die Reise-Kill-Switch-Vorlage im WireGuard 2026-Leitfaden für die Inline-wg0.conf-Version.

Letzte Überprüfung

# Vollständiger Neustart
sudo reboot

# Nach dem Neustart keine manuellen Schritte
ip a show wg0
# Muss Tunnel UP anzeigen

iptables -L OUTPUT -v -n | head -5
# Standardrichtlinie muss DROP sein, Akzeptanzzähler müssen wachsen

curl -s ifconfig.me
# Muss VPS-IP zurückgeben

Alles grün: Ihr Kill-Switch ist eingerichtet, läuft beim Start, übersteht Abstürze. Sie können die Maschine in ein feindliches Netzwerk einstecken, ohne Leckrisiko.

Weiterführende Schritte

Der Kill-Switch blockiert Lecks. Aber für echten Seelenfrieden, fügen Sie hinzu:

Und die Grundlage: WireGuard-Setup auf Contabo in 20 Minuten.

★ Nürnberger DSGVO-Rechenzentrum · ✓ Dedizierte IPv4 inklusive · 200+ Mbps garantiert

Self-host your VPN on your own VPS → ContaboFull root access · public IPv4 · pick your region