PTENES
MÓDULO 4.3

⚙️ Systemd: Servicios que nunca se detienen

Subiste tu aplicación al servidor, pero ¿qué pasa cuando el servidor se reinicia? ¿O cuando el programa se bloquea? systemd es el administrador que mantiene tus servicios en funcionamiento las 24 horas del día, los 7 días de la semana. Aquí aprenderás a convertir cualquier programa en un servicio que nunca se detiene.

6
Temas
45
Minutos
Básico
Nivel
Práctico
Tipo
1

Qué es systemd

El systemd es el gerente de guardia de tu servidor Linux. Es el primer programa que se inicia cuando arranca la máquina y se encarga de iniciar, supervisar y volver a iniciar todos los demás servicios. Sin él, tendrías que abrir la terminal e iniciar tu programa manualmente cada vez que se reiniciara el servidor. Con él, defines una vez cómo debe ejecutarse el servicio y systemd se encarga del resto, día y noche.

systemd (PID 1) gerente de guardia 24/7 meuapp.service active (running) api.service se bloqueó → restart nginx.service active (running)

🧠 Analogía: el gerente de guardia

Imagina un edificio comercial con un gerente que nunca duerme. Su función es sencilla: mantener las luces encendidas, los ascensores funcionando y la recepción abierta. Si un equipo se apaga, lo vuelve a encender de inmediato. Si se corta la energía y vuelve, lo abre todo automáticamente. Ese gerente es systemd, y los equipos son tus servicios.

  • •Inicia los servicios: cuando se inicia el servidor
  • •Monitorea los servicios: verifica si siguen en pie
  • •Vuelve a iniciar los servicios: si alguno se bloquea o se cae
  • •Anota todo: guarda los registros (logs) de lo que ocurrió

💡 Vocabulario: unit, service y PID 1

En el mundo de systemd, cada cosa que administra es una unit (unidad). El tipo de unit más común es el service (servicio), que es un programa que se ejecuta en segundo plano. systemd en sí es el PID 1: el proceso número 1, el padre de todos los demás procesos de la máquina. Cuando oigas "crear un service", entiende "enseñarle al gerente a cuidar tu programa".

2

Crear tu primer service file

Para que systemd se encargue de tu programa, necesitas escribir un archivo de servicio. Es un archivo de texto simple que termina en .service y queda en la carpeta /etc/systemd/system/. Ahí le explicas al administrador qué ejecutar, cómo hacerlo y cuándo.

Crea el archivo con nano

# Necesitas sudo: la carpeta es del sistema

$ sudo nano /etc/systemd/system/meuapp.service

El nombre antes de .service y es cómo vas a llamar al servicio después. Elige algo corto y sin espacios.

📝 Las tres secciones: Unit, Service e Install

Todo archivo de servicio tiene tres bloques. Cada uno responde una pregunta diferente:

[Unit]

Description=Mi aplicación Node

After=network.target

# ------------------------------

[Service]

ExecStart=/usr/bin/node /home/deploy/app/server.js

WorkingDirectory=/home/deploy/app

User=deploy

Restart=always

# ------------------------------

[Install]

WantedBy=multi-user.target

[Unit]

"¿Quién soy?" Descripción del servicio y de aquello de lo que depende para iniciarse.

[Service]

"¿Cómo ejecutarme?" El comando que inicia el programa, la carpeta, el usuario y la política de reinicio.

[Install]

"¿Cuándo iniciarme en el arranque?" En qué momento del inicio entra el servicio.

⚠️ Error común

Problema: "Puse solo node server.js no ExecStart y dio error."
Solución: El systemd no sabe dónde está el node. Usa siempre el ruta completa del ejecutable. Descúbrelo con which node (mostrará algo como /usr/bin/node) y usa esta ruta completa en ExecStart.

3

Controlar el servicio: start, stop, restart, enable

Después de escribir el archivo, te comunicas con systemd usando el comando systemctl. Piensa en él como el control remoto del administrador: inicia, detiene, reinicia y programa los servicios para el arranque.

Siempre que cambies el archivo: vuelve a cargar

