← Back to blog

The Cron Script for Disk/CPU/Memory Alerts (and When to Stop Maintaining It Yourself)

You've been here: the site's down, the disk's full, the database wrote nothing for six hours. Somewhere in /var/log there's a warning you never saw, because nothing was watching for it.

The fix doesn't need to be complicated. You don't need an agent, a daemon, or a weekend lost to Grafana dashboards for two servers. You need a script that checks disk, CPU, and memory on a schedule, and yells at you — over email, Telegram, or whatever you already check — before something breaks.

Here's that script.

The script

Save this as /usr/local/bin/health-check.sh:

health-check.sh
# Thresholds — tune to taste
DISK_THRESHOLD=85
CPU_THRESHOLD=90
MEM_THRESHOLD=90
EMAIL=you@example.com
HOSTNAME=$(hostname)

alert() {
  local subject="$1"
  local body="$2"
  echo "$body" | mail -s "$subject" "$EMAIL"
}

# --- Disk ---
df -h --output=pcent,target -x tmpfs -x devtmpfs | tail -n +2 | while read -r line; do
  usage=$(echo "$line" | awk '{print $1}' | tr -d '%')
  mount=$(echo "$line" | awk '{print $2}')
  if [ "$usage" -ge "$DISK_THRESHOLD" ]; then
    alert "[$HOSTNAME] Disk at ${usage}% on $mount" \
          "Mount $mount is at ${usage}% usage (threshold: ${DISK_THRESHOLD}%)."
  fi
done

# --- CPU (5-min load average as a % of core count) ---
CORES=$(nproc)
LOAD=$(cut -d ' ' -f2 /proc/loadavg)
CPU_PCT=$(awk -v load="$LOAD" -v cores="$CORES" 'BEGIN { printf "%.0f", (load/cores)*100 }')
if [ "$CPU_PCT" -ge "$CPU_THRESHOLD" ]; then
  alert "[$HOSTNAME] CPU load at ${CPU_PCT}%" \
        "5-min load average is ${LOAD} across ${CORES} cores (~${CPU_PCT}%)."
fi

# --- Memory ---
MEM_PCT=$(free | awk '/Mem:/ {printf "%.0f", ($3/$2)*100}')
if [ "$MEM_PCT" -ge "$MEM_THRESHOLD" ]; then
  alert "[$HOSTNAME] Memory at ${MEM_PCT}%" \
        "Memory usage is at ${MEM_PCT}% (threshold: ${MEM_THRESHOLD}%)."
fi

Make it executable and drop it in cron:

crontab — web-01
chmod +x /usr/local/bin/health-check.sh
crontab -e

# add this line
*/5 * * * * /usr/local/bin/health-check.sh

That's it. Every five minutes, it checks all three, and mails you if anything's over threshold. No package to install beyond mailutils or mailx if you don't already have a mail command. Works on Ubuntu, Debian, AlmaLinux, Amazon Linux, Alpine — anywhere with df, free, and /proc/loadavg.

Where this breaks down

This script is genuinely fine for a while. Then, usually right after it saves you once, you start improving it — and that's where the maintenance creeps in.

Repeat alerts. The disk hits 87%, you get an email. Five minutes later, it's still at 87%, and you get another. And another, every five minutes, forever, until you fix it or the disk fills completely. Silencing this properly means tracking state between runs — a temp file, a timestamp, some "have I already alerted for this in the last N hours" logic. That's not hard to write once. It's mildly annoying to get right, and easy to get subtly wrong (what happens across a reboot? what if the script itself doesn't run for an hour?).

No multi-server view. This script tells you about one machine. If you run three or four, you're now managing three or four crontabs, three or four sets of thresholds, and getting alerts in three or four separate emails with no shared view of "how are my servers doing right now."

Brittle mail setup. mail -s assumes a working MTA on the box. On a fresh VPS, that's often not true — you'll spend twenty minutes fighting Postfix or msmtp config before your first alert even sends. And even once it works, email is easy to miss; there's no push notification, no Telegram ping, nothing that reaches you the way a real incident should.

No history. When the disk fills at 3am, you want to know: was this sudden, or has it been creeping for two weeks? A cron script that emails you once has no memory of last week's 60%, last month's 40%. You're flying blind on trend.

None of these are hard problems individually. Collectively, they're exactly the reason a version of this script exists, finished, as Brimfull — one shell script in your crontab still, but one that dedupes alerts, tracks history, and pushes to ntfy, Telegram, or email without you configuring an MTA. No agent, no binary, no open ports, same as the script above — it just doesn't stop at "mostly works."

When to keep the DIY script

If you've got one server and don't mind the occasional repeat email, the script above is genuinely enough. Don't add infrastructure you don't need. The moment it stops being enough is usually the moment you're either:

  • managing more than one or two servers, and want them in one place, or
  • tired of getting the same alert every five minutes for an hour, or
  • wanting to glance at "how full is this disk been trending" instead of a single point-in-time number.

That's the point where finishing the script yourself costs more time than just pointing your crontab at something that already handles it.