|

5 razones por las que tu crontab falla en silencio

Los cron jobs en VPS fallan silenciosamente porque cron no envía notificaciones por defecto cuando un script termina sin producir salida, y los errores se pierden en un mailer local que nadie configuró. El resultado: tareas críticas que “corrieron” según el log pero no hicieron nada.

En 30 segundos

  • Hay al menos 4 lugares distintos donde puede vivir un cron job en Ubuntu, y mezclar la sintaxis entre ellos hace que el job no corra y no avise.
  • Cron no hereda las variables de entorno del shell, así que scripts que corren bien en terminal fallan en silencio cuando los ejecuta cron.
  • Los errores van a un mailer local que en el 95% de los servidores VPS modernos no está configurado, por eso nunca llegás a verlos.
  • Herramientas como Cronitor, Better Stack o Healthchecks.io resuelven el monitoreo que cron nunca tuvo de forma nativa.
  • En 2026 hay alternativas maduras: systemd timers, Kubernetes CronJobs y servicios gestionados que evitan todos estos problemas de raíz.

Por qué los cron jobs VPS fallas son tan difíciles de detectar

Cron es de 1975. No es una crítica, es un dato relevante: fue diseñado para un modelo operativo donde el administrador estaba presente, leía el correo del sistema y tenía control directo sobre el servidor. En 2026, el contexto cambió por completo y cron no lo sabe.

El problema central es este: cuando un cron job falla, cron intenta mandarte un email al usuario local del sistema. Si ese mailer local no está configurado (y en la enorme mayoría de los VPS modernos no lo está), el error desaparece. El job figura como “ejecutado” en el log del sistema. El output queda vacío. Vos no recibís nada.

Según el artículo técnico de referencia publicado en mayo de 2026, quien onboardeó más de 30 equipos que migraron de VPS-based cron en los últimos 14 meses, el patrón se repite: emails que no salieron, Discord callado, webhook que no disparó, y un log que dice que todo corrió a las 06:00. Lo que falla no es cron en sí, sino la capa operacional alrededor de cron cuando lo corrés en un Linux genérico que mantenés vos mismo.

Killer #1: Editaste el crontab equivocado

En un Ubuntu estándar hay al menos cuatro lugares donde puede vivir un cron job:

  • El crontab del usuario (editado con crontab -e): no requiere campo de usuario en la línea.
  • El crontab de root (/var/spool/cron/crontabs/root): tampoco requiere campo de usuario.
  • /etc/cron.d/: sí requiere campo de usuario. La sintaxis es diferente.
  • /etc/cron.daily/, /etc/cron.hourly/, /etc/cron.weekly/, /etc/cron.monthly/: son scripts ejecutables, no tienen línea cron con horario.

Copiás un snippet de un blog (como este), lo pegás en el lugar equivocado con la sintaxis incorrecta y cron lo ignora en silencio. Sin warning, sin error en syslog, sin nada. Verificá siempre con crontab -l para ver el crontab del usuario actual, y cat /etc/cron.d/tu-archivo para los de sistema.

Killers #2 y #3: Variables de entorno y rutas relativas

Ponele que tenés un script Python que usa una variable de entorno DATABASE_URL. Lo corrés en terminal, funciona perfecto. Lo ponés en cron y falla. ¿Por qué? Porque cron no hereda el PATH, ni HOME, ni ninguna variable custom que tenés configurada en .bashrc o .zshrc.

El entorno que ve cron es mínimo, algo así:

SHELL=/bin/sh
PATH=/usr/bin:/bin
LOGNAME=tu-usuario

Nada más. Entonces cuando tu script llama a python3, cron lo busca en /usr/bin y /bin. Si usás un virtualenv o tenés Python en /usr/local/bin, no lo encuentra. Solución: definí las variables que necesitás al principio del crontab o usá rutas absolutas en todo, incluyendo el intérprete.

MAL: */5 * * * * ./scripts/sync.sh

BIEN: */5 * * * * /home/usuario/scripts/sync.sh

Las rutas relativas son otro killer silencioso. Cron ejecuta desde el directorio home del usuario, no desde donde está el script. Si tu script hace open('config.json') asumiendo que está en el mismo directorio, va a fallar buscando ese archivo en el home. Te puede servir nuestra cobertura de alternativas modernas a cron jobs.

Killers #4 y #5: Permisos insuficientes y recursos agotados

El script tiene permisos de ejecución cuando lo corrés como root en tu sesión SSH. Pero el cron job corre como otro usuario y ese archivo no es ejecutable para él, o intenta escribir en un directorio donde no tiene permisos. Cron no te avisa. El job “corrió”.

Verificación rápida: ls -la /ruta/al/script y confirmar que el usuario que corre cron tiene permisos de lectura y ejecución. Para scripts que escriben archivos, revisá los permisos del directorio destino también.

