Willekeurige OpenVPN-keuze in systemd: waarom ExecStart faalt
systemd is geen shell, dus een geschudde kopie in ExecStart sterft. Verplaats de keuze naar ExecStartPre, of laat OpenVPN zelf een server kiezen.
Veertig .ovpn-bestanden voor één land komen van een provider, en het plan lijkt voor de hand te liggen: kopieer er willekeurig een naar zijn plaats en start dan de tunnel. Als pipeline in ExecStart geschreven, sterft dat plan bij het opstarten met een statuscode die niets verklaart. Het unitbestand is geen script, en de reparatie is ofwel expliciet een shell binnenhalen of helemaal stoppen met bestanden kiezen.
Het symptoom: een unit die start en meteen sterft
De status laat zien dat de dienst in een fractie van een seconde mislukte, en de journaalregel noemt een commando dat geen enkele shell ooit zou hebben ontvangen. Niets over de tunnel verschijnt, omdat de tunnel nooit begon.
De exacte commandoregel uit het journaal lezen is de snelste manier om dit te bevestigen. systemd herhaalt wat het uitvoerde, en de string toont de pipeline-tekens als letterlijke argumenten in plaats van als operatoren.
Waarom ExecStart geen pipeline kan uitvoeren
systemd splitst de commandoregel zelf, past zijn eigen quoting en variabelensubstitutie toe en voert het resultaat vervolgens direct uit. Pipes, omleiding, glob-uitbreiding door een shell en commandosubstitutie maken simpelweg geen deel uit van die grammatica. Het is een ontwerpkeuze en geen omissie: een unit zegt declaratief wat er moet draaien, en shell-logica hoort in een script dat de unit aanroept. Beide reparaties volgen daaruit, en geen van beide vereist dat de unit meer rechten krijgt.
Het verklaart ook de misleidende exitcode. Het eerste argument wordt als de binary behandeld, dus een misvormde regel faalt voordat iets van jouw logica draait.
Doe de selectie in ExecStartPre
De directe reparatie is een voorbereidingsstap die expliciet een shell aanroept en de selectie en de start in dezelfde unit houdt, zodat een fout in het ene het andere niet alleen kan laten draaien.
[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
Drie details bepalen of dit contact met een echte machine overleeft. Naamgeving is de eerste valkuil: systemd vervangt %i al bij het parsen van de unit, lang voordat bash draait, dus de specifier moet buiten enkele aanhalingstekens staan. xargs -r voorkomt dat cp zonder argument draait wanneer de glob nergens op past. En een mislukte voorbereidingsstap stopt de unit, en dat is de juiste uitkomst: starten met de configuratie van gisteren is erger dan niet starten. Een willekeurige keuze die altijd hetzelfde bestand pakt is meestal geen pech. Controleer of het gekopieerde bestand door een pakketupdate wordt overschreven, of of de glob maar op één verouderde vermelding past.
Of laat OpenVPN het eindpunt kiezen
OpenVPN kan al meerdere eindpunten in één profiel houden en er willekeurig uit kiezen, wat de shell, de kopie en de schrijftoegang volledig uit het opstartpad haalt.
client
remote-random
<connection>
remote au1.example.net 1194 udp
</connection>
<connection>
remote au2.example.net 1194 udp
</connection>
Deze vorm houdt de serverkeuze in het bestand dat de provider schreef, dus een rotatie die bestanden hernoemt breekt de unit niet. Hij maakt ook de kandidatenlijst controleerbaar, wat een glob over een map nooit is. Het schudden verdient nog steeds zijn plaats wanneer profielen in meer dan een eindpunt verschillen: andere certificaten, andere routeringsrichtlijnen, ander cijferbeleid. In dat geval gaat de keuze tussen hele configuraties en is een shell-stap de eerlijke manier om dat uit te drukken.
Lees de instantie en het bestand dat ze gebruikte terug
Bevestig welke unit echt draait voordat je de inhoud debugt. De verpakte metaservice en het sjabloon zijn infrastructuur; de units die bij jouw bestanden horen, zijn de instanties die daarnaar vernoemd zijn.
systemctl list-units 'openvpn*'
systemctl cat [email protected]
journalctl -u openvpn@au -n 30 --no-pager
Een instantie waarvan niemand zich herinnert dat hij is aangezet, leidt meestal terug naar een verdwaald configuratiebestand in de pakketmap. Schakel die genoemde instantie uit in plaats van het sjabloon, anders brengt de volgende pakketupgrade hem terug. Start na de wijziging de unit en lees de commandoregel die het journaal meldt, en bevestig dan het configuratiepad dat hij werkelijk opende. Die ene controle scheidt een werkende willekeurige keuze van een dienst die stil een bestand van vorige maand hergebruikt.