Das Problem

Du hostest einen Proxmox-Server bei einem Cloud-Provider (srv-r2d2), der auf dein internes Netzwerk zugreifen muss. Die Lösung: OpenVPN-Client in einer Screen-Session.

# Das fragile Setup
screen -S openvpn
cd /root
openvpn --config gw-deathstar.ovpn
# Passwort eingeben
# Ctrl+A+D zum Detachen

Was schiefgehen kann:

  1. Screen stirbt: Session crashed, VPN tot, keine Auto-Reconnect
  2. Reboot: Nach Neustart ist die Session weg
  3. Jemand killt die Session: screen -X -S openvpn quit → Game Over
  4. Passwort-Eingabe: Manuelle Intervention bei jedem Start
  5. Keine Logs: Debugging via Screen-Scroll? Viel Spaß damit
  6. Kein Monitoring: Tunnel down? Du merkst es wenn die ersten Tickets reinkommen

Das ist wie den Todesstern ohne Schild in den Kampf zu schicken - funktioniert bis es nicht mehr funktioniert.

TL;DR

Migriere deinen OpenVPN-Client zu einem systemd Service mit:

  • ✅ Auto-Reconnect bei Verbindungsabbruch (max 120s)
  • ✅ Automatischer Start nach Reboot
  • ✅ Credentials in Datei (kein manuelles Tippen)
  • ✅ Proper Logging via journalctl
  • ✅ Health-Check Cron (alle 5 Min)
  • ✅ Monitoring via Zabbix

Die Lösung: systemd Service

Schritt 1: Config + Credentials vorbereiten

OpenVPN-Configs gehören nach /etc/openvpn/client/.

# Config von ~/gw-deathstar.ovpn nach /etc/openvpn/client/ kopieren
cp ~/gw-deathstar.ovpn /etc/openvpn/client/gw-deathstar.conf

# Credentials-Datei erstellen
cat > /etc/openvpn/client/gw-deathstar.auth << EOF
luke.skywalker
your-password
EOF

chmod 600 /etc/openvpn/client/gw-deathstar.auth

# Config anpassen: auth-user-pass mit Datei
echo "auth-user-pass /etc/openvpn/client/gw-deathstar.auth" >> /etc/openvpn/client/gw-deathstar.conf

⚠️ Sicherheit: Die .auth Datei hat sensible Credentials! Permissions 600 (nur root lesbar) sind Pflicht.

Schritt 2: systemd Service aktivieren

OpenVPN kommt mit einem systemd Template openvpn-client@.service. Das @ Teil ist der Name deiner Config (ohne .conf).

# Service aktivieren (startet bei Boot)
systemctl enable openvpn-client@gw-deathstar

# Service starten
systemctl start openvpn-client@gw-deathstar

# Status prüfen
systemctl status openvpn-client@gw-deathstar

Der Service heißt openvpn-client@gw-deathstar weil die Config /etc/openvpn/client/gw-deathstar.conf heißt.

Schritt 3: Verifikation

# 1. Service läuft?
systemctl is-active openvpn-client@gw-deathstar
# Erwartung: active

# 2. tun0 Interface existiert?
ip addr show tun0
# Erwartung: inet 10.99.99.2/24

# 3. Routing zu internem Netz?
ip route | grep tun0
# Erwartung: 192.168.66.0/24 via 10.99.99.1 dev tun0

# 4. VPN-Gateway erreichbar?
ping -c3 10.99.99.1
# Erwartung: 3 packets transmitted, 3 received

# 5. Internes Netzwerk erreichbar?
ping -c3 192.168.66.1
# Erwartung: 3 packets transmitted, 3 received

Schritt 4: Auto-Reconnect testen

Der systemd Service hat eingebautes Auto-Reconnect:

# Kill die Verbindung
pkill -f "openvpn --config.*gw-deathstar"

# Warte 30s
sleep 30

# Service sollte neu gestartet sein
systemctl status openvpn-client@gw-deathstar
# Erwartung: active (running)

Die systemd-Unit hat standardmäßig Restart=on-failure und RestartSec=120s.

Schritt 5: Health-Check Cron (optional aber empfohlen)

Ein Cron-Job prüft regelmäßig ob der Service läuft und ob das Netz erreichbar ist.

# Script erstellen
cat > /usr/local/bin/openvpn-healthcheck.sh << 'EOF'
#!/bin/bash
set -euo pipefail

SERVICE="openvpn-client@gw-deathstar"
TUNNEL_IP="10.99.99.1"
INTERNAL_IP="192.168.66.1"

# 1. Service läuft?
if ! systemctl is-active --quiet "$SERVICE"; then
    echo "$(date): $SERVICE not running, starting..."
    systemctl start "$SERVICE"
    exit 0
fi