Los recursos son más traicioneros. ¿Alguien verificó de forma independiente cuánta memoria consume tu script cuando lo corre cron vs cuando lo corrés vos? El disco lleno es el más común: el job arranca, intenta escribir un log, no puede porque no hay espacio, y termina sin hacer nada. df -h antes de debuggear dos horas.

Por qué nunca ves los errores: el mailer fantasma

Cron tiene un mecanismo de notificación: toma todo lo que el script imprime a stdout y stderr, y lo manda por email al usuario del sistema. Si configuraste la variable MAILTO en el crontab, va a esa dirección. Si no, va al usuario local.

El problema es que en un VPS típico en 2026, ese mailer local no está configurado. El email se “envía” y desaparece en el éter. Para capturar la salida y verla de verdad, tenés que redirigirla explícitamente en la línea del crontab:

*/5 * * * * /ruta/al/script.sh >> /var/log/mi-script.log 2>&1

El 2>&1 redirige stderr a stdout, y el >> lo agrega al archivo de log sin borrarlo. Sin eso, los errores van al mailer y no los ves jamás. Con eso, podés hacer tail -f /var/log/mi-script.log y ver exactamente qué pasa.

La variable MAILTO="" al principio del crontab desactiva el email completamente. Útil si el job produce mucha salida y no querés spam local, pero asegurate de tener otro mecanismo de logging antes de hacerlo. Esto se conecta con lo que analizamos en automatización inteligente de tareas.

Depuración práctica: el entorno vacío que revela todo

La técnica más efectiva para debuggear un cron job es simular el entorno mínimo que usa cron. Desde la terminal, como el usuario que corre el job:

env -i HOME=/home/usuario SHELL=/bin/bash PATH=/usr/bin:/bin /bin/bash -x /ruta/al/script.sh

El env -i borra todas las variables de entorno. El -x activa el modo verbose de bash: imprime cada comando antes de ejecutarlo, con el signo +. Si algo falla en este contexto, es exactamente lo que falla en cron.

Para revisar si cron al menos intentó correr el job, mirá el syslog: grep CRON /var/log/syslog | tail -20 o journalctl -u cron --since "1 hour ago" dependiendo del sistema. Ahí vas a ver entradas como CMD (/ruta/al/script.sh) cuando el job arranca. Si esa línea no aparece en el horario esperado, el problema está en el crontab mismo, no en el script.

Monitoreo moderno: las herramientas que llenan el hueco de cron

Cron no tiene estado. No sabe si el job tardó 3 segundos o 3 horas. No sabe si la ejecución de ayer tardó el doble que la de hoy. No tiene forma de alertarte si un job que siempre corrió a las 06:00 no corrió. Para eso existen las plataformas de monitoreo especializadas.

HerramientaModeloAlertasHistorialPlan gratuito
CronitorSaaSEmail, Slack, PagerDutySí, con anomaly detectionSí (5 monitors)
Better StackSaaSEmail, SMS, llamadaSí (10 monitors)
Healthchecks.ioSaaS / self-hostedEmail, Slack, webhookSí (20 checks)
UptimeRobotSaaSEmail, SMSLimitadoSí (50 monitors)
Sentry CronsSaaS (parte de Sentry)Integrado con erroresCon plan Sentry
cron jobs vps fallas diagrama explicativo

El patrón de funcionamiento es simple: al principio del job hacés un GET a una URL única que te da la plataforma. Al final del job, otro GET. Si el segundo GET no llega en el tiempo esperado, te mandan una alerta. Healthchecks.io llama a esto “dead man’s switch”.

Cronitor y Better Stack (según su comparativa de herramientas 2026) van un paso más: detectan anomalías en la duración de ejecución. Si tu backup siempre tarda 4 minutos y hoy tardó 40, te avisan aunque haya terminado con código 0.

Alternativas modernas: cuándo conviene dejar cron atrás

Cron zafa para tareas simples en un servidor que ya tenés. Pero hay casos donde tiene sentido migrar. Más contexto en scripts inteligentes sin cron.

Systemd timers: mejor logging sin cambiar el servidor

Si ya corrés systemd (casi todo Linux moderno), los timers son la alternativa más directa. Cada job tiene un archivo .service y un .timer. El logging va a journald automáticamente, podés ver el estado con systemctl status tu-timer.timer, y tenés manejo de dependencias nativo. La configuración es más verbosa que cron, pero el debugging es incomparablemente más fácil.

Kubernetes CronJobs: para arquitecturas cloud-native

Si ya tenés un cluster K8s, los CronJobs son la opción natural. Corren en pods, tenés logs centralizados, reintentos configurables y visibilidad desde el dashboard. El costo operacional es cero si ya tenés el cluster. Si no lo tenés, montarlo solo para reemplazar cron es exagerado.

