Ir al contenido

Systemd timers: la alternativa moderna a cron que necesitabas

Rogelio Guerra Riverón
Autor
Rogelio Guerra Riverón
Construyendo mi propia infraestructura web desde cero. Aquí documento cada paso: servidores, redes, contenedores y lo que vaya surgiendo.

Por qué dejé cron
#

Llevo años usando cron en mis servidores. Es simple, confiable y funciona. Pero hace poco descubrí systemd timers y no vuelvo atrás. La razón principal: logs integrados en journald, sin archivos .log dando vueltas por el sistema, y mejor control sobre qué pasa cuando el servidor arranca o reinicia.

En mi caso específico, tenía un backup que no se ejecutaba si el servidor estaba apagado a la hora programada. Con cron, simplemente se perdía. Con systemd timers y Persistent=true, la tarea se ejecuta en cuanto el servidor se enciende.

Estructura básica: .service + .timer
#

Systemd necesita dos archivos:

El servicio (/etc/systemd/system/mibackup.service):

[Unit]
Description=Backup diario de datos
After=network.target

[Service]
Type=oneshot
User=backup
ExecStart=/usr/local/bin/backup.sh
StandardOutput=journal
StandardError=journal

El timer (/etc/systemd/system/mibackup.timer):

[Unit]
Description=Ejecuta backup diariamente

[Timer]
OnCalendar=daily
OnCalendar=*-*-* 03:00:00
Persistent=true
Accuracy=1min

[Install]
WantedBy=timers.target

Luego:

sudo systemctl daemon-reload
sudo systemctl enable --now mibackup.timer

OnCalendar: la sintaxis que necesitas
#

OnCalendar es el cron de systemd, pero más legible:

  • daily → todos los días a medianoche
  • weekly → cada lunes a medianoche
  • hourly → cada hora
  • *-*-* 03:00:00 → todos los días a las 3 AM
  • Mon *-*-* 14:30:00 → cada lunes a las 14:30
  • *-01,04,07,10-01 00:00:00 → primero de cada trimestre

Puedes combinar múltiples líneas OnCalendar:

OnCalendar=*-*-* 03:00:00
OnCalendar=*-*-* 15:00:00

Esto ejecuta la tarea dos veces al día.

Persistent=true: el cambio que me convenció
#

Por defecto, si tu servidor está apagado cuando se programa una tarea, systemd simplemente la ignora. Con Persistent=true, systemd remembers y ejecuta la tarea la próxima vez que arranque.

En mi servidor doméstico, esto es crítico. No siempre está encendido, y necesito garantizar que mis backups se ejecuten aunque hayan pasado horas.

[Timer]
OnCalendar=daily
Persistent=true

Type=oneshot: para tareas que terminan
#

El parámetro Type=oneshot en el .service indica que el proceso terminará. Es lo normal para scripts de backup, sincronización, etc.

Si usas Type=simple (el default), systemd espera que el proceso se mantenga ejecutándose. No es lo que queremos aquí.

Ver logs sin archivos externos
#

Aquí está lo mejor: olvídate de >> /var/log/mibackup.log.

Los logs van directo a journald:

# Ver los últimos logs del timer
journalctl -u mibackup.service -n 50

# Ver en tiempo real
journalctl -u mibackup.service -f

# Los últimos 2 horas
journalctl -u mibackup.service --since "2 hours ago"

# Con niveles de prioridad
journalctl -u mibackup.service -p err

Dentro de tu script puedes loguear con echo o logger:

#!/bin/bash
logger "Iniciando backup..."
/backup/script.sh
logger "Backup completado"

Todo se captura automáticamente.

Checklist de lo que hicimos
#

  1. ✅ Creaste un .service con Type=oneshot
  2. ✅ Creaste un .timer con OnCalendar y Persistent=true
  3. ✅ Recargaste systemd y activaste el timer
  4. ✅ Verificas logs con journalctl, sin archivos de log extra

Consejo final
#

Antes de depender de un timer, pruébalo manualmente:

# Ejecutar el servicio ahora
sudo systemctl start mibackup.service

# Ver qué pasó
journalctl -u mibackup.service -n 20

Eso. Systemd timers no es la panacea, pero para tareas programadas en servidores modernos, es superior a cron en casi todos los aspectos. Los logs centralizados en journald, combinados con Persistent=true, hacen que sea imposible no recomendarlo.

En mi servidor doméstico, todos los backups, limpiezas de caché y sincronizaciones de datos usan timers. Cero archivos de log sueltos. Todo integrado.