Every minute of downtime costs money and reputation. Proper monitoring lets you react to problems within minutes, not hours.
UptimeRobot — free monitoring
- Sign up at uptimerobot.com
- Add New Monitor → HTTP(s)
- URL:
https://yourdomain.com - Interval: 5 minutes (free plan)
- Notifications: Email, Telegram, Slack
Telegram alerts from a VPS via bash
#!/bin/bash
# /usr/local/bin/check-site.sh
BOT_TOKEN="YOUR_TOKEN"
CHAT_ID="YOUR_CHAT_ID"
URL="https://yourdomain.com"
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "$URL")
if [ "$HTTP_CODE" != "200" ]; then
curl -s "https://api.telegram.org/bot$BOT_TOKEN/sendMessage" -d "chat_id=$CHAT_ID" -d "text=🚨 Site is down! Code: $HTTP_CODE - $(date)"
fi
chmod +x /usr/local/bin/check-site.sh
# Cron every 5 minutes:
*/5 * * * * /usr/local/bin/check-site.sh
Monitoring server resources
# Install netdata (a nice dashboard)
bash <(curl -Ss https://my-netdata.io/kickstart.sh)
# Available at http://YOUR_IP:19999
Useful diagnostic commands
htop # CPU, RAM, processes
iotop # Disk load
nethogs # Traffic by process
df -h # Disk space
free -h # RAM usage
ss -tlnp # Open ports
Diagnosing common problems with the check script
The script reports "site down" even though the site opens fine in a browser — a common cause is that curl without extra flags does not follow redirects and does not set a User-Agent header, so some sites or a WAF return 403 or 301 instead of 200.
$ curl -s -o /dev/null -w "%{http_code}" https://yourdomain.com
403
Add -L to follow redirects and a User-Agent header that mimics a browser if the site is protected against bots: curl -s -L -A "Mozilla/5.0" -o /dev/null -w "%{http_code}" https://yourdomain.com. Test the final command manually from the console before putting it in cron — that way you see the real response code, not just the script's interpretation of it.
A Telegram notification never arrives even though the curl call to the Telegram API succeeds — check Telegram's own response code, not just curl's exit code: a wrong chat_id or a bot that never received /start returns JSON with "ok": false, but curl still exits with code 0 because the request itself went through.
{"ok":false,"error_code":400,"description":"Bad Request: chat not found"}
Comparing uptime monitoring options
| Option | Checked from | Minimum interval |
|---|---|---|
| UptimeRobot (free plan) | The service's external servers | 5 minutes |
| Bash script on the VPS itself | The same server as the site | Any, depends on cron |
| Uptime Kuma (self-hosted) | Your own separate monitoring server | 20 seconds |
| Zabbix | A dedicated monitoring server, supports agents | Configurable, down to seconds |
When monitoring from a single point is not enough
- A bash script on the VPS itself will not notice the whole server going down — if the server itself fails, there is nothing left to run the check and send an alert. You need an external service like UptimeRobot checking from outside.
- A single external checker can give a false alarm because of temporary issues in its own network — paid monitoring plans check from several geographic points and only alert when the outage is confirmed from multiple locations.
- You need to monitor more than the HTTP code — page content or the response time of a critical API — a simple curl script only checks the status code; content checks need more specialized tools.
- You need SLA reporting with months of incident history for clients or management — free tools usually keep history for a limited period; long-term reporting needs a paid plan or your own incident database.
Verifying the result
- Run the script manually and temporarily stop Nginx:
systemctl stop nginx— a Telegram notification must arrive by the next cron run. - Confirm cron is actually running the job:
grep CRON /var/log/syslog | tailmust show regular entries for the script's run. - Make sure the script does not fire false alarms on brief network hiccups — add a retry before alerting if single false positives have already happened.
- Confirm that after the site recovers the system also sends a recovery notification, not just a failure one — otherwise it is easy to forget the issue was resolved long ago.
For monitoring the server's own resources, not just external site availability, see the article on Netdata. A self-hosted alternative to UptimeRobot with its own dashboard is covered in the article on Uptime Kuma.