--- title: "Cómo monitorizar tareas cron con Healthchecks self-hosted" description: "Despliega Healthchecks con Docker y PostgreSQL en Ubuntu 24.04, crea checks con horario cron y recibe alertas cuando una tarea programada falla o no se ejecuta." category: "Herramientas de Servidor" language: es source: https://cubepath.com/es/docs/herramientas-de-servidor/healthchecks-monitorizacion-de-cron-self-hosted updated: 2026-09-25 --- # Cómo monitorizar tareas cron con Healthchecks self-hosted Healthchecks es una herramienta de monitorización de tareas programadas que funciona como un interruptor de hombre muerto: cada tarea hace una petición HTTP (un ping) a una URL única cuando se ejecuta, y si el ping no llega a tiempo o llega marcando un error, Healthchecks envía una alerta. Así detectas tanto las copias de seguridad que fallan como las que dejan de ejecutarse sin avisar. En este tutorial desplegarás Healthchecks con Docker Compose y PostgreSQL en Ubuntu 24.04, lo publicarás con Nginx y HTTPS, y conectarás tareas de cron y timers de systemd mediante un pequeño script envoltorio. ## Requisitos previos Para seguir esta guía necesitas: - Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath, con al menos 1 GB de RAM y un usuario no root con privilegios `sudo`. - Docker Engine y el plugin Docker Compose instalados. - Nginx instalado y los puertos 80 y 443 abiertos. Si usas UFW: `sudo ufw allow 'Nginx Full'`. - Un subdominio (en esta guía, `hc.your_domain`) con un registro DNS A que apunte a la IP del servidor. - Una cuenta SMTP para enviar las alertas por correo (servidor, puerto, usuario y contraseña). ## Paso 1: Preparar la configuración Crea el directorio del proyecto: ```bash sudo mkdir -p /opt/healthchecks sudo chown "$USER": /opt/healthchecks cd /opt/healthchecks ``` Healthchecks se configura con variables de entorno. Genera el archivo `.env` con una clave secreta y una contraseña de base de datos aleatorias. El heredoc sin comillas hace que la shell sustituya las llamadas a `openssl` por su resultado: ```bash cat > .env <`. Haz un ping manual para comprobar que funciona (sustituye `your_check_uuid`): ```bash curl -fsS -m 10 https://hc.your_domain/ping/your_check_uuid ``` ```output OK ``` El check pasa a verde (`up`) en el panel y el ping aparece en su historial. Si prefieres crear los checks por código, genera una clave de API de lectura y escritura en **Settings** del proyecto, en la sección **API Access**. Este ejemplo crea el mismo check y, gracias a `unique`, no lo duplica si ejecutas la petición dos veces (sustituye `your_api_key`): ```bash curl -s -X POST https://hc.your_domain/api/v3/checks/ \ -H "X-Api-Key: your_api_key" \ -H "Content-Type: application/json" \ -d '{ "name": "backup-postgresql", "tags": "backup prod", "schedule": "0 3 * * *", "tz": "Europe/Madrid", "grace": 1800, "channels": "*", "unique": ["name"] }' ``` La respuesta es el check en JSON, y el campo `ping_url` contiene la URL de ping. ## Paso 5: Conectar las tareas con un script envoltorio Healthchecks entiende varias variantes de la URL de ping: | URL | Significado | |-----|-------------| | `/ping//start` | La tarea ha empezado. Permite medir su duración. | | `/ping/` o `/ping//0` | La tarea ha terminado bien. | | `/ping//fail` o `/ping//` con código de 1 a 255 | La tarea ha fallado. Alerta inmediata. | En lugar de repetir la lógica en cada línea de cron, crea un script que envíe el ping de inicio, ejecute el comando, adjunte las últimas líneas de su salida y envíe el código de salida real: ```bash sudo nano /usr/local/bin/hc-run ``` ```bash #!/usr/bin/env bash set -uo pipefail if [[ $# -lt 2 ]]; then echo "Uso: hc-run PING_URL COMANDO [ARGUMENTOS...]" >&2 exit 64 fi url="$1" shift curl -fsS -m 10 --retry 5 -o /dev/null "${url}/start" || true output="$("$@" 2>&1)" status=$? printf '%s\n' "$output" printf '%s\n' "$output" | tail -c 10000 \ | curl -fsS -m 10 --retry 5 -o /dev/null --data-binary @- "${url}/${status}" || true exit "$status" ``` ```bash sudo chmod 755 /usr/local/bin/hc-run ``` El script no usa `set -e` a propósito: debe seguir ejecutándose cuando el comando falla para poder informar del fallo. Los errores de `curl` se ignoran (`|| true`) para que una caída de Healthchecks no rompa tus tareas; si el ping no llega, Healthchecks alertará igualmente por falta de ping. Pruébalo con un comando que falla, usando la URL del check: ```bash hc-run https://hc.your_domain/ping/your_check_uuid false echo "Código de salida: $?" ``` ```output Código de salida: 1 ``` En el panel, el check pasa a rojo (`down`) y recibes una alerta por los canales configurados. Ejecuta después `hc-run https://hc.your_domain/ping/your_check_uuid true` para devolverlo a verde. ### Con cron Añade la tarea en un archivo de `/etc/cron.d`: ```bash sudo nano /etc/cron.d/backup-postgresql ``` ```text 0 3 * * * root /usr/local/bin/hc-run https://hc.your_domain/ping/your_check_uuid /usr/local/bin/backup-postgresql.sh ``` Sustituye `/usr/local/bin/backup-postgresql.sh` por tu script real. El horario de cron y el del check deben coincidir. ### Con un timer de systemd Crea la unidad de servicio: ```bash sudo nano /etc/systemd/system/backup-postgresql.service ``` ```ini [Unit] Description=Copia de seguridad de PostgreSQL Wants=network-online.target After=network-online.target [Service] Type=oneshot ExecStart=/usr/local/bin/hc-run https://hc.your_domain/ping/your_check_uuid /usr/local/bin/backup-postgresql.sh ``` Crea el timer que la lanza cada día a las 03:00: ```bash sudo nano /etc/systemd/system/backup-postgresql.timer ``` ```ini [Unit] Description=Copia de seguridad diaria de PostgreSQL [Timer] OnCalendar=*-*-* 03:00:00 Persistent=true [Install] WantedBy=timers.target ``` Activa el timer y lanza el servicio una vez a mano para comprobarlo: ```bash sudo systemctl daemon-reload sudo systemctl enable --now backup-postgresql.timer sudo systemctl start backup-postgresql.service systemctl list-timers backup-postgresql.timer ``` El ping aparece en el historial del check con la duración de la ejecución y la salida del script. ## Paso 6: Configurar los canales de alerta Comprueba primero que el envío de correo funciona: ```bash docker compose exec web /opt/healthchecks/manage.py sendtestemail your_email@your_domain ``` Si el correo llega, ve a **Integrations** en el proyecto. El correo de tu cuenta suele aparecer ya como integración; si no, añádelo con **Email** y confirma la dirección desde el mensaje que recibirás. Healthchecks incluye integraciones nativas con servicios como ntfy, Slack, Telegram o webhooks genéricos. Para ntfy, por ejemplo, elige **ntfy** en **Integrations**, indica la URL del servidor y el topic, y guarda. Cada integración tiene un botón para enviar una notificación de prueba. Revisa en la configuración de cada check qué integraciones tiene activadas: los checks creados con `"channels": "*"` usan todas las del proyecto. ## Solución de problemas **Error CSRF al iniciar sesión.** `SITE_ROOT` no coincide con la URL con la que accedes (por ejemplo, falta `https://` o el subdominio es distinto). Corrígelo en `.env` y recrea el contenedor con `docker compose up -d --force-recreate web`. **Los checks aparecen en verde aunque la tarea falle.** El comando no devuelve un código de salida distinto de cero al fallar, o la línea de cron envía el ping con `;` sin tener en cuenta el resultado. Usa `hc-run`, que envía el código real, y comprueba el código de tu script con `tu_script; echo $?`. **No llegan las alertas.** Revisa los logs del contenedor con `docker compose logs web --tail=50` y vuelve a probar el correo con `sendtestemail`. Si usas el puerto 587, `EMAIL_USE_TLS` debe ser `True`. ## Conclusión Tienes Healthchecks funcionando con PostgreSQL detrás de Nginx con HTTPS, checks con horario cron y un script que informa del inicio, la duración, la salida y el código de salida de cada tarea. Como siguientes pasos, puedes crear un check por cada tarea crítica (copias de seguridad, renovaciones, sincronizaciones), añadir una segunda integración como ntfy para no depender solo del correo e incluir el volumen de PostgreSQL en tus copias de seguridad.