261 lines
9.6 KiB
Markdown
261 lines
9.6 KiB
Markdown
# 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 <benutzer>@<clupilot-server>
|
|
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.
|
|
|
|
---
|
|
|
|
## Zuerst: ein Befehl, der das meiste allein macht
|
|
|
|
```bash
|
|
cd /opt/clupilot && sudo -u clupilot bash deploy/rescue-tunnel.sh
|
|
```
|
|
|
|
Er stellt der Reihe nach fest, wo es klemmt, startet und zieht hoch, was fehlt,
|
|
räumt die gemerkten Ströme weg — und sagt am Ende, was noch von Hand bleibt. Er
|
|
fasst den Tunnel-Container **nicht** neu an; genau das wäre die Ursache und
|
|
nicht die Lösung.
|
|
|
|
Was er tut, steht unten einzeln, falls man es von Hand nachvollziehen will.
|
|
|
|
---
|
|
|
|
## Von Hand 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 vpn-hub wg show
|
|
|
|
# 2. Läuft der Container, dem der Namensraum mit wg0 gehört?
|
|
sudo -u clupilot docker compose ps vpn-hub
|
|
|
|
# 3. Was sagt er beim Starten?
|
|
sudo -u clupilot docker compose logs --tail=40 vpn-hub
|
|
```
|
|
|
|
**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.9 kann das gar nicht mehr passieren.** Der Hub hat eine feste
|
|
> Adresse im Compose-Netz (`172.18.0.240`, über `CLUPILOT_VPN_HUB_IP`
|
|
> änderbar). Nach einem Neubau entsteht damit exakt dieselbe Weiterleitung, und
|
|
> die gemerkten Ströme bleiben gültig. Was unten steht, gilt für Server, die
|
|
> älter sind — und als Rückfahrkarte, falls jemand das Subnetz ändert.
|
|
>
|
|
> **Seit v1.4.6 macht das Update das Aufräumen ohnehin 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 vpn-hub wg-quick up wg0
|
|
|
|
# Steht die Konfiguration überhaupt noch im Datenträger?
|
|
sudo -u clupilot docker compose exec -T vpn-hub 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 vpn-hub
|
|
sudo -u clupilot docker compose logs --tail=40 vpn-hub
|
|
```
|
|
|
|
Prozess 1 ist `/usr/local/bin/vpn-hub`. Das Skript zieht wg0 hoch und tut danach
|
|
nichts mehr — genau das ist die Aufgabe. Steht dort etwas anderes, läuft der
|
|
Server auf einem Stand vor v1.4.8, und der Tunnel hängt noch am
|
|
Provisionierungs-Arbeiter.
|
|
|
|
---
|
|
|
|
## 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 = <Hub>` 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
|
|
|
|
Fünf 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. Dasselbe gilt seither für den Knopf „Dienste neu
|
|
starten" in der Konsole — der lief über denselben Befehl.
|
|
* **Bis v1.4.7** wohnte wg0 im Container des Provisionierungs-Arbeiters, also im
|
|
Abbild `clupilot-app`. Das wird bei fast jeder Freigabe neu gebaut, und ein
|
|
neu gebauter Container bekommt eine neue Adresse — mit allem, was oben unter
|
|
„gemerkte Ströme" steht. Seit **v1.4.8** gehört der Namensraum einem eigenen
|
|
Container `vpn-hub` mit eigenem, selten wechselndem Abbild. Nachgemessen:
|
|
App-Abbild neu gebaut, Arbeiter und Brücke neu erzeugt — der Hub blieb
|
|
derselbe Container, wg0 und beide Zugänge unangetastet.
|
|
* **Bis v1.4.8** bekam der Hub bei jedem Neubau die nächste freie Adresse im
|
|
Compose-Netz. Genau darauf zeigen die gemerkten UDP-Ströme — eine neue Adresse
|
|
machte sie alle ungültig. Seit **v1.4.9** hat er eine feste. Nachgemessen:
|
|
`172.18.0.240` vor und nach `up -d --force-recreate vpn-hub`.
|
|
|
|
Erzwungen durch `tests/Feature/DeploymentRunsAsTheAppUserTest.php` — der Container
|
|
darf nicht in der Neustart-Liste stehen, und der conntrack-Griff muss im Skript
|
|
bleiben.
|