Ejecutar programas automáticamente al iniciar el servidor (systemd y cron)

Publicado el Actualizado el 6 min de lectura

Así arrancan solas tus aplicaciones, servidores de juego y scripts después de cada reinicio: con una unidad de servicio systemd, el estándar actual, o con una entrada de cron con @reboot.

Arrancar a mano todos los servicios después de cada reinicio del servidor: eso cuesta tiempo y tarde o temprano acaba saliendo mal. Linux trae su propio mecanismo para esto. En esta guía te mostramos cómo ejecutar automáticamente tus propias aplicaciones, servidores de juego, bots o scripts al iniciar el servidor.

Vamos a recorrer dos caminos: una unidad de servicio systemd, que es la solución habitual hoy en día, y la vía más antigua a través de una entrada de cron con @reboot. Ambas funcionan con independencia de la distribución, es decir, igual en Debian, Ubuntu, AlmaLinux y Rocky Linux.

systemd o cron: ¿qué camino te conviene?

systemd es el estándar para los servicios en todas las distribuciones de Linux actuales. Una entrada de cron con @reboot también arranca tu aplicación, pero no sabe hacer nada más que eso.

CaracterísticaUnidad systemdCron con @reboot
Arranque al iniciar el sistema
Reinicio tras una caídasí, automáticono
Consultar el estadosí, con systemctlno
Registro de las salidassí, en el journalsolo si lo rediriges tú
Orden de arranque controlablesí, por ejemplo después de la redsolo de forma aproximada con sleep

Para todo lo que deba ejecutarse de forma permanente, la unidad systemd es la mejor opción. La entrada de cron sigue siendo un apaño rápido para comandos sencillos que se lanzan una sola vez.

Requisitos previos

  • Acceso root por SSH a tu VPS o a tu servidor root.
  • Un script de inicio o un programa que ya arranque correctamente desde la línea de comandos. Pruébalo primero a mano antes de automatizarlo.
  • La ruta absoluta hasta ese script. Las rutas relativas no funcionan de forma fiable durante el arranque del sistema.

Crear una unidad de servicio systemd

Tus propias unidades van en /etc/systemd/system/ y terminan en .service. Crea el archivo:

nano /etc/systemd/system/miservicio.service

Una plantilla sencilla y lista para usar tiene este aspecto:

[Unit]
Description=Mi propio servicio
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=miusuario
WorkingDirectory=/opt/miservicio
ExecStart=/bin/bash /opt/miservicio/start.sh
Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target

Qué significa cada línea

  • Description: el nombre en texto claro que muestra systemctl status.
  • After y Wants: el servicio no arranca hasta que la red está disponible. Así te ahorras el truco del sleep que se conoce de cron.
  • Type=simple: el programa se queda ejecutándose en primer plano. Si tu script de inicio se envía a sí mismo a segundo plano, necesitas en su lugar Type=forking y una indicación PIDFile.
  • User: el usuario con el que se ejecuta el servicio. Nunca dejes que una aplicación se ejecute como root sin necesidad.
  • WorkingDirectory: sustituye al cd de un script de inicio.
  • Restart=on-failure: systemd reinicia el servicio después de una caída. Con Restart=always lo hace también cuando el programa termina de forma normal.
  • WantedBy=multi-user.target: hace que el servicio arranque junto con el sistema en un inicio normal.

Activar y probar el servicio

Después de cada cambio en un archivo de unidad, systemd tiene que volver a leerlo. A continuación activas el servicio para el arranque del sistema y lo inicias directamente:

systemctl daemon-reload
systemctl enable --now miservicio.service

Para ver si todo funciona:

systemctl status miservicio.service

Las salidas de la aplicación acaban en el journal. Con el siguiente comando las lees en directo, que es la vía más rápida cuando buscas un error:

journalctl -u miservicio.service -f

Para detenerlo, reiniciarlo o desactivarlo de forma permanente:

systemctl stop miservicio.service
systemctl restart miservicio.service
systemctl disable miservicio.service

Ejemplo: iniciar automáticamente un servidor TeamSpeak 3

El script de inicio que incluye TeamSpeak se envía a sí mismo a segundo plano y crea un archivo PID. Por eso aquí lo correcto es Type=forking:

[Unit]
Description=TeamSpeak 3 Server
After=network-online.target
Wants=network-online.target

[Service]
Type=forking
User=teamspeak
WorkingDirectory=/home/teamspeak
ExecStart=/home/teamspeak/ts3server_startscript.sh start
ExecStop=/home/teamspeak/ts3server_startscript.sh stop
PIDFile=/home/teamspeak/ts3server.pid
Restart=on-failure
RestartSec=15

