#!/usr/bin/env bash # # CluPilot — den Tunnel wieder hinbekommen. # # Ein Befehl statt einer Befehlsfolge, die man sich im Ernstfall merken müsste. # Das Skript stellt der Reihe nach fest, WO es klemmt, sagt es in klaren Worten, # und behebt, was sich von hier aus beheben lässt. # # Es macht nichts Zerstörerisches: kein Neubau, kein Löschen, kein Neustart des # Tunnel-Containers. Genau der wäre nämlich die Ursache und nicht die Lösung — # ein Neubau schreibt die Weiterleitungsregeln neu und reisst alle Sitzungen ab. # # sudo -u clupilot bash deploy/rescue-tunnel.sh # # Ausführlich: docs/runbooks/tunnel-recovery.md set -uo pipefail cd "$(cd "$(dirname "$0")/.." && pwd)" log() { printf '\n\033[1;34m==>\033[0m %s\n' "$*"; } ok() { printf '\033[1;32m ✓\033[0m %s\n' "$*"; } warn() { printf '\033[1;33m !\033[0m %s\n' "$*"; } bad() { printf '\033[1;31m ✗\033[0m %s\n' "$*"; } if [[ $EUID -eq 0 ]]; then echo "Bitte als Dienstbenutzer starten, nicht als root:" >&2 echo " sudo -u clupilot bash $0" >&2 exit 1 fi hub() { docker compose exec -T vpn-hub "$@" 2>/dev/null; } WG_PORT="$(grep -m1 '^WG_HUB_PORT=' .env 2>/dev/null | cut -d= -f2- | tr -d '"'"'"' ')" WG_PORT="${WG_PORT:-51820}" # ── 1. Läuft der Container, in dessen Namensraum wg0 lebt? ─────────────────── log "Der Container mit dem Tunnel" if ! docker compose ps --status running vpn-hub 2>/dev/null | grep -q vpn-hub; then bad "vpn-hub läuft nicht. Ich starte ihn." docker compose up -d vpn-hub || true sleep 8 fi if docker compose ps --status running vpn-hub 2>/dev/null | grep -q vpn-hub; then ok "läuft" else bad "startet nicht. Das Protokoll sagt warum:" docker compose logs --tail=30 vpn-hub exit 1 fi # Prozess 1 verrät den Stand. Gehört der Namensraum noch dem # Warteschlangen-Arbeiter, nimmt ihn jede Freigabe und jeder Absturz mit. if hub sh -c 'tr "\0" " " < /proc/1/cmdline' | grep -q 'vpn-hub'; then ok "Der Tunnel hat einen eigenen Container (v1.4.8 oder neuer)" else warn "Dieser Server hat den eigenen Tunnel-Container noch nicht." warn "Bis dahin nimmt jede Freigabe den Tunnel mit. Update einspielen." fi # ── 2. Steht wg0? ──────────────────────────────────────────────────────────── log "Das Interface wg0" if ! hub wg show wg0 >/dev/null 2>&1; then bad "wg0 fehlt. Ich ziehe es hoch." hub wg-quick up wg0 || true sleep 3 fi if hub wg show wg0 >/dev/null 2>&1; then ok "steht" else bad "lässt sich nicht hochziehen. Liegt die Konfiguration überhaupt da?" hub ls -l /etc/wireguard/ || true echo bad "Weiter in docs/runbooks/tunnel-recovery.md, Abschnitt 'Der Tunnel kommt nicht hoch'." exit 1 fi peers="$(hub wg show wg0 peers | grep -c . || true)" if [[ "${peers:-0}" -gt 0 ]]; then ok "$peers Zugänge geladen" else warn "Kein einziger Zugang geladen — /etc/wireguard/wg0.conf ansehen." fi # ── 3. Kommt auch etwas an? ────────────────────────────────────────────────── # # Das eigentliche Krankheitsbild: der Hub sendet, aber empfängt nichts. Dann # zeigen die im Kernel gemerkten UDP-Ströme noch auf einen Container, den es # nicht mehr gibt — und sie verfallen NICHT, weil WireGuards Keepalive sie alle # 25 Sekunden auffrischt. Das heilt nie von allein. log "Kommen Antworten an?" stumm=0 while read -r line; do [[ -z "$line" ]] && continue empfangen="$(awk '{print $1}' <<<"$line")" [[ "$empfangen" == "0" ]] && stumm=$((stumm + 1)) done < <(hub wg show wg0 transfer | awk '{print $2, $3}') gesamt="$(hub wg show wg0 transfer | grep -c . || echo 0)" if [[ "${stumm:-0}" -gt 0 ]]; then warn "$stumm von $gesamt Zugängen haben noch NIE etwas geschickt." log "Gemerkte UDP-Ströme wegräumen" if sudo -n conntrack -D -p udp --dport "$WG_PORT" >/dev/null 2>&1; then ok "erledigt — die Zugänge bauen sich in den nächsten 30 Sekunden neu auf" else bad "Dafür fehlt mir Root. Bitte einmal von Hand ausführen:" echo echo " sudo conntrack -D -p udp --dport $WG_PORT" echo warn "Damit ich das künftig selbst darf, siehe docs/runbooks/tunnel-recovery.md," warn "Abschnitt 'Einmal einrichten'." fi else ok "Alle Zugänge haben schon Daten geschickt" fi # ── 4. Der Stand, zum Mitlesen ─────────────────────────────────────────────── log "Stand jetzt" hub wg show wg0 || true echo log "Wenn ein HOST weiter fehlt, während andere Zugänge stehen" echo " Dann liegt es auf der Maschine, nicht hier. Über die Konsole des" echo " Anbieters (SSH ist von aussen zu, das ist Absicht):" echo echo " systemctl status wg-quick@wg0" echo " systemctl restart wg-quick@wg0" echo echo " Kommt man dort nicht weit genug, macht dieses Skript auf dem Host SSH" echo " wieder auf — und muss danach zurückgenommen werden:" echo echo " /usr/local/sbin/clupilot-emergency-open-firewall.sh" echo