Patruzeci de fișiere .ovpn pentru o țară sosesc de la un furnizor, iar planul pare evident: copiază unul aleatoriu la locul lui, apoi pornește tunelul. Scris ca un pipeline în ExecStart, planul moare la pornire cu un cod de stare care nu explică nimic. Fișierul de unitate nu este un script, iar remedierea este fie să aduci un shell explicit, fie să renunți complet la alegerea fișierelor.

Simptomul: o unitate care pornește și moare imediat

Starea arată că serviciul a eșuat într-o fracțiune de secundă, iar linia din jurnal numește o comandă pe care niciun shell nu ar fi primit-o vreodată. Nimic despre tunel nu apare, pentru că tunelul nu a început niciodată.

Citirea liniei de comandă exacte din jurnal este cea mai rapidă cale de a confirma acest lucru. systemd reproduce ceea ce a executat, iar șirul va arăta caracterele pipeline-ului ca argumente literale, nu ca operatori.

De ce ExecStart nu poate rula un pipeline

systemd împarte singur linia de comandă, aplică propria citare și substituire de variabile, apoi execută rezultatul direct. Pipeline-urile, redirecționarea, extinderea de tipare de către un shell și substituirea comenzilor pur și simplu nu fac parte din această gramatică. Este o alegere de proiectare și nu o omisiune: o unitate declară ce trebuie executat, iar logica de shell aparține unui script pe care unitatea îl invocă. Ambele remedieri decurg de aici și niciuna nu cere acordarea de privilegii suplimentare unității.

Aceasta explică și codul de ieșire înșelător. Primul argument este tratat ca binarul, așa că o linie malformată eșuează înainte ca vreo parte a logicii tale să ruleze.

Faceți selecția în ExecStartPre

Remedierea directă este un pas de pregătire care apelează explicit un shell, păstrând selecția și pornirea în aceeași unitate, astfel încât o defecțiune într-una să nu o lase pe cealaltă să ruleze singură.

[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

Trei detalii decid dacă acest lucru supraviețuiește contactului cu o mașină reală. Denumirea este prima capcană: systemd înlocuiește %i în timpul analizei unității, mult înainte de a rula bash, deci specificatorul trebuie să stea în afara ghilimelelor simple. xargs -r împiedică cp să ruleze fără argument atunci când tiparul nu se potrivește cu nimic. Iar un pas de pregătire eșuat oprește unitatea, iar acesta este rezultatul corect: pornirea cu configurația de ieri este mai rea decât nepornirea. O alegere aleatorie care ia mereu același fișier nu este de obicei ghinion. Verificați dacă fișierul copiat este suprascris de o actualizare de pachet sau dacă tiparul se potrivește doar cu o singură intrare învechită.

Sau lăsați OpenVPN să aleagă punctul final

OpenVPN poate deja să țină mai multe puncte finale într-un singur profil și să aleagă aleatoriu dintre ele, ceea ce elimină complet shell-ul, copierea și accesul de scriere din calea de pornire.

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

Această formă păstrează alegerea serverului în fișierul scris de furnizor, așa că o rotație care redenumește fișiere nu strică unitatea. Face, de asemenea, lista de candidați auditabilă, ceea ce un tipar pe un director nu este niciodată. Amestecarea își păstrează locul atunci când profilurile diferă în mai mult de un punct final: certificate diferite, directive de rutare diferite, politică de cifrare diferită. În acel caz alegerea este între configurații întregi, iar un pas cu shell este modul onest de a exprima acest lucru.

Recitiți instanța și fișierul pe care l-a folosit

Confirmați ce unitate rulează de fapt înainte de a depana conținutul ei. Serviciul meta împachetat și șablonul sunt infrastructură; unitățile care corespund fișierelor tale sunt instanțele numite după ele.

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

O instanță despre care nimeni nu își amintește că a activat-o duce de obicei la un fișier de configurare rătăcit în directorul pachetului. Dezactivați acea instanță numită în locul șablonului, altfel următoarea actualizare de pachet o va readuce. După modificare, porniți unitatea și citiți linia de comandă pe care o raportează jurnalul, apoi confirmați calea de configurare pe care a deschis-o efectiv. Acea singură verificare separă o alegere aleatorie funcțională de un serviciu care refolosește în tăcere un fișier de luna trecută.

Articole similare