Silent cron job failures are one of the most common causes of undetected issues in server infrastructure. Healthchecks.io is a cron job monitoring service that alerts you when scheduled tasks fail to run or take too long. This guide covers setting up comprehensive cron monitoring with both the hosted service and self-hosted option.
How Healthchecks.io Works
- Create a check with an expected schedule (e.g., every 5 minutes)
- Add a ping URL to your cron job script
- Healthchecks.io expects a ping at each interval
- If a ping is missed, you get alerted via email, Slack, PagerDuty, etc.
Self-Host Healthchecks.io
# Clone and deploy with Docker
cd /opt
git clone https://github.com/healthchecks/healthchecks.git
cd healthchecks
cat > docker-compose.yml /dev/null
# Report start and finish (measures duration)
*/5 * * * * curl -fsS --retry 3 https://hc.yourdomain.com/ping/UUID/start > /dev/null; /opt/scripts/backup.sh; curl -fsS --retry 3 https://hc.yourdomain.com/ping/UUID/$? > /dev/null
# Send output as body (for debugging failures)
0 3 * * * /opt/scripts/nightly-maintenance.sh 2>&1 | curl -fsS --retry 3 --data-binary @- https://hc.yourdomain.com/ping/UUID > /dev/null
Wrapper Script for All Cron Jobs
#!/bin/bash
# /usr/local/bin/cronwrap
# Usage: cronwrap
HC_URL="https://healthchecks.yourdomain.com/ping"
UUID="$1"
shift
CMD="$@"
# Signal start
curl -fsS --retry 3 "$HC_URL/$UUID/start" > /dev/null 2>&1
# Run the command, capture output and exit code
OUTPUT=$($CMD 2>&1)
EXIT_CODE=$?
# Send result with output
echo "$OUTPUT" | curl -fsS --retry 3 --data-binary @- "$HC_URL/$UUID/$EXIT_CODE" > /dev/null 2>&1
exit $EXIT_CODE
# Usage in crontab:
# */5 * * * * cronwrap abc-123-uuid /opt/scripts/check-disk.sh
# 0 2 * * * cronwrap def-456-uuid /opt/scripts/database-backup.sh
Monitor Different Job Types
# Database backup — daily at 2 AM, allow 30 min grace
0 2 * * * cronwrap DB-BACKUP-UUID pg_dump -U postgres mydb | gzip > /backup/db-$(date +\%Y\%m\%d).sql.gz
# Certificate renewal — twice daily, 24hr grace period
0 */12 * * * cronwrap CERT-UUID certbot renew --quiet
# Log rotation — weekly Sunday 4 AM
0 4 * * 0 cronwrap LOGROTATE-UUID logrotate /etc/logrotate.conf
# Application health check — every minute
* * * * * cronwrap HEALTH-UUID curl -f http://localhost:8080/health
# Systemd timer monitoring
# In your timer's ExecStart service:
[Service]
ExecStart=/bin/bash -c '/opt/scripts/task.sh && curl -fsS https://hc.yourdomain.com/ping/UUID'
Alert Integration
# Healthchecks.io supports many notification channels:
# - Email
# - Slack
# - PagerDuty
# - Telegram
# - Discord
# - Microsoft Teams
# - Webhooks (generic)
# - Pushover
# - OpsGenie
# Slack integration example (via webhook):
# In the Healthchecks.io web UI:
# 1. Go to Integrations
# 2. Add Slack
# 3. Enter your Slack webhook URL
# 4. Select which checks trigger notifications
# Custom webhook for your own alerting:
# POST to your endpoint with JSON:
# {
# "name": "Database Backup",
# "status": "down",
# "last_ping": "2026-03-15T02:00:00Z",
# "tags": "backup database production"
# }
Best Practices
- Set appropriate grace periods: Allow enough time for jobs to complete before alerting
- Use the /start signal for long-running jobs to detect jobs that start but never finish
- Send job output: Include stdout/stderr in the ping body for debugging failed jobs
- Tag checks by server, environment, and purpose for organized dashboards
- Use the wrapper script for consistent monitoring across all cron jobs
- Monitor the monitor: Set up a simple ping check on your Healthchecks instance itself