From 7b336d49f903706e763cd995c7b1b69d088f1563 Mon Sep 17 00:00:00 2001 From: nexxo Date: Mon, 3 Aug 2026 07:15:10 +0200 Subject: [PATCH] Runbook: Wenn der Tunnel weg ist MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Der Rettungsweg war bisher muendliche Ueberlieferung, verteilt ueber einen Chatverlauf. Jetzt aufgeschrieben, mit der einen Regel darueber: kein Weg zurueck darf durch den Tunnel fuehren, der gerade kaputt ist. Vier Wege hinein (SSH auf den Server, Anbieterkonsole, das Notfallskript auf dem Host, eine offline abgelegte WireGuard-Konfiguration), ein Entscheidungsbaum zum Eingrenzen, und je Fall die Befehle. Dazu vier Dinge, die man EINMAL einrichtet, solange nichts brennt — darunter der sudoers-Eintrag, ohne den der conntrack- Griff aus v1.4.6 nur als Warnung im Protokoll landet statt zu laufen. Und ein Abschnitt darueber, was seit v1.4.4/v1.4.6 nicht mehr passieren sollte: wer es trotzdem sieht, hat einen Server auf altem Stand. Co-Authored-By: Claude Opus 5 --- docs/runbooks/tunnel-recovery.md | 226 +++++++++++++++++++++++++++++++ 1 file changed, 226 insertions(+) create mode 100644 docs/runbooks/tunnel-recovery.md diff --git a/docs/runbooks/tunnel-recovery.md b/docs/runbooks/tunnel-recovery.md new file mode 100644 index 0000000..449af42 --- /dev/null +++ b/docs/runbooks/tunnel-recovery.md @@ -0,0 +1,226 @@ +# Runbook: Wenn der Tunnel weg ist + +Der WireGuard-Tunnel trägt alles: die Konsole, jeden Host, jede +Provisionierung, das Terminal. Fällt er aus, sieht es aus, als sei das ganze +Produkt kaputt — obwohl meistens nur eine Sitzung nicht wieder aufgebaut wurde. + +Dieses Runbook beantwortet zwei Fragen. Erstens: **womit komme ich noch hinein, +wenn der Tunnel nicht steht?** Zweitens: **wie bringe ich ihn zurück?** + +--- + +## Die eine Regel + +**Kein Weg zurück darf durch den Tunnel führen, der gerade kaputt ist.** + +Alles unten ist danach sortiert. Wer als Rettungsweg etwas einplant, das selbst +WireGuard braucht, hat keinen Rettungsweg eingeplant. + +--- + +## Die vier Wege hinein, in dieser Reihenfolge + +### 1. SSH auf den CluPilot-Server + +Der Hebel für fast alles. Er hängt an nichts, was hier beschrieben wird — der +Server ist über seine öffentliche Adresse erreichbar, unabhängig vom Tunnel. + +```bash +ssh @ +cd /opt/clupilot +``` + +Von hier aus laufen alle Befehle weiter unten. + +### 2. Die Konsole des Anbieters (Hetzner: KVM oder Rettungssystem) + +Für einen **Host**, nicht für den CluPilot-Server. Immer verfügbar, hängt an +keinem Dienst von uns. Der Weg, wenn ein Host weder über den Tunnel noch über +SSH antwortet. + +### 3. Das Notfallskript auf dem Host + +Liegt auf jedem übernommenen Host: + +``` +/usr/local/sbin/clupilot-emergency-open-firewall.sh +``` + +`SecureHostFirewall` lässt Port 22 nur aus dem WireGuard-Netz zu. Steht der +Tunnel nicht, ist SSH aus dem Internet **zu** — das ist Absicht und genau der +Grund, warum es dieses Skript gibt. Aufgerufen wird es über die Konsole des +Anbieters (Weg 2), nicht per SSH; per SSH käme man ja gerade nicht hin. + +Danach ist der Host wieder aus dem Internet erreichbar. **Nach der Reparatur den +Schritt `SecureHostFirewall` erneut laufen lassen**, sonst bleibt die Maschine +offen. + +### 4. Eine WireGuard-Konfiguration, die offline liegt + +In der Zugangsliste der Konsole gibt es zu jedem Mitarbeiter-Zugang einen +Download. **Eine davon gehört außerhalb der Konsole aufbewahrt** — Passwort-Safe, +zweites Gerät, ausgedruckt. Sonst braucht man die Konsole, um an den Zugang zu +kommen, der einen zur Konsole bringt. + +--- + +## Erst feststellen, wo es klemmt + +Vom CluPilot-Server aus, in dieser Reihenfolge. Jede Zeile schließt eine +Möglichkeit aus. + +```bash +cd /opt/clupilot + +# 1. Steht wg0 überhaupt, und wie viele Zugänge kennt es? +sudo -u clupilot docker compose exec -T queue-provisioning wg show + +# 2. Läuft der Container, in dessen Namensraum wg0 lebt? +sudo -u clupilot docker compose ps queue-provisioning + +# 3. Was sagt er beim Starten? +sudo -u clupilot docker compose logs --tail=40 queue-provisioning +``` + +**Kein Interface, kein `wg0`** → weiter bei „Der Tunnel kommt nicht hoch". + +**Interface da, Zugänge da, aber `Letzter Kontakt: nie` oder uralt, und die +Zahlen stehen bei ↑ etwas / ↓ 0 B** → weiter bei „Der Tunnel steht, aber +niemand kommt an". + +**Ein einzelner Zugang fehlt, die anderen stehen** → das Problem liegt auf +dessen Gegenseite, nicht hier. Bei einem Host: Weg 2 und `systemctl status +wg-quick@wg0` auf der Maschine. + +--- + +## Der Tunnel steht, aber niemand kommt an + +Das häufigste Bild, und das mit der unauffälligsten Ursache. + +Der Kernel merkt sich laufende UDP-Ströme samt Ziel. Wird der Tunnel-Container +**neu gebaut** (nicht neu gestartet — neu gebaut), bekommt er eine neue Adresse +im Compose-Netz, und die Weiterleitung für den WireGuard-Port wird neu +geschrieben. Die gemerkten Einträge zeigen aber weiter auf den alten Container. + +Und sie verfallen nicht: WireGuard schickt alle 25 Sekunden ein Lebenszeichen +und hält den kaputten Eintrag damit am Leben. Der Zustand heilt also **nie** von +allein. + +Daran erkennt man ihn: + +* Ein Telefon kommt nach Aus- und Einschalten sofort zurück — ein neuer + Quellport bekommt einen frischen Eintrag. +* Ein **Host** kommt gar nicht zurück — er schickt stur vom selben Port. +* Auf der Zugangsseite: ↑ wächst weiter, ↓ bleibt bei 0 B. + +Der Griff, auf dem **Wirt**, nicht im Container: + +```bash +sudo conntrack -D -p udp --dport 51820 +``` + +Fehlt das Werkzeug: `sudo apt-get install -y conntrack`. Danach dreißig Sekunden +warten — jeder Zugang meldet sich von selbst wieder, alle 25 Sekunden läuft sein +Keepalive. + +> **Seit v1.4.6 macht das Update das selbst.** Es merkt sich die Container-ID +> vor und nach `docker compose up -d`; hat sie sich geändert, räumt es die +> Ströme weg. Kann es das nicht (es läuft als Dienstbenutzer, der Griff braucht +> Root), steht der Befehl als Warnung im Protokoll. Siehe „Einmal einrichten" +> unten. + +--- + +## Der Tunnel kommt nicht hoch + +`wg show` zeigt gar kein Interface. + +```bash +cd /opt/clupilot + +# Von Hand hochziehen — sagt auch gleich, woran es scheitert. +sudo -u clupilot docker compose exec -T queue-provisioning wg-quick up wg0 + +# Steht die Konfiguration überhaupt noch im Datenträger? +sudo -u clupilot docker compose exec -T queue-provisioning ls -l /etc/wireguard/ +``` + +Die Zugänge stehen **in `wg0.conf`** und überleben einen Neustart. Fehlt die +Datei, ist der `wireguard`-Datenträger das Problem, nicht WireGuard. + +Läuft der Container gar nicht: + +```bash +sudo -u clupilot docker compose up -d queue-provisioning +sudo -u clupilot docker compose logs --tail=40 queue-provisioning +``` + +Prozess 1 ist `docker/provisioning-worker.sh`. Das Skript zieht wg0 hoch und +hält danach den Warteschlangen-Arbeiter in einer Schleife. Steht dort etwas +anderes, läuft der Container auf einem alten Stand — dann fehlt das Update. + +--- + +## Ein Host kommt nicht zurück, alle anderen schon + +Dann liegt es auf der Maschine. Über die Konsole des Anbieters (Weg 2): + +```bash +systemctl status wg-quick@wg0 +wg show +systemctl restart wg-quick@wg0 +``` + +`ConfigureWireguard` schreibt dem Host `Endpoint = ` und +`PersistentKeepalive = 25` — er meldet sich also von sich aus, alle 25 Sekunden. +Tut er das nicht, läuft wg0 dort nicht. + +Kommt man über die Konsole nicht weit genug, weil SSH zu ist: erst Weg 3, dann +weiter. + +--- + +## Einmal einrichten, damit der Plan später trägt + +Vier Dinge, die man vorher macht und nicht, wenn es brennt. + +1. **Eine WireGuard-Konfiguration offline ablegen.** Siehe Weg 4. +2. **Zugang zur Anbieterkonsole prüfen** — einmal einloggen, bevor man es + braucht. Ein vergessenes Passwort ist im Ernstfall ein zweiter Ausfall. +3. **Dem Dienstbenutzer den conntrack-Griff erlauben**, damit das Update ihn + selbst ausführen kann. In `/etc/sudoers.d/clupilot-conntrack`: + + ``` + clupilot ALL=(root) NOPASSWD: /usr/sbin/conntrack -D -p udp --dport 51820 + ``` + + Genau dieser eine Aufruf, nicht `conntrack` allgemein. +4. **`conntrack` installieren**, falls nicht vorhanden: + `sudo apt-get install -y conntrack`. + +--- + +## Was inzwischen NICHT mehr passieren sollte + +Drei Ursachen sind abgestellt. Wer sie trotzdem sieht, hat einen Server auf +altem Stand. + +* **Bis v1.4.3** hing wg0 am Leben des Warteschlangen-Arbeiters: Prozess 1 des + Containers war `php artisan queue:work`. Ein Zeitüberlauf, ein fataler Fehler + oder ein Speicherlimit beendete den Arbeiter, damit den Container, damit den + Tunnel. Das las sich von außen als „das VPN ist unzuverlässig". Seit v1.4.4 + läuft der Arbeiter in einer Schleife neben dem Tunnel. +* **v1.4.2** gab dem Tunnel-Container einen Netz-Alias. Ein Alias ist Teil der + Netzkonfiguration, und Compose baut einen Container neu, sobald die sich + ändert — mit allem, was oben unter „gemerkte Ströme" steht. Seit v1.4.4 ist + der Alias weg; nginx spricht die Terminal-Brücke unter dem Dienstnamen des + Nachbarn an. +* **Bis v1.4.5** startete jedes Update `queue-provisioning` neu und riss damit + jede Sitzung ab, auch wenn sich nur PHP-Code geändert hatte. Seit v1.4.6 + bekommt der Arbeiter ein Signal und wird von seiner Schleife neu gestartet, + während der Container steht. + +Erzwungen durch `tests/Feature/DeploymentRunsAsTheAppUserTest.php` — der Container +darf nicht in der Neustart-Liste stehen, und der conntrack-Griff muss im Skript +bleiben.