systemd y journalctl: por qué un servicio no arranca
Un servicio falla y el reflejo es reiniciar a ciegas. Acá aprendés a leer el estado real con systemctl y a encontrar la causa en los logs con journalctl.
Antes de empezar necesitás
- Una terminal en Linux (con systemd) o WSL2 con systemd activado
- Saber moverte por el filesystem y leer permisos
Al terminar vas a poder
- Leer el estado de un servicio con systemctl status y entender cada campo
- Encontrar la causa de una falla en journalctl, no adivinarla
- Distinguir 'no arrancó' de 'arrancó y se murió' de 'está deshabilitado'
- Filtrar logs por unidad, por tiempo y por prioridad
Un servicio no levanta y el reflejo es restart una y otra vez, como quien golpea la tele. systemd ya te está diciendo qué pasó: el problema es que casi nadie lee la respuesta completa. Este lab es sobre leerla.
Paso 1: leer el estado, no inventarlo
systemctl status no es solo un “verde o rojo”. Cada línea importa:
systemctl status nginx --no-pager ● nginx.service - A high performance web server
Loaded: loaded (/lib/systemd/system/nginx.service; enabled; preset: enabled)
Active: failed (Result: exit-code) since Tue 2026-06-24 18:02:11; 5s ago
Process: 5821 ExecStartPre=/usr/sbin/nginx -t (code=exited, status=1/FAILURE)
- Loaded: si la unit existe y si está
enabled(arranca sola al bootear) odisabled. - Active: el estado real.
active (running),failed,inactive (dead),activating. - Process / ExecStartPre: qué comando corrió y con qué código salió.
status=1/FAILUREes la pista grande.
Paso 2: la causa está en el journal
status te muestra las últimas líneas. Para la historia completa de esa unit:
# Logs de un servicio, solo del boot actual (-b), sin paginador
journalctl -u nginx -b --no-pager
# Las últimas 50 líneas y seguir en vivo mientras reintentás
journalctl -u nginx -n 50 -f La clave es -u <unit>: filtra el ruido de todo el sistema y te deja solo lo del servicio. Ahí suele estar la línea real, del tipo bind() to 0.0.0.0:80 failed (98: Address already in use) o permission denied.
Paso 3: un caso clásico para reproducir
Creá un servicio de juguete que apunte a un binario que no existe y mirá cómo systemd lo reporta:
# Unit mínima que va a fallar a propósito
sudo tee /etc/systemd/system/roto.service >/dev/null <<'EOF'
[Service]
ExecStart=/usr/local/bin/no-existe-este-binario
EOF
sudo systemctl daemon-reload
sudo systemctl start roto.service # no va a levantar
systemctl status roto.service --no-pager
journalctl -u roto.service -b --no-pager Vas a ver algo como status=203/EXEC: systemd no pudo ejecutar el binario. El código te dice la familia del problema sin que adivines.
203/EXEC no pudo ejecutar el binario (no existe, sin permiso, mal path)
200/CHDIR el WorkingDirectory no existe
1/FAILURE el programa arrancó y salió con error (mirá su log)
El criterio
Debuggear un servicio es un flujo corto y repetible:
1. systemctl status <unit> → ¿failed, inactive o disabled? ¿qué exit code?
2. journalctl -u <unit> -b → ¿qué línea explica el fallo?
3. arreglo el origen (path, permiso, puerto, config)
4. systemctl restart <unit> → y verifico con status, no por fe
Lo que practicás en este lab
Llevátelo a tu repo si querés, pero no es obligatorio: es tu aprendizaje.
- La salida de systemctl status del servicio fallando, con la línea que explica por qué
- El comando de journalctl que usaste para aislar el error
- Writeup de 2 líneas: cuál era la causa y cómo la confirmaste en los logs
Reto
Tomá un servicio que falle (o creá uno de juguete que apunte a un binario inexistente). Usá systemctl + journalctl para encontrar la causa exacta. Escribí dos líneas: qué decía el log y qué cambiarías para arreglarlo.
Resolvelo y escribí dos líneas explicando qué pasó. Con eso lo fijás.