Monitor Website Uptime From the Command Line

2026-05-01 | Tags: ["monitoring", "uptime", "bash", "api", "devops"]

Monitor Website Uptime From the Command Line

Uptime monitoring services charge $10-50/month for what amounts to periodic HTTP requests with alerting. If you're monitoring a handful of sites for a side project or small team, you can build the same thing with curl, cron, and free APIs.

Here's how.

The Simplest Monitor

#!/bin/bash
# check-uptime.sh — Monitor a single URL
URL="https://example.com"
STATUS=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 "$URL")

if [ "$STATUS" != "200" ]; then
  echo "[$(date -u)] $URL returned $STATUS" >> /var/log/uptime.log
  # Send alert (email, Slack webhook, etc.)
fi

Add it to cron:

# Check every 5 minutes
*/5 * * * * /home/user/check-uptime.sh

That's a functional uptime monitor in 8 lines.

Going Further: Visual Verification

HTTP 200 doesn't always mean your site is working. A blank page, a crashed React app, or a database error can all return 200. For visual verification, take a screenshot and check it:

#!/bin/bash
URL="https://myapp.com"

# Get screenshot
curl -s -o /tmp/site-check.png \
  "https://hermesforge.dev/api/screenshot?url=${URL}&width=1280&height=720"

# Check file size — a tiny image likely means a blank/error page
SIZE=$(stat -f%z /tmp/site-check.png 2>/dev/null || stat -c%s /tmp/site-check.png)
if [ "$SIZE" -lt 5000 ]; then
  echo "[$(date -u)] WARNING: $URL screenshot suspiciously small (${SIZE} bytes)" >> /var/log/uptime.log
fi

A real page renders to a reasonably large image. If the screenshot is tiny (under 5KB), something is probably wrong.

Check Multiple Sites

#!/bin/bash
SITES=(
  "https://myapp.com"
  "https://api.myapp.com/health"
  "https://docs.myapp.com"
)

for URL in "${SITES[@]}"; do
  STATUS=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 "$URL")
  if [ "$STATUS" != "200" ]; then
    echo "[$(date -u)] DOWN: $URL ($STATUS)" >> /var/log/uptime.log
  fi
done

Beyond uptime, broken links frustrate users and hurt SEO. Check for dead links on a schedule:

#!/bin/bash
# Weekly dead link scan
RESULT=$(curl -s "https://hermesforge.dev/api/deadlinks?url=https://myapp.com&depth=2")
BROKEN=$(echo "$RESULT" | python3 -c "import sys,json; d=json.load(sys.stdin); print(len(d.get('broken_links',[])))")

if [ "$BROKEN" -gt 0 ]; then
  echo "[$(date -u)] Found $BROKEN broken links on myapp.com" >> /var/log/uptime.log
  echo "$RESULT" >> /var/log/broken-links.json
fi

Check SSL Certificate Expiry

Expired certificates cause downtime that HTTP checks won't catch until it's too late:

#!/bin/bash
# Check SSL expiry for your domains
RESULT=$(curl -s "https://hermesforge.dev/api/ssl?url=https://myapp.com")
DAYS_LEFT=$(echo "$RESULT" | python3 -c "import sys,json; print(json.load(sys.stdin).get('days_until_expiry',0))")

if [ "$DAYS_LEFT" -lt 14 ]; then
  echo "[$(date -u)] SSL cert expires in $DAYS_LEFT days!" >> /var/log/uptime.log
fi

The Full Monitor Script

Combining all of the above into one script that runs every 5 minutes:

#!/bin/bash
# full-monitor.sh
LOG="/var/log/uptime.log"
ALERT_EMAIL="you@example.com"
BASE="https://hermesforge.dev"

SITES=("https://myapp.com" "https://api.myapp.com/health")

for URL in "${SITES[@]}"; do
  STATUS=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 "$URL")
  if [ "$STATUS" != "200" ]; then
    MSG="[$(date -u)] DOWN: $URL ($STATUS)"
    echo "$MSG" >> "$LOG"
    # Optional: send alert via your preferred method
  fi
done

# Visual check (hourly — don't overdo it)
MINUTE=$(date +%M)
if [ "$MINUTE" = "00" ]; then
  for URL in "${SITES[@]}"; do
    curl -s -o /tmp/check.png "${BASE}/api/screenshot?url=${URL}&width=1280"
    SIZE=$(stat -c%s /tmp/check.png 2>/dev/null || echo 0)
    if [ "$SIZE" -lt 5000 ]; then
      echo "[$(date -u)] VISUAL CHECK FAILED: $URL (${SIZE} bytes)" >> "$LOG"
    fi
  done
fi

Why Not Use a SaaS Monitor?

For production systems with SLAs, use a proper monitoring service — they offer multi-region checks, incident management, and status pages.

But for side projects, staging environments, or personal sites:

DIY (curl + cron) SaaS Monitor
Cost $0 $10-50/month
Setup 10 minutes 5 minutes
Regions 1 (your server) Multiple
Customization Unlimited Limited
Visual checks Yes (via screenshot API) Some paid tiers
SSL monitoring Yes (via SSL API) Usually included
Link checking Yes (via dead links API) Rarely

For a $0/month side project, a $0/month monitor makes sense.


All the APIs used in this tutorial are free with no signup required. Try them: Screenshot API, Dead Links API, SSL Checker.