Coldwast
Generador de archivos de servicio systemd
Escribe el comando que arranca tu aplicación y obtén una unidad .service lista para colocar en /etc/systemd/system/, con los comandos de instalación correspondientes. El generador también revisa lo que has escrito y señala los errores que hacen fallar una unidad en el primer arranque. Todo se ejecuta en tu navegador.

Tu archivo de unidad
Lo que ha detectado el generador
Instalarlo
Las cinco líneas que deciden si funciona
ExecStart no es un shell. systemd divide la línea en argumentos por sí mismo y ejecuta el programa directamente. Una tubería, una redirección > o un && llega a tu programa como argumento literal. systemd también expande $VAR por su cuenta, así que un dólar literal se escribe $$. Cuando el generador detecta sintaxis de shell, envuelve el comando en /bin/sh -c y hace ese escape por ti.
Usa una ruta absoluta. Una ruta como ./server se rechaza directamente. Un nombre sin ruta como node se acepta, pero systemd solo busca en sus propios directorios fijos, no en el PATH de tu shell, así que un Node instalado con nvm o una herramienta en ~/.local/bin no se encuentra.
Type=simple o exec para casi todo. Un servidor web, un worker o un bot que se queda en primer plano es simple. exec difiere en algo útil: el arranque solo se da por bueno cuando el binario se ha ejecutado de verdad, así que una ruta errónea hace fallar systemctl start en lugar de fallar en silencio un momento después. forking es para demonios antiguos que se van solos a segundo plano, y notify solo funciona si el programa llama a sd_notify.
Restart=on-failure, con un límite. on-failure reinicia tras un fallo o una salida distinta de cero, pero no tras una parada limpia; always reinicia incluso entonces. Por defecto systemd permite 5 arranques en 10 segundos, y con una espera de 5 segundos una app que falla nunca llega a ese límite, así que entra en un bucle infinito. StartLimitIntervalSec=300 con StartLimitBurst=5 hace que se rinda y deje un estado de fallo claro.
Wants= y After= juntos. After=network-online.target por sí solo solo fija un orden; no activa el target. Sin Wants=network-online.target tu servicio puede arrancar antes de que la red esté lista: el clásico «funciona tras un reinicio manual, falla al arrancar la máquina».
El aislamiento, y lo que se dejó fuera a propósito
Con ProtectSystem=strict todo el sistema de archivos es de solo lectura para el servicio, salvo las rutas que indiques en ReadWritePaths=. PrivateTmp le da su propio /tmp, NoNewPrivileges le impide ganar permisos mediante binarios setuid, y los ajustes de kernel y cgroup le impiden cambiar el estado del sistema. Ejecuta systemd-analyze security tuapp.service antes y después: muestra una puntuación de exposición y lista cada ajuste que sigue abierto.
Faltan a propósito dos recomendaciones habituales. MemoryDenyWriteExecute=true rompe los compiladores just-in-time, es decir Node.js, la JVM y PyPy. PrivateDevices=true no da problemas en una app web, pero rompe cualquier cosa que hable con una GPU o un puerto serie. Añádelas tú si sabes que tu programa no las necesita.

Cuando no arranca: los códigos de salida
systemctl status tuapp muestra un estado como status=203/EXEC. El número indica qué paso falló antes incluso de que tu programa se ejecutara:
| Estado | Significado | Solución habitual |
|---|---|---|
203/EXEC | No se pudo ejecutar el programa | Ruta errónea, sin permiso de ejecución o script sin línea shebang |
200/CHDIR | WorkingDirectory no existe o no es accesible | Créalo o comprueba que ProtectHome no lo oculta |
217/USER | La cuenta de User= no existe | Ejecuta la línea useradd de arriba |
226/NAMESPACE | No se pudo montar el aislamiento | Una ruta de ReadWritePaths no existe: créala o ponle el prefijo - |
Cualquier otro fallo es tu propio programa saliendo, y su salida está en journalctl -u tuapp -b.
Cambiarlo más adelante
Tras editar el archivo en /etc/systemd/system/, ejecuta sudo systemctl daemon-reload antes de reiniciar, o systemd seguirá usando la versión antigua. Para una unidad instalada por un paquete, no la edites en su sitio: sudo systemctl edit tuapp crea un archivo de sobrescritura que sobrevive a las actualizaciones y recarga systemd por ti.
Relacionado: qué es un VPS, poner un proxy inverso delante de la app, lo básico de SSH y, para tareas programadas, el explicador de expresiones cron.