Monitor Website Uptime From the Command Line
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
Add Dead Link Checking
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.