Vierzig .ovpn-Dateien für ein Land kommen von einem Anbieter, und der Plan wirkt offensichtlich: eine zufällige an ihren Platz kopieren, dann den Tunnel starten. Als Pipeline in ExecStart geschrieben, stirbt dieser Plan beim Booten mit einem Statuscode, der nichts erklärt. Die Unit-Datei ist kein Skript, und die Reparatur besteht entweder darin, eine Shell ausdrücklich ins Spiel zu bringen, oder darin, das Auswählen von Dateien ganz zu lassen.

Das Symptom: eine Unit, die startet und sofort stirbt

Der Status zeigt, dass der Dienst in Sekundenbruchteilen fehlschlug, und die Journal-Zeile nennt einen Befehl, den keine Shell je erhalten hätte. Vom Tunnel erscheint nichts, weil der Tunnel nie begann.

Die exakte Befehlszeile aus dem Journal zu lesen ist der schnellste Weg, das zu bestätigen. systemd gibt wieder, was es ausgeführt hat, und die Zeichenkette zeigt die Pipeline-Zeichen als wörtliche Argumente statt als Operatoren.

Warum ExecStart keine Pipeline ausführen kann

systemd zerlegt die Befehlszeile selbst, wendet seine eigene Quotierung und Variablenersetzung an und führt das Ergebnis dann direkt aus. Pipes, Umleitung, Globbing durch eine Shell und Kommandosubstitution gehören schlicht nicht zu dieser Grammatik. Das ist eine Designentscheidung und keine Auslassung: Eine Unit sagt deklarativ, was laufen soll, und Shell-Logik gehört in ein Skript, das die Unit aufruft. Beide Reparaturen folgen daraus, und keine von beiden verlangt, der Unit mehr Rechte zu geben.

Das erklärt auch den irreführenden Exit-Code. Das erste Argument wird als Binary behandelt, also scheitert eine fehlerhafte Zeile, bevor irgendein Teil Ihrer Logik läuft.

Treffen Sie die Auswahl in ExecStartPre

Die direkte Reparatur ist ein Vorbereitungsschritt, der ausdrücklich eine Shell aufruft und Auswahl und Start in derselben Unit hält, damit ein Fehler im einen das andere nicht allein weiterlaufen lässt.

[Service]
Type=notify
ExecStartPre=/bin/bash -c "ls /etc/openvpn/profiles/au* | shuf -n 1 | xargs -r -I{} cp -f {} /etc/openvpn/%i.conf"
ExecStart=/usr/sbin/openvpn --config /etc/openvpn/%i.conf

Drei Details entscheiden, ob das den Kontakt mit einer echten Maschine übersteht. Die Benennung ist die erste Falle: systemd ersetzt %i schon beim Parsen der Unit, lange bevor bash läuft, also muss der Spezifizierer außerhalb einfacher Anführungszeichen stehen. xargs -r verhindert, dass cp ohne Argument läuft, wenn das Glob nichts trifft. Und ein fehlgeschlagener Vorbereitungsschritt stoppt die Unit, was das richtige Ergebnis ist: Mit der gestrigen Konfiguration zu starten ist schlimmer, als nicht zu starten. Eine zufällige Auswahl, die immer dieselbe Datei nimmt, ist meist kein Pech. Prüfen Sie, ob die kopierte Datei von einem Paket-Update überschrieben wird, oder ob das Glob nur einen einzigen veralteten Eintrag trifft.

Oder lassen Sie OpenVPN den Endpunkt wählen

OpenVPN kann bereits mehrere Endpunkte in einem Profil halten und zufällig unter ihnen wählen, was die Shell, die Kopie und den Schreibzugriff vollständig aus dem Boot-Pfad entfernt.

client
remote-random
<connection>
remote au1.example.net 1194 udp
</connection>
<connection>
remote au2.example.net 1194 udp
</connection>

Diese Form hält die Serverauswahl in der Datei, die der Anbieter erstellt hat, sodass eine Rotation, die Dateien umbenennt, die Unit nicht bricht. Sie macht auch die Kandidatenliste prüfbar, was ein Glob über ein Verzeichnis nie ist. Das Durchmischen verdient seinen Platz weiterhin, wenn sich Profile in mehr als einem Endpunkt unterscheiden: andere Zertifikate, andere Routing-Direktiven, andere Verschlüsselungsrichtlinie. In dem Fall geht es um die Wahl zwischen ganzen Konfigurationen, und ein Shell-Schritt ist die ehrliche Art, das auszudrücken.

Lesen Sie die Instanz und die Datei zurück, die sie benutzt hat

Bestätigen Sie, welche Unit tatsächlich läuft, bevor Sie ihren Inhalt debuggen. Der paketierte Meta-Dienst und das Template sind Infrastruktur; die Units, die Ihren Dateien entsprechen, sind die nach ihnen benannten Instanzen.

systemctl list-units 'openvpn*'
systemctl cat [email protected]
journalctl -u openvpn@au -n 30 --no-pager

Eine Instanz, von der niemand weiß, dass er sie aktiviert hat, führt meist auf eine verirrte Konfigurationsdatei im Paketverzeichnis zurück. Schalten Sie diese benannte Instanz statt des Templates ab, sonst bringt das nächste Paket-Upgrade sie zurück. Starten Sie nach der Änderung die Unit und lesen Sie die Befehlszeile, die das Journal meldet, und bestätigen Sie dann den Konfigurationspfad, den sie tatsächlich geöffnet hat. Diese eine Prüfung trennt eine funktionierende Zufallsauswahl von einem Dienst, der still eine Datei vom letzten Monat wiederverwendet.

Ähnliche Artikel