[Install]
WantedBy=multi-user.target

Adapta el nombre de usuario y el directorio a tu instalación. Es importante que el usuario indicado sea realmente el propietario del directorio.

Ejemplo: servidor de juego o bot con un script de inicio

Para Minecraft, ARK, Arma 3, servidores LinuxGSM o un bot escrito por ti, normalmente basta con la variante sencilla. El servicio se ejecuta en primer plano y systemd se encarga de la supervisión y del reinicio:

[Unit]
Description=Servidor de juego
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=gameserver
WorkingDirectory=/home/gameserver/server
ExecStart=/bin/bash /home/gameserver/server/start.sh
Restart=always
RestartSec=15

[Install]
WantedBy=multi-user.target

Si varios servicios arrancan a la vez y se frenan entre sí, reparte el arranque con valores distintos en RestartSec o amplía After= con el nombre de la unidad que debe ejecutarse primero.

Alternativa: inicio automático con cron y @reboot

Si solo quieres ejecutar un único comando durante el arranque y no necesitas supervisión, basta con una entrada de cron. Configura primero el editor y abre la crontab:

export VISUAL=nano; crontab -e

Añade ahí una línea con @reboot:

@reboot sleep 60 && cd /<DIRECTORIO-DEL-SCRIPT>/ && bash <TU-SCRIPT>.sh

El @reboot hace que el comando se ejecute una vez en cada arranque del sistema. La parte sleep 60 espera 60 segundos para que la red y la base de datos estén listas antes. Después el comando cambia al directorio de tu script y lo inicia.

Un ejemplo para un servidor de voz que debe ejecutarse con un usuario propio:

@reboot sleep 45 && cd /home/<DIRECTORIO-TEAMSPEAK>/ && sudo -u <USUARIO-TEAMSPEAK> bash ts3server_startscript.sh start

Si añades varias líneas, dale a cada una un valor de sleep distinto (como mínimo 45) para que no arranquen todos los servicios al mismo tiempo. El valor se indica en segundos.

Errores frecuentes

  • El servicio no arranca aunque a mano funciona: casi siempre falta una ruta absoluta. Dentro de una unidad o en cron, la variable de entorno PATH está definida de forma muy escueta, así que escribe siempre /bin/bash /ruta/completa/script.sh.
  • "Unit not found" después de crearla: se te ha olvidado systemctl daemon-reload.
  • El servicio se detiene de inmediato: el programa se ramifica hacia segundo plano. Usa Type=forking con la PIDFile adecuada, o inicia el programa en modo primer plano.
  • Error de permisos al arrancar: el usuario indicado en User= no puede acceder al directorio. Comprueba el propietario con ls -la.
  • Después del arranque no se ejecuta nada: el servicio se inició, pero no se activó. systemctl enable es el paso que lo registra de forma permanente.

Para terminar, la mejor prueba de todas: reinicia el servidor una vez con reboot y comprueba después con systemctl status si todos los servicios se ejecutan como esperabas.

Preguntas frecuentes

¿Qué es mejor: systemd o cron con @reboot?
Para todo lo que deba ejecutarse de forma permanente, systemd es claramente superior. Reinicia la aplicación tras una caída, muestra el estado y registra las salidas. Una entrada de cron solo lanza el comando una vez durante el arranque.
¿Dónde guardo mi propia unidad systemd?
Los archivos de unidad propios van en /etc/systemd/system/ y terminan en .service. Después de cada cambio tienes que ejecutar systemctl daemon-reload, si no systemd no reconoce el archivo.
Mi servicio funciona a mano, pero no arranca al iniciar el sistema. ¿Por qué?
Casi siempre falta una ruta absoluta, porque la variable de entorno PATH está definida de forma muy escueta durante el arranque del sistema. El segundo motivo más habitual: el servicio solo se inició, pero nunca se activó de forma permanente con systemctl enable.
¿Cómo veo las salidas de mi servicio?
systemd lo escribe todo en el journal. Con journalctl -u miservicio.service -f lees las salidas en directo, que es la vía más rápida cuando buscas un error.
¿Necesito todavía screen o tmux para un servidor de juego?
No. systemd mantiene el proceso en ejecución por sí mismo, registra la salida y lo reinicia automáticamente tras una caída. Para el funcionamiento continuo, screen y tmux dejan de hacer falta.

Inicio automático systemd Crontab Linux Servidor de juego TeamSpeak3 Arranque del servidor