ExecStart no es un shell: arreglar una unidad auxiliar de VPN
ExecStart ejecuta un programa con argumentos, no una tubería de shell. Use un intérprete explícito o un script real; después verifique la unidad y lea el registro.
Copie una línea de comandos que funcione en ExecStart, recargue y la unidad falla o sale en silencio con los argumentos tratados como nombres de archivo. Nada está roto en systemd. ExecStart es una lista de argumentos, no un shell, así que las tuberías, la redirección y los condicionales pierden su sentido en el momento en que salen de su terminal. Decida dónde corresponde el shell y luego escriba una unidad que diga exactamente qué debe ejecutarse.
Por qué la tubería de ExecStart no hace nada
Cuando se escribe un comando en una terminal, el shell lo analiza primero. Construye una tubería, abre archivos para la redirección y expande variables antes de que empiece cualquier programa. systemd no hace nada de eso: divide ExecStart según sus propias reglas y ejecuta el programa resultante con esos argumentos. Por eso > llega como argumento literal, y | se entrega al programa en lugar de conectar dos procesos. La unidad no se comporta mal; la sintaxis quería decir otra cosa.
Eso es deliberado y no descuidado, porque el tratamiento predecible de los argumentos es lo que hace auditables las unidades. Solo sorprende a quienes dan por hecho que hay un shell.
Escriba una unidad que diga exactamente qué se ejecuta
Empiece con una unidad pequeña cuyo propósito sea visible en el registro, para que los problemas de análisis queden separados de los del túnel. Esta solo informa de la versión de un binario.
[Unit]
Description=Report the installed OpenVPN version
[Service]
Type=oneshot
ExecStart=/usr/sbin/openvpn --version
StandardOutput=journal
StandardError=journalLa ruta es un marcador de posición, así que sustitúyala por el binario que realmente está instalado. Type=oneshot encaja con un comando que se ejecuta hasta terminar, y la configuración del registro coloca su salida donde pueda leerla sin terminal. Deliberadamente no hay sección de instalación, así que la unidad se invoca a mano en lugar de habilitarse al arrancar. Valide el archivo antes de iniciarlo, porque una errata en el nombre de una directiva falla de forma distinta que una errata en la ruta.
systemd-analyze verify /etc/systemd/system/openvpn-version.service
systemctl start openvpn-version.serviceMantenga la lógica de shell en un script
Cuando un auxiliar necesita de verdad lógica condicional, ponga esa lógica en un script y llámelo explícitamente. El script necesita una línea de intérprete, permiso de ejecución y códigos de salida que el servicio pueda informar. Lanzar /bin/sh -c con un comando entre comillas funciona, pero esconde las reglas de comillas dentro de una unidad y dificulta la revisión. Un script con nombre se puede probar a mano y reemplazar después sin editar la unidad. No dependa del perfil de shell del usuario interactivo, porque un servicio arranca con su propio entorno.
Establezca WorkingDirectory cuando importen las rutas relativas, y pase el entorno mediante las directivas admitidas de la unidad en lugar de exportarlo en una terminal. Los secretos pertenecen a archivos protegidos o credenciales, no a listas de argumentos que el registro pueda grabar.
Compruebe la unidad que realmente existe
Los archivos drop-in cambian el comportamiento sin tocar el archivo que recuerda haber editado. Lea qué cargó el gestor y qué informó la última ejecución.
systemctl cat vpn-helper.service
journalctl -u vpn-helper.service -n 20 --no-pagerEl volcado de la unidad incluye los drop-in en orden de carga, y de ahí suele venir un ExecStart inesperado. Tras cualquier cambio, recargue el gestor y confirme que la nueva definición es lo que imprime systemctl cat. El registro muestra la línea de comandos exacta y el estado de salida, lo que separa un problema de argumentos de un binario ausente o un error de permisos. Después decida si el auxiliar pertenece al ciclo de vida de la VPN existente o debe seguir siendo un diagnóstico manual, porque un segundo proceso de túnel en segundo plano crea un propietario en competencia.
Una unidad que imprime la salida correcta cuando se le pide es un buen primer hito. Todavía no es un túnel, y no debería fingir que lo es.