Selección aleatoria de OpenVPN en systemd: por que falla ExecStart
systemd non é unha shell, así que unha copia mesturada dentro de ExecStart morre. Move a elección a ExecStartPre ou deixa que OpenVPN escolla el mesmo un servidor.
Corenta ficheiros .ovpn dun país chegan dun provedor, e o plan parece obvio: copiar un ao azar no seu sitio e despois iniciar o túnel. Escrito como unha tubería dentro de ExecStart, ese plan morre no arranque cun código de estado que non explica nada. O ficheiro de unidade non é un script, e a reparación consiste en traer unha shell de forma explícita ou en deixar de escoller ficheiros por completo.
O síntoma: unha unidade que arranca e morre de inmediato
O estado mostra que o servizo fallou nunha fracción de segundo, e a liña do rexistro nomea un comando que ningunha shell recibiría xamais. Non aparece nada sobre o túnel, porque o túnel nunca comezou.
Ler a liña de comandos exacta do rexistro é a forma máis rápida de confirmalo. systemd repite o que executou, e a cadea mostrará os caracteres da tubería como argumentos literais en lugar de operadores.
Por que ExecStart non pode executar unha tubería
systemd divide a liña de comandos por si mesmo, aplica as súas propias comiñas e substitución de variables, e despois executa o resultado directamente. As tuberías, a redirección, a expansión de patróns por unha shell e a substitución de comandos simplemente non forman parte desa gramática. É unha decisión de deseño e non unha omisión: unha unidade declara que executar, e a lóxica de shell pertence a un script que a unidade invoca. Ambas reparacións derivan diso, e ningunha esixe dar máis privilexios á unidade.
Tamén explica o código de saída enganoso. O primeiro argumento trátase como o binario, así que unha liña mal formada falla antes de que se execute nada da túa lóxica.
Fai a selección en ExecStartPre
A reparación directa é un paso de preparación que chama unha shell de forma explícita, mantendo a selección e o arranque na mesma unidade para que un fallo nun non deixe o outro funcionando só.
[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
Tres detalles deciden se isto sobrevive ao contacto cunha máquina real. O nomeado é a primeira trampa: systemd substitúe %i mentres analiza a unidade, moito antes de que bash se execute, así que o especificador debe quedar fóra das comiñas simples. xargs -r impide que cp se execute sen argumento cando o patrón non coincide con nada. E un paso de preparación fallido detén a unidade, que é o resultado correcto: arrancar coa configuración de onte é peor que non arrancar. Unha selección aleatoria que sempre toma o mesmo ficheiro normalmente non é mala sorte. Comproba se o ficheiro copiado está a ser sobrescrito por unha actualización do paquete, ou se o patrón só coincide cunha entrada obsoleta.
Ou deixa que OpenVPN escolla o extremo
OpenVPN xa pode ter varios extremos nun perfil e escoller entre eles ao azar, o que elimina por completo a shell, a copia e o acceso de escritura da ruta de arranque.
client
remote-random
<connection>
remote au1.example.net 1194 udp
</connection>
<connection>
remote au2.example.net 1194 udp
</connection>
Esta forma mantén a elección de servidor dentro do ficheiro que redactou o provedor, así que unha rotación que renomea ficheiros non rompe a unidade. Tamén fai auditable a lista de candidatos, algo que un patrón sobre un directorio nunca é. A mestura segue merecendo o seu lugar cando os perfís difiren en máis que un extremo: certificados distintos, directivas de encamiñamento distintas, política de cifrado distinta. Nese caso a elección é entre configuracións enteiras e un paso de shell é a maneira honesta de expresalo.
Volve ler a instancia e o ficheiro que utilizou
Confirma que unidade se executa realmente antes de depurar o seu contido. O servizo meta empaquetado e o modelo son infraestrutura; as unidades que corresponden aos teus ficheiros son as instancias que levan o seu nome.
systemctl list-units 'openvpn*'
systemctl cat [email protected]
journalctl -u openvpn@au -n 30 --no-pager
Unha instancia que ninguén recorda ter activado adoita remontarse a un ficheiro de configuración perdido no directorio do paquete. Desactiva esa instancia con nome en lugar do modelo, se non a seguinte actualización do paquete traeraa de volta. Despois do cambio, inicia a unidade e le a liña de comandos que informa o rexistro, e despois confirma a ruta de configuración que abriu realmente. Esa única comprobación separa unha selección aleatoria que funciona dun servizo que reutiliza en silencio un ficheiro do mes pasado.