Servicios de cron gestionado: para quien no quiere mantener infraestructura

Servicios como EasyCron o Cron-job.org ejecutan HTTP requests en horarios configurados. Tu script vive en tu servidor y expone un endpoint; el servicio externo lo llama. Ventaja: el monitoreo, los reintentos y los logs están incluidos. Desventaja: tu script tiene que estar accesible por HTTP y vos gestionás la autenticación. Para tareas internas que acceden a la base de datos directamente, no aplica.

Si corrés infraestructura en donweb.com, los planes VPS incluyen acceso root completo para configurar tanto cron como systemd timers, y el soporte puede ayudarte con la configuración inicial del entorno.

Errores comunes que se repiten

Testear el script como root y correr el cron job como usuario sin privilegios. Lo probaste, funcionó, lo pusiste en cron del usuario deploy, y falla porque ese script necesita escribir en /var/log/. Siempre testeá con el mismo usuario que va a correr el job: su -s /bin/bash usuario-cron -c "/ruta/al/script.sh".

Usar */5 * * * * pensando que son cada 5 minutos a partir de la hora, pero sin entender que corre en los minutos 0, 5, 10, 15… Si el job tarda más de 5 minutos y no tenés locking, arrancás una segunda instancia mientras la primera todavía corre. Para jobs largos, usá flock o verificá si ya hay un proceso corriendo antes de arrancar.

Redirigir stdout pero no stderr. >> /var/log/script.log solo captura la salida normal. Los errores siguen yendo al mailer. Siempre agregá 2>&1 al final para capturar ambos.

Preguntas Frecuentes

¿Por qué mis tareas cron no se ejecutan sin mostrar errores?

La razón más frecuente es que cron corre con un entorno de variables mínimo y sin el PATH que tenés configurado en tu sesión. Si el script llama a un binario que no está en /usr/bin o /bin, falla silenciosamente. Revisá que todas las rutas sean absolutas y que las variables de entorno necesarias estén definidas en el propio crontab o en el script. Cubrimos ese tema en detalle en automatización moderna de procesos.

¿Cómo revisar los logs y detectar fallas en cron jobs?

En sistemas con rsyslog: grep CRON /var/log/syslog. En sistemas con systemd: journalctl -u cron --since "today". Para ver la salida del script mismo, redirigila en el crontab con >> /ruta/al/log.log 2>&1. Sin esa redirección, los errores van a un mailer local que en la mayoría de los VPS no está configurado.

¿Cuál es la forma correcta de configurar un crontab en Linux?

Usá crontab -e para el crontab del usuario actual. Definí MAILTO="" al principio si no querés emails. Usá rutas absolutas para el script y para cualquier archivo que el script lea o escriba. Redirigí stdout y stderr a un archivo de log. Testeá primero con un cron que corre cada minuto (* * * * *) antes de poner el horario definitivo.

¿Cómo configurar alertas y monitoreo para cron jobs en un VPS?

La opción más simple es Healthchecks.io: creás un “check”, obtenés una URL única, y en el crontab hacés un curl a esa URL al final del script exitoso. Si el check no llega en el tiempo esperado, te manda un email. El plan gratuito incluye 20 checks. Para monitoreo más avanzado con detección de anomalías en duración, Cronitor tiene un plan gratuito para hasta 5 monitors.

¿Qué alternativas modernas existen a cron jobs en 2026?

Systemd timers son la alternativa más directa si ya usás Linux moderno: mejor logging, manejo de dependencias y visibilidad sin cambiar el servidor. Para arquitecturas cloud-native, Kubernetes CronJobs. Para orquestación compleja con dependencias entre jobs, Apache Airflow. Para quienes no quieren mantener infraestructura, servicios de cron HTTP gestionado como EasyCron. Cada opción tiene su contexto; cron sigue siendo válido para tareas simples en servidores existentes.

Conclusión

Cron lleva funcionando desde 1975 y va a seguir funcionando. El problema nunca fue cron, sino asumir que “si no hay error, todo está bien” es verdad en un sistema que fue diseñado para enviar notificaciones por un canal que nadie configuró.

Los cinco killers silenciosos (crontab equivocado, variables de entorno faltantes, rutas relativas, permisos insuficientes y recursos agotados) tienen soluciones concretas que podés implementar hoy. La redirección de stderr, el testeo con entorno vacío usando env -i, y un monitor básico como Healthchecks.io cambian completamente la experiencia de operar cron jobs en producción.

Si manejás más de tres o cuatro jobs críticos en un VPS, el tiempo que invertís en agregarles monitoreo lo recuperás en la primera vez que algo falla a las 3 de la mañana y el alert te llega en vez de enterarte el lunes cuando ya es tarde.

Fuentes

Te puede interesar...