# 2. tun0 existiert?
if ! ip link show tun0 &>/dev/null; then
    echo "$(date): tun0 missing, restarting $SERVICE..."
    systemctl restart "$SERVICE"
    exit 0
fi

# 3. VPN-Gateway erreichbar?
if ! ping -c1 -W2 "$TUNNEL_IP" &>/dev/null; then
    echo "$(date): $TUNNEL_IP unreachable, restarting $SERVICE..."
    systemctl restart "$SERVICE"
    exit 0
fi

# 4. Internes Netz erreichbar?
if ! ping -c1 -W2 "$INTERNAL_IP" &>/dev/null; then
    echo "$(date): $INTERNAL_IP unreachable, restarting $SERVICE..."
    systemctl restart "$SERVICE"
    exit 0
fi

# Alles grün
exit 0
EOF

chmod +x /usr/local/bin/openvpn-healthcheck.sh

# Cron-Job (alle 5 Min)
echo "*/5 * * * * root /usr/local/bin/openvpn-healthcheck.sh >> /var/log/openvpn-healthcheck.log 2>&1" > /etc/cron.d/openvpn-healthcheck

Der Health-Check ist dein R2-D2 - er repariert die Verbindung bevor du überhaupt merkst dass sie tot war.

Monitoring mit Zabbix

Für Production-Umgebungen reicht ein Health-Check nicht - du willst sofort benachrichtigt werden wenn die Verbindung stirbt.

Items

ItemKeyIntervalBeschreibung
Service Statussystemd.unit.info[openvpn-client@gw-deathstar.service,ActiveState]1mIst der Service active/inactive/failed?
Tunnel Gatewaynet.tcp.service[icmppingsec,10.99.99.1]2mVPN-Gateway per Ping erreichbar?
tun0 Interfacevfs.file.exists[/sys/class/net/tun0]1mExistiert das tun0 Interface?

Triggers

TriggerSeverityExpression
Service downDisasterlast(...ActiveState)<>"active"
Tunnel unreachableHighlast(...icmppingsec...)=0
tun0 missingWarninglast(...vfs.file.exists...)=0

Trigger Dependencies: “Tunnel unreachable” und “tun0 missing” hängen von “Service down” ab - du willst nicht 3 Alerts für dasselbe Problem.

Troubleshooting: Wenn die Verbindung nicht funktioniert

Diagnose-Befehle

Wenn der Service nicht startet oder die Verbindung abbricht:

# 1. Service-Status prüfen
systemctl status openvpn-client@gw-deathstar
# Achte auf: "Active: failed" oder "Active: activating (auto-restart)"

# 2. Logs der letzten 50 Zeilen
journalctl -u openvpn-client@gw-deathstar -n 50

# 3. Logs in Echtzeit verfolgen
journalctl -u openvpn-client@gw-deathstar -f

# 4. Auth-Fehler prüfen
journalctl -u openvpn-client@gw-deathstar | grep -i "auth\|credential\|tls"

# 5. Netzwerk-Probleme prüfen
journalctl -u openvpn-client@gw-deathstar | grep -i "timeout\|unreachable\|connection"

Log-Beispiele

Healthy (funktioniert):

Feb 16 07:30:42 srv-r2d2 openvpn[1234]: Initialization Sequence Completed
Feb 16 07:30:42 srv-r2d2 openvpn[1234]: /sbin/ip addr add dev tun0 10.99.99.2/24
Feb 16 07:30:42 srv-r2d2 openvpn[1234]: /sbin/ip route add 192.168.66.0/24 via 10.99.99.1

Broken: Auth-Fehler (falsche Credentials):

Feb 16 07:32:15 srv-r2d2 openvpn[1235]: AUTH: Received control message: AUTH_FAILED
Feb 16 07:32:15 srv-r2d2 openvpn[1235]: SIGTERM received, process exiting

Fix: Prüfe /etc/openvpn/client/gw-deathstar.auth - Username/Password korrekt?

Broken: Connection Timeout (Firewall/Route-Problem):

Feb 16 07:33:20 srv-r2d2 openvpn[1236]: Connection reset, restarting
Feb 16 07:33:20 srv-r2d2 openvpn[1236]: TCP/UDP: Closing socket
Feb 16 07:33:25 srv-r2d2 openvpn[1236]: Connection timeout

Fix: Prüfe ob VPN-Server erreichbar ist: ping vpn.deathstar.lan oder telnet vpn.deathstar.lan 1194

Broken: Permissions (Datei nicht lesbar):

Feb 16 07:34:10 srv-r2d2 openvpn[1237]: Options error: --auth-user-pass fails with '/etc/openvpn/client/gw-deathstar.auth': Permission denied (errno=13)

Fix: chmod 600 /etc/openvpn/client/gw-deathstar.auth && chown root:root /etc/openvpn/client/gw-deathstar.auth

