Bandwidth Usage Alerts on Linux: Thresholds Without Spam
A useful bandwidth alert answers one question: is the link full for long enough to hurt users, or am I about to blow my monthly transfer quota? Everything else - a 3-second spike during a backup, a burst when a cache warms up - is noise.
This guide gives you two alerts that cover almost every server:
- Utilization alert - throughput above X% of link speed, sustained for N minutes.
- Quota alert - monthly transfer on track to exceed the provider's limit.
To inspect bandwidth by hand first, see how to check network bandwidth usage on Linux. To confirm a slowdown is really bandwidth, run the 5 bandwidth checks.
Step 1: Measure Throughput From Kernel Counters
The kernel keeps byte counters per interface in /sys/class/net/<iface>/statistics/. Read them twice and divide by the interval - no extra packages needed:
#!/usr/bin/env bash
# bw-usage.sh - average in/out Mbit/s over an interval, plus % of link speed
IFACE=${1:-eth0}
INTERVAL=${2:-60}
S=/sys/class/net/$IFACE/statistics
rx1=$(cat $S/rx_bytes); tx1=$(cat $S/tx_bytes)
sleep "$INTERVAL"
rx2=$(cat $S/rx_bytes); tx2=$(cat $S/tx_bytes)
rx_mbit=$(( (rx2 - rx1) * 8 / INTERVAL / 1000000 ))
tx_mbit=$(( (tx2 - tx1) * 8 / INTERVAL / 1000000 ))
speed=$(cat /sys/class/net/$IFACE/speed 2>/dev/null) # Mbit/s, -1 or empty on many virtual NICs
speed=${LINK_MBIT:-$speed} # override: LINK_MBIT=200 ./bw-usage.sh
if [ -n "$speed" ] && [ "$speed" -gt 0 ]; then
max=$(( rx_mbit > tx_mbit ? rx_mbit : tx_mbit ))
util=$(( max * 100 / speed ))
echo "rx=${rx_mbit}Mbit/s tx=${tx_mbit}Mbit/s util=${util}%"
[ "$util" -lt "${THRESHOLD:-90}" ] || exit 2 # non-zero exit = threshold breached
else
echo "rx=${rx_mbit}Mbit/s tx=${tx_mbit}Mbit/s util=unknown (set LINK_MBIT)"
fi
$ ./bw-usage.sh eth0 60
rx=41Mbit/s tx=612Mbit/s util=61%
Averaging over 60 seconds already removes most sub-second bursts. Use the name of your real uplink (ip -br link lists them - often eth0, ens3 or enp1s0).
Virtual machines: /sys/class/net/*/speed often reports -1 or a meaningless 10000. Use the bandwidth your provider sells instead (for example 1 Gbit/s port, or 200 Mbit/s on a small cloud plan) and pass it as LINK_MBIT=200.
Step 2: Pick Thresholds That Mean Something
| Signal | Warning | Critical | Sustained for |
|---|---|---|---|
| Utilization of link speed (either direction) | 70% | 90% | 5-10 minutes |
| Absolute throughput on a capped VPS | 70% of the cap | 90% of the cap | 5-10 minutes |
| Monthly transfer vs. quota | 80% of quota | 95% of quota | - (check daily) |
| Throughput drop to near zero on a busy server | - | < 5% of the usual level | 5 minutes |
Why these numbers:
- Links degrade before 100%. Queues build up and latency rises well before a link is "full"; 90% sustained is already user-visible for interactive traffic.
- Sustained, not instant. Alert only when the condition holds for several consecutive checks. One sample over the threshold is a spike; five in a row is a problem.
- The "drop to zero" alert is underrated. A web server that normally pushes 50 Mbit/s and suddenly pushes 0.2 is usually broken (DNS, firewall, crashed app) - bandwidth is just where it shows first.
Step 3: Alert on Monthly Transfer Quotas
Many VPS and dedicated plans include a monthly transfer allowance and charge (or throttle) above it. vnstat keeps per-month totals across reboots:
sudo apt install vnstat # Debian/Ubuntu
sudo dnf install vnstat # RHEL/Rocky/Alma (EPEL)
sudo systemctl enable --now vnstat
# Current month totals
vnstat -m -i eth0
# Machine-readable: field 11 = total for the current month (vnStat 2.x --oneline b)
vnstat -i eth0 --oneline b | cut -d';' -f11
A quota check that prints the percentage used:
#!/usr/bin/env bash
# bw-quota.sh - % of the monthly transfer quota used so far
IFACE=${1:-eth0}
QUOTA_GB=${2:-20000} # e.g. 20 TB allowance
used_bytes=$(vnstat -i "$IFACE" --oneline b | cut -d';' -f11)
echo "used=$(( used_bytes / 1000000000 ))GB quota=${QUOTA_GB}GB pct=$(( used_bytes / 10000000 / QUOTA_GB ))%"
Check whether your provider counts inbound, outbound or both, and adjust the field accordingly (vnstat --oneline fields 9 and 10 are month rx and tx).
Step 4: Find Who Is Using the Bandwidth When It Fires
An alert is only useful if the next step is obvious:
# Per remote host / IP, live
sudo iftop -i eth0 -P -n
# Per process
sudo nethogs eth0
# Per connection with byte counters
ss -tinp | grep -E "bytes_(sent|acked|received)"
Common culprits: backup jobs scheduled during business hours, log shippers after an outage, a crawler hammering one endpoint, or a large file being hot-linked.
Step 5: Run It Automatically With Zuzia
With the Zuzia agent installed on the server:
- Add a scheduled task that runs
bw-usage.sh eth0 60every 5 minutes (andbw-quota.shonce a day). - The script exits with code
2when utilization reachesTHRESHOLD(90% by default), so breaches stand out in the task history; setTHRESHOLD=70for an early warning. - Keep host-level CPU, RAM, disk and load metrics on the same server in the same panel, so you can tell whether a bandwidth peak is also a load peak.
Every run's output is stored, so the history doubles as a simple bandwidth log: you can see whether the 90% alert was a one-off or the third evening in a row - which is the point where you schedule the backup elsewhere or upgrade the port.
Common Mistakes
- Alerting on a single sample. Use a 60-second average and require several consecutive breaches.
- Measuring the wrong interface. On Docker or Kubernetes hosts,
docker0,cni0andveth*carry the same traffic as the uplink; alert on the physical/uplink interface only. - Using bytes instead of bits. Link speeds are in bits per second;
/syscounters are in bytes. Multiply by 8. - Ignoring direction. A web server saturates
tx; a backup target saturatesrx. Check both and alert on the larger. - Counter resets. Counters reset on reboot or driver reload; if the second reading is lower than the first, skip that sample.
FAQ
What is a good bandwidth utilization alert threshold?
Warn at 70% of link speed and go critical at 90%, both sustained for 5-10 minutes. For capped cloud instances, use the provider's bandwidth cap instead of the NIC speed.
How do I get an alert when bandwidth usage is high on Linux?
Measure throughput from /sys/class/net/<iface>/statistics over 60 seconds, compare it with the link speed, and run that check on a schedule with an alerting tool - cron plus email, or a monitoring service such as Zuzia that stores the history and notifies you.
How do I check bandwidth usage per IP?
Use iftop -i eth0 -P -n for live per-host traffic, or nethogs for per-process usage. For historical per-IP accounting you need flow data (for example nfdump/sFlow) or firewall counters.
How do I track monthly bandwidth usage for a VPS quota?
Install vnstat, enable its service, and read the current month total with vnstat -m or vnstat --oneline b. Alert at 80% of the provider's quota so you have time to react before overage charges apply.