Healthchecks.io on a VPS: Monitor Cron Jobs and Scheduled Tasks with Dead Man’s Switch Alerts

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.

5 Comments

  • taxes
    November 1, 2026

    It 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, 2026

    The 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, 2026

    I enjoyed reading this guide. The practical points make the topic feel less confusing. I found this discussion worthwhile.

  • natural health website
    November 1, 2026

    This 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, 2026

    This article gives readers helpful context. I like that the article keeps the discussion measured and reader-friendly. A follow-up article would be interesting.

Post Your Comment

Fast • Reliable • Affordable VPS - DO It Now!

Get top VPS hosting with VPS.DO’s fast, low-cost plans. Try risk-free with our 7-day no-questions-asked refund and start today!