Healthchecks.io on a VPS: Monitor Cron Jobs and Scheduled Tasks with Dead Man’s Switch Alerts
Healthchecks.io is a cron job monitoring service — your scheduled tasks (backups, ETL jobs, reports) ping a unique URL after completing successfully, and Healthchecks.io alerts you when a ping doesn’t arrive on schedule. It’s a “dead man’s switch” for your automation: silence means something failed. Self-hosting gives you unlimited checks, custom domains, private infrastructure, and complete control over alert channels.
Why Monitor Cron Jobs
<code"># Cron jobs fail silently by default: # - The backup ran but mysqldump failed (disk full) # - The ETL job started but network timed out midway # - The scheduled email was skipped (SMTP error) # - Cron itself failed after OS update changed PATH # Without monitoring: you discover the backup failed # when you need to restore from it — 3 months later. # With Healthchecks: alert within 15 minutes of any missed execution.
Step 1: Docker Compose Setup
<code">mkdir -p /opt/healthchecks && cd /opt/healthchecks nano docker-compose.yml
<code">version: '3.8'
services:
healthchecks:
image: healthchecks/healthchecks:latest
container_name: healthchecks
restart: always
ports:
- "127.0.0.1:8000:8000"
environment:
SITE_NAME: "YourCompany Health Monitor"
SITE_ROOT: "https://health.yourdomain.com"
SECRET_KEY: ${SECRET_KEY}
ALLOWED_HOSTS: "health.yourdomain.com"
DEFAULT_FROM_EMAIL: "[email protected]"
EMAIL_HOST: "smtp.mailgun.org"
EMAIL_PORT: 587
EMAIL_HOST_USER: "[email protected]"
EMAIL_HOST_PASSWORD: ${SMTP_PASSWORD}
EMAIL_USE_TLS: "True"
DB: postgres
DB_HOST: healthchecks-db
DB_NAME: healthchecks
DB_USER: healthchecks
DB_PASSWORD: ${POSTGRES_PASSWORD}
REGISTRATION_OPEN: "False" # Invite-only
TELEGRAM_BOT_TOKEN: ${TELEGRAM_BOT_TOKEN:-}
SLACK_CLIENT_ID: ${SLACK_CLIENT_ID:-}
SLACK_CLIENT_SECRET: ${SLACK_CLIENT_SECRET:-}
depends_on:
healthchecks-db:
condition: service_healthy
healthchecks-db:
image: postgres:16-alpine
restart: always
environment:
POSTGRES_DB: healthchecks
POSTGRES_USER: healthchecks
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- healthchecks_db:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U healthchecks"]
interval: 10s
timeout: 5s
retries: 5
volumes:
healthchecks_db:
<code">cat > .env << 'EOF' SECRET_KEY=$(openssl rand -hex 32) POSTGRES_PASSWORD=StrongHealthDbPassword! SMTP_PASSWORD=your_mailgun_password EOF chmod 600 .env docker compose up -d # Create admin user: docker compose exec healthchecks /opt/healthchecks/manage.py createsuperuser
Step 2: Nginx Reverse Proxy
<code">sudo nano /etc/nginx/sites-available/healthchecks
<code">server {
listen 443 ssl http2;
server_name health.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/health.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/health.yourdomain.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
<code">sudo certbot --nginx -d health.yourdomain.com sudo systemctl reload nginx
Step 3: Create Checks
<code"># In Healthchecks UI → + Add Check # Example: Daily backup check # Name: "Production Database Backup" # Schedule: cron(30 2 * * *) — 2:30 AM daily # Grace time: 1 hour — alert if ping not received within 1 hour of schedule # Tags: backup, production # Get the ping URL: https://health.yourdomain.com/ping/UNIQUE-UUID # Check types: # Simple: ping after success (most common) # Cron: matches exact cron schedule # OnCalendar: systemd timer syntax
Step 4: Integrate Ping into Scripts
<code"># Pattern: script runs → success ping or fail ping
# If script crashes without reaching end → healthchecks alerts after grace period
# Bash backup script:
#!/bin/bash
PING_URL="https://health.yourdomain.com/ping/YOUR-UUID"
# Notify start (optional)
curl -fsS --retry 3 "$PING_URL/start" > /dev/null
# Run the backup
pg_dumpall -U postgres | gzip > /backup/db-$(date +%Y%m%d).sql.gz
RESULT=$?
if [ $RESULT -eq 0 ]; then
# Success ping
curl -fsS --retry 3 "$PING_URL" > /dev/null
echo "Backup completed successfully"
else
# Failure ping (immediately alerts)
curl -fsS --retry 3 "$PING_URL/fail" > /dev/null
echo "Backup FAILED with exit code $RESULT" >&2
exit 1
fi
<code"># Python script with Healthchecks:
import httpx
import os
PING_URL = os.environ["HEALTHCHECKS_PING_URL"]
def run_etl():
httpx.get(f"{PING_URL}/start") # Notify started
try:
process_data()
httpx.get(PING_URL) # Success
except Exception as e:
httpx.get(f"{PING_URL}/fail", content=str(e)) # Failure + error message
raise
Step 5: Alert Channels
<code"># In Healthchecks UI → Integrations → Add # Available alert channels: # Email (built-in) # Telegram (via bot token) # Slack (via webhook) # PagerDuty (for on-call escalation) # Webhook (any HTTP endpoint) # Matrix, Discord, Pushover # Configure Telegram: # 1. Create bot via @BotFather → get token # 2. Healthchecks UI → Integrations → Telegram → enter bot token + chat ID # 3. Test integration # Set alerts per check: # Check Settings → Notification Channels → assign channels # Choose: notify on failure only, or also on "back to normal"
Step 6: Monitor All Critical Cron Jobs
<code"># Typical jobs to monitor: # - Database backups (daily) # - File backups with Restic (daily) # - SSL certificate checks (weekly) # - Data sync/ETL jobs (hourly) # - Report generation (daily) # - Disk cleanup jobs (weekly) # - Log rotation (daily) # - Security update checks (daily) # Add to each cron job in /etc/cron.d/: # 30 2 * * * root /usr/local/bin/backup.sh && \ # curl -fsS https://health.yourdomain.com/ping/UUID > /dev/null # Or use the HEALTHCHECKS_PING_URL environment variable pattern # to avoid hard-coding URLs in scripts
Getting Started
Healthchecks.io uses under 100 MB RAM. It runs on a 1 GB Ubuntu VPS at VPS.DO. The most common failure mode — a cron job that silently stops working — is undetectable without job monitoring. For operations teams running production infrastructure, Healthchecks monitoring for backups, ETL jobs, and maintenance scripts is as important as uptime monitoring for web services.
Conclusion
Healthchecks.io self-hosted provides silent failure detection for all scheduled tasks — if a job doesn’t ping within its expected window, you get alerted immediately rather than discovering the failure when you need the backup or report. The start/success/failure ping pattern captures both missing executions and partial failures. For production infrastructure, monitoring your automation is as critical as monitoring your services.
taxes
November 1, 2026It is truly a nice and helpful piece of info.
I am happy that you just shared this helpful info with us.
Please keep us up to date like this. Thank you for sharing.
supplement reviews
November 1, 2026The article was informative without being difficult to understand. This encourages me to do a little more reading on the subject. Thanks for making the subject easier to explore.
supplement side effects
November 1, 2026I enjoyed reading this guide. The practical points make the topic feel less confusing. I found this discussion worthwhile.
natural health website
November 1, 2026This is an informative and well-organized post. It is always worth checking trustworthy sources before acting on health information. I appreciate the reader-focused writing.
wellness information
November 1, 2026This article gives readers helpful context. I like that the article keeps the discussion measured and reader-friendly. A follow-up article would be interesting.