Cada vez que creas o editas un .service, systemd necesita volver a leer los archivos:

$ sudo systemctl daemon-reload

# sin salida = todo salió bien

Iniciar, detener y reiniciar

# Iniciar el servicio ahora

$ sudo systemctl start meuapp

# Detener el servicio

$ sudo systemctl stop meuapp

# Reiniciar (detener y volver a iniciar)

$ sudo systemctl restart meuapp

# Ver el estado actual

$ sudo systemctl status meuapp

● meuapp.service - Mi aplicación Node

Loaded: loaded (/etc/systemd/system/meuapp.service)

Active: active (running) since Tue 2026-06-17 12:30:01

Main PID: 4821 (node)

Nota: no necesitas escribir el .service al final. systemd entiende meuapp por sí solo.

👁 enable: la diferencia que importa

O start inicia el servicio ahora, pero si el servidor se reinicia, no vuelve. El enable marca el servicio para iniciar automáticamente al arrancar. Casi siempre quieres ambos.

# Iniciar al arrancar (pero no ahora)

$ sudo systemctl enable meuapp

# Iniciar ahora Y al arrancar (lo más usado)

$ sudo systemctl enable --now meuapp

# Deshacer: ya no iniciar en el arranque

$ sudo systemctl disable meuapp

✓ Qué HACER

  • ✓Ejecutar daemon-reload después de editar el archivo
  • ✓Verificar con status si quedó activo
  • ✓Usar enable --now para producción

✗ Qué NO hacer

  • ✗Olvidar el enable y perder el servicio al reiniciar
  • ✗Confundir start (ahora) con enable (arranque)
  • ✗Editar el archivo sin recargar el daemon
4

Leyendo los logs con journalctl

Cuando falla un servicio, la primera pregunta es: "¿qué dijo antes de caerse?". systemd guarda todo lo que cada servicio imprime en pantalla en un diario central. Lees ese diario con el comando journalctl. Es tu detective de problemas.

🧠 Analogía: el diario de navegación

Piensa en journalctl como la bitácora de un barco. Todo lo que sucede queda anotado con fecha y hora: cuándo se inició el servicio, cuándo se reinició, qué error apareció. Cuando algo sale mal, abres la bitácora en la página correcta y descubres qué pasó, sin adivinar.

Los filtros esenciales: -u, -f y --since

# -u = filtra por un servicio (unit)

$ journalctl -u meuapp

jun 17 12:30:01 srv node[4821]: Servidor en el puerto 3000

jun 17 12:34:18 srv node[4821]: GET /api/users 200

# -f = sigue en vivo (follow), como ver

$ journalctl -u meuapp -f

(aparecen nuevas líneas en tiempo real... Ctrl+C para salir)

# --since = desde cuándo

$ journalctl -u meuapp --since "hoy"

$ journalctl -u meuapp --since "10 min ago"

# Combinando: solo errores de las últimas 30 líneas

$ journalctl -u meuapp -n 30 --no-pager

💡 Consejo: el trío que resuelve el 90% de los casos

Cuando tu servicio no se inicia, ejecuta systemctl status meuapp para ver el resumen, después journalctl -u meuapp -n 50 para leer las últimas líneas de error. Si quieres ver lo que ocurre en el momento, deja journalctl -u meuapp -f abierto y reinicia el servicio en otra pestaña.

⚠️ Error común

Problema: "journalctl abre una pantalla extraña y no puedo salir."
Solución: De forma predeterminada, se abre en el paginador. Usa las flechas para desplazarte, q para salir, o agrega --no-pager para mostrar todo directamente en pantalla. Para ir al final del registro, presiona Shift+G.

5

Dependencias: After y Requires

Los servicios rara vez funcionan solos. Es posible que tu aplicación necesite el base de datos iniciada antes de subir, o de la red lista. systemd te permite declarar ese orden con dos claves: After (orden) y Requires (obligatoriedad).

1

network.target sube

La red queda lista. Casi todos los servicios de internet esperan esto primero.

2

postgresql.service se inicia

