Un servidor se gana el sueldo haciendo cosas mientras duermes: copias de seguridad, rotación de registros, renovación de certificados, un informe a las nueve. Linux tiene dos planificadores para eso. Cron tiene cuarenta años y ocupa una línea. Los temporizadores de systemd ocupan dos archivos pequeños y a cambio te dan registros, recuperación tras una caída y hora exacta. Esta guía cubre ambos en Ubuntu 24.04, con cada comportamiento comprobado en un servidor nuevo de nuestra imagen, incluidos los tres errores que hacen que una tarea de cron falle sin decir nada.
Necesitas un usuario con sudo; la guía de configuración de Ubuntu crea uno.
1. Cron en cinco minutos
Cron está instalado y en marcha en nuestras imágenes de Ubuntu y Debian. Cada usuario tiene una tabla de tareas; edita la tuya con:
crontab -e
Cada línea tiene cinco campos de tiempo y un comando:
# min hour day month weekday command
30 3 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
*/5 * * * * /usr/local/bin/check.sh
0 9 * * 1-5 /usr/local/bin/report.sh
@reboot /usr/local/bin/start-tunnel.sh
Es decir: a las 03:30 cada noche, cada 5 minutos, a las 09:00 entre semana y una vez después de cada arranque. */5 significa uno de cada cinco valores, 1-5 un rango, 1,15 una lista. Se aplica la zona horaria del servidor, UTC en nuestras imágenes; configura la tuya una vez con la guía de nombre de host y zona horaria y cron la sigue.
Comprueba lo que se ejecutó con journalctl -u cron. Cada ejecución registra el usuario y el comando, y ahí aparecen las tres trampas.
Trampa 1: la salida desaparece. Cron envía por correo la salida de una tarea al usuario. Nuestra imagen no tiene servidor de correo, así que el journal decía (CRON) info (No MTA installed, discarding output) y la salida se perdía. Redirígela tú, como hace el primer ejemplo con >> /var/log/backup.log 2>&1.
Trampa 2: el signo de porcentaje. En un crontab, % termina el comando y convierte el resto en entrada estándar. Programamos date +%F > /tmp/today. El journal muestra lo que cron ejecutó de verdad: CMD (date +). No se escribió ningún archivo ni nos llegó ningún error. Escribe \%, o pon el comando en un script y programa el script.
Trampa 3: un entorno distinto. Cron ejecuta las tareas con /bin/sh, no con bash, en tu directorio personal y con un entorno reducido. En Ubuntu 24.04 el PATH resultó mejor que su fama: la ruta completa del sistema, incluidos /usr/local/bin y /snap/bin, para root y para un usuario normal. Lo que sigue faltando es todo lo de tu directorio personal: ~/.local/bin, el node de nvm, pipx, cargo. Usa rutas completas en la tarea o empieza la línea con . $HOME/.profile;.
Las tareas que pertenecen al sistema y no a un usuario van en /etc/cron.d/, como archivo con un campo extra, el usuario:
30 3 * * * root /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
Ubuntu también ejecuta todo lo que haya en /etc/cron.hourly, cron.daily, cron.weekly y cron.monthly, a los 17 minutos de cada hora, a las 06:25, a las 06:47 los domingos y a las 06:52 el día 1. Deja ahí un script ejecutable y correrá con los demás.
2. Temporizadores de systemd
Un temporizador son dos unidades: un servicio que hace el trabajo y un temporizador que dice cuándo. Crea primero el script y luego las unidades.
sudo nano /usr/local/bin/backup.sh
sudo chmod +x /usr/local/bin/backup.sh
sudo nano /etc/systemd/system/backup.service
[Unit]
Description=Nightly backup
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
sudo nano /etc/systemd/system/backup.timer
[Unit]
Description=Run the backup every night at 03:30
[Timer]
OnCalendar=*-*-* 03:30
Persistent=true
AccuracySec=1m
[Install]
WantedBy=timers.target
Activa el temporizador, no el servicio:
sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer
systemctl list-timers backup.timer
list-timers muestra la próxima ejecución, cuánto falta y la última ejecución. Los registros no necesitan configuración: journalctl -u backup.service tiene cada inicio, cada final y cada línea de salida, con marcas de tiempo. Para ejecutar la tarea ahora mismo, sudo systemctl start backup.service; así también pruebas el script antes de fiarte del horario.
Sintaxis del calendario. OnCalendar se lee díasemana año-mes-día hora:minuto:segundo, con * para cualquiera. Prueba una expresión antes de usarla:
systemd-analyze calendar "Mon..Fri *-*-* 03:00" --iterations 2
Imprime la forma normalizada y las próximas fechas. Algunas expresiones que comprobamos:
| OnCalendar | Significado |
|---|---|
*-*-* 03:30 | Cada día a las 03:30 |
Mon..Fri *-*-* 09:00 | Entre semana a las 09:00 |
*:0/15 | Cada 15 minutos |
weekly | Los lunes a las 00:00 |
*-*-01 04:00 | El día 1 de cada mes a las 04:00 |
*-*-* 03:00 Europe/Kyiv | 03:00 hora de Kyiv; se ejecutó a las 01:00 UTC en nuestra prueba |
Los tres ajustes que conviene conocer. Persistent=true guarda la última ejecución en disco y recupera una ejecución perdida mientras el servidor estaba apagado o el temporizador detenido. Detuvimos nuestro temporizador de cada dos minutos, esperamos a que pasara una ejecución programada y lo volvimos a iniciar: la ejecución perdida saltó en el mismo segundo. Sin Persistent, simplemente espera al siguiente hueco.
AccuracySec es la sorpresa. Por defecto systemd agrupa los temporizadores en una ventana de un minuto para ahorrar despertares, así que nuestra primera ejecución llegó a las 07:42:18, no a las 07:42:00. Con AccuracySec=1s las siguientes cayeron a las 07:46:00 y 07:48:00 al segundo. Ajústalo cuando importe el minuto; deja el valor por defecto para una copia nocturna.
RandomizedDelaySec=10m hace lo contrario a propósito: reparte el inicio en una ventana para que diez servidores no golpeen el mismo almacenamiento de copias en el mismo segundo.
Para una tarea puntual, ningún archivo:
sudo systemd-run --on-active=30m --unit=cleanup-once /usr/local/bin/cleanup.sh
Crea un temporizador transitorio que se dispara una vez y desaparece; hasta entonces lo muestra systemctl list-timers.
3. Cuál usar
| Cron | Temporizador systemd | |
|---|---|---|
| Configuración | 1 línea | 2 archivos |
| Registros | Solo si rediriges la salida | journalctl -u name.service |
| Ejecución perdida con el servidor apagado | Perdida | Se ejecuta al arrancar con Persistent=true |
| Tarea aún en marcha en el siguiente tic | Arranca una segunda copia | Se omite hasta que termina la primera |
| Hora exacta | Al minuto | Al segundo con AccuracySec=1s |
| Estado | Ninguno | list-timers, systemctl status |
Usa cron para una línea rápida que reconocerás dentro de un año. Usa un temporizador para todo aquello cuyo fallo necesitas ver, que no debe solaparse o que debe ejecutarse tras un reinicio que se perdió: copias de seguridad, renovación de certificados, limpieza de bases de datos. Si una tarea de cron puede solaparse, envuélvela: flock -n /tmp/backup.lock /usr/local/bin/backup.sh, y la segunda copia termina al instante.
Ambos planificadores ejecutan una tarea y se detienen. Para un programa que debe funcionar sin parar y volver tras un fallo, necesitas un servicio, no un horario; consulta cómo crear un servicio de systemd y, para Windows, cómo ejecutar un script 24/7 en Windows Server. Un buen primer temporizador es el de nuestra guía de copias con restic; las actualizaciones de seguridad automáticas son un temporizador que Ubuntu ya trae, apt-daily-upgrade.timer, uno de los 17 que funcionan en un servidor nuevo.
Comentarios
Aún no hay comentarios. Sé el primero.