Häufige Probleme

ProblemSymptomDiagnoseFix
Auth fehlschlägtAUTH_FAILED in Logscat /etc/openvpn/client/gw-deathstar.authCredentials prüfen
tun0 nicht erstelltip addr show tun0 = not existjournalctl ... | grep tunKernel-Modul tun laden: modprobe tun
Service auto-restart Loopsystemctl status zeigt “activating (auto-restart)”journalctl -n 100Credentials/Config/Firewall prüfen
Route fehltping 192.168.66.1 = no routeip route | grep tun0In .conf: route 192.168.66.0 255.255.255.0 hinzufügen

Migration: Step-by-Step

Du hast einen laufenden OpenVPN-Client in einer Screen-Session? So migrierst du:

1. Backup der Screen-Session Config

# Config sichern
cp ~/gw-deathstar.ovpn ~/gw-deathstar.ovpn.backup

# Aktuelles Setup dokumentieren (Route, IP, etc.)
ip addr show tun0 > ~/vpn-migration-state.txt
ip route | grep tun0 >> ~/vpn-migration-state.txt

2. Screen-Session stoppen

# Screen-Session finden
screen -ls

# Session terminieren
screen -X -S openvpn quit

# Verifizieren: tun0 sollte weg sein
ip addr show tun0
# Erwartung: Device "tun0" does not exist

3. systemd Service setup (siehe oben)

# Config + Credentials wie in Schritt 1-2 beschrieben
# ...

# Service starten
systemctl enable --now openvpn-client@gw-deathstar

4. Funktionstest

# Route Check
ip route | grep tun0
# Erwartung: 192.168.66.0/24 via 10.99.99.1 dev tun0

# Internal Network Test
ping -c3 192.168.66.1
ssh c3po@192.168.66.25  # Test SSH zu internem Host

5. Rollback-Plan (falls was schiefgeht)

# Service stoppen
systemctl stop openvpn-client@gw-deathstar
systemctl disable openvpn-client@gw-deathstar

# Alte Screen-Session wiederherstellen
screen -S openvpn
openvpn --config ~/gw-deathstar.ovpn.backup
# Ctrl+A+D

Lessons Learned

✅ Was gut funktioniert

  1. Auto-Reconnect: systemd startet den Service nach max. 120s neu - kein manueller Eingriff nötig
  2. Credentials in Datei: auth-user-pass /path/to/file eliminiert manuelle Passwort-Eingabe
  3. Logging: journalctl -u openvpn-client@gw-deathstar -f zeigt alle Events
  4. Health-Check Cron: Fängt Edge-Cases wo systemd nicht greift (z.B. Service läuft aber Tunnel tot)
  5. Monitoring: Zabbix-Alerts per Telegram - du weißt SOFORT wenn was stirbt

⚠️ Gotchas

  1. Credentials-Permissions: chmod 600 ist Pflicht, sonst startet OpenVPN nicht
  2. Config-Pfad: Muss /etc/openvpn/client/NAME.conf heißen, sonst findet systemd die Config nicht
  3. Auth-User-Pass Zeile: Alte Config hatte auth-user-pass ohne Pfad (für interaktive Eingabe) - das MUSS angepasst werden
  4. DNS/Routing: Wenn der VPN-Server DNS pushed, kann das mit systemd-resolved kollidieren - evtl. pull-filter ignore "dhcp-option DNS" in die Config

🚀 Bonus: Multi-VPN Setup

Du hast mehrere VPNs? Leg für jeden eine eigene Config an:

/etc/openvpn/client/
├── gw-deathstar.conf
├── gw-deathstar.auth
├── office-vpn.conf
└── office-vpn.auth

Start separate Services:

systemctl enable --now openvpn-client@gw-deathstar
systemctl enable --now openvpn-client@office-vpn

Jeder Service kriegt sein eigenes tun-Device (tun0, tun1, …).

Fazit

Screen-Sessions für Production-VPNs sind wie ein TIE-Fighter ohne Schild - cool, aber riskant. systemd Services mit Auto-Reconnect und Monitoring sind der X-Wing mit vollem Arsenal.

Vorher:

  • 😰 Screen stirbt → VPN tot
  • 😰 Reboot → manuelle Intervention nötig
  • 😰 Tunnel down → du merkst es nach 2h

Nachher:

  • ✅ Service stirbt → Auto-Restart nach max. 120s
  • ✅ Reboot → Service startet automatisch
  • ✅ Tunnel down → Zabbix-Alert nach 2 Min + Health-Check Restart nach 5 Min

May the Service be with you! 🚀


Dieser Artikel entstand nach der Migration von srv-r2d2 - von fragiler Screen-Session zu robustem systemd Service. Zero Downtime seit der Migration.