La base de datos se inicia. Tu aplicación la necesita en funcionamiento para conectarse.

3

meuapp.service se inicia al final

Solo ahora, con la red y la base de datos listas, tu aplicación se inicia sin errores de conexión.

Declarar el orden en el archivo service

[Unit]

Description=Mi aplicación

# Se inicia DESPUÉS de la red y de la base de datos

After=network.target postgresql.service

# La base de datos es OBLIGATORIA: si se cae, yo caigo con ella

Requires=postgresql.service

After=

Define solo el orden: "iníciame después de este". No obliga a que el otro exista. Si el servicio mencionado no se inicia, el tuyo se inicia de todos modos.

Úsalo para: asegurarte de que la red esté lista antes.

Requires=

Crea dependencia fuerte: "no funciono sin él". Si falla el servicio requerido, el tuyo también se detiene. Suele venir junto con After.

Úsalo para: la base de datos sin la cual la app no funciona.

💡 Consejo: After y Requires son independientes

Requires garantiza que el otro servicio se inicie junto, pero no garantiza el orden. Para establecer el orden Y que sea obligatorio, declara ambos: Requires=db.service más After=db.service. Este par es la forma correcta de decir "necesito la base de datos y se conecta después de ella".

6

Reinicio automático: el superpoder de Systemd

Aquí está el motivo para usar systemd: reinicia tu servicio por sí solo cuando se cae. ¿Se bloqueó por un error? ¿Se quedó sin memoria? El administrador lo detecta y vuelve a iniciar todo en segundos, sin que tengas que levantarte de madrugada. Esto se configura con dos claves: Restart e RestartSec.

En el bloque [Service]

[Service]

ExecStart=/usr/bin/node /home/deploy/app/server.js

# Siempre vuelve a iniciarse, sin importar el motivo

Restart=always

# Espera 5 segundos antes de volver a intentarlo

RestartSec=5

Los valores de Restart más usados

always Vuelve a iniciarlo siempre, incluso si el programa terminó sin errores. Es lo más común en aplicaciones web.
on-failure Vuelve a iniciarlo solo cuando el programa termina con un error (código distinto de cero).
no Nunca se reinicia (es el valor predeterminado si no defines nada). Evítalo en producción.

👁 Qué vas a ver en el estado después de un crash

● meuapp.service - Mi aplicación Node

Active: active (running) since Tue 12:40:09

Main PID: 5102 (node)

# En journalctl, systemd registra el reinicio:

12:40:04 systemd: meuapp.service: Main process exited, code=killed

12:40:09 systemd: meuapp.service: Scheduled restart, attempt 1

12:40:09 systemd: Inició mi aplicación Node.

⚠️ Error común

Problema: "Mi app tiene un bug que hace que se cierre de inmediato, y systemd la sigue reiniciando en un bucle sin parar."
Solución: Sin RestartSec, intenta reiniciarse al instante y systemd lo bloquea por exceso de intentos (start-limit). Coloca RestartSec=5 para dejar un respiro entre los intentos y corrige el error revisando el journalctl. Reiniciar no sustituye corregir el error.

✓ Qué HACER

  • ✓Usar Restart=always en aplicaciones web
  • ✓Definir RestartSec=5 para evitar un bucle
  • ✓Revisar el log para entender por qué se cayó

✗ Qué NO hacer

  • ✗Dejar Restart=no en producción
  • ✗Usar restart para ocultar errores sin corregirlos
  • ✗Olvidar daemon-reload después de cambiar las claves

📚 Resumen del módulo

✓
Systemd es el encargado de turno - mantiene tus servicios en funcionamiento 24/7
✓
El archivo service tiene [Unit], [Service] y [Install] - vive en /etc/systemd/system/
✓
systemctl start/stop/restart/enable - enable hace que se inicie al arrancar
✓
journalctl -u, -f, --since - lee los logs para descubrir qué pasó
✓
After/Requires e Restart=always - orden entre servicios y reinicio automático

Siguiente módulo:

4.4 - Cron Jobs: tareas programadas (ejecutar comandos automáticamente en horarios definidos)