Skip to content
Servers

How to Monitor VPS Bandwidth With vnStat

In this article9 sections

To know how much of a monthly traffic allowance your VPS has used, install vnStat. It reads the network counters the kernel already keeps, stores them in a small database, and answers with one command: vnstat -m shows the total for this month and previous months, and vnstat -d shows each day. It uses almost no CPU, needs no configuration on a normal server, and a ten-line script on top of it can warn you at 80% of your allowance, well before the connection is slowed down.

This guide is for VPS plans that include a fixed amount of traffic per month, which is common in Mumbai, Singapore and Sydney, where bandwidth costs providers far more than in Europe or North America. Commands are for Ubuntu and Debian.

Step 1: Install vnStat and find your interface

sudo apt update && sudo apt install -y vnstat
ip -br link | grep -v '^lo'

The second command lists the network interfaces. On most VPS plans there is one, named eth0 or ens3. vnStat finds it by itself and starts recording immediately.

Note. vnStat only knows about traffic from the moment it was installed. Install it on the first day of the server’s life, or at least before the start of a billing month, so the first monthly total is complete.

Step 2: Read the numbers

vnstat -m        # this month and earlier months
vnstat -d 10     # the last 10 days
vnstat -h        # the last 24 hours, by hour
vnstat -l        # live rate, Ctrl+C to stop

The monthly view looks like this:

 eth0  /  monthly

        month        rx      |     tx      |    total    |   avg. rate
     ------------------------+-------------+-------------+---------------
       2026-09     18.42 GiB |  212.60 GiB |  231.02 GiB |  713.03 kbit/s
       2026-10      6.11 GiB |   71.94 GiB |   78.05 GiB |  722.41 kbit/s
     ------------------------+-------------+-------------+---------------
     estimated     18.80 GiB |  221.30 GiB |  240.10 GiB |

rx is traffic received by the server and tx is traffic it sent. A web server sends far more than it receives. The estimated line projects the current month to its end at the present rate, which is the number to compare with your allowance.

Step 3: Know what your allowance means in practice

An allowance in gigabytes is hard to picture. Converted to an average rate, and to page views at a typical 2 MB per page, it looks like this:

Monthly allowance Average rate, all month Page views at 2 MB each
500 GB about 1.5 Mbps about 250,000
1 TB about 3.1 Mbps about 500,000
3 TB about 9.3 Mbps about 1,500,000

Most business websites never come close. The servers that do run out are the ones serving video or large downloads, taking off-site backups every night, or being scraped by bots.

Ask your host two questions, because providers differ: does the allowance count sent traffic only or both directions, and does the month run from the 1st or from your billing date? Until you know, treat vnStat’s total column as the number that counts.

Step 4: Get a warning at 80%

Install jq (sudo apt install -y jq) and save this as /usr/local/sbin/traffic-check.sh. Set LIMIT_GB to your plan’s allowance.

#!/usr/bin/env bash
# Logs a warning when this month's traffic passes WARN_PCT of the allowance.
set -euo pipefail
LIMIT_GB=500
WARN_PCT=80

USED_GB=$(vnstat --json m 1 | jq '.interfaces[0].traffic.month[-1] | ((.rx + .tx) / 1073741824) | floor')
PCT=$(( USED_GB * 100 / LIMIT_GB ))

if [ "$PCT" -ge "$WARN_PCT" ]; then
  logger -p user.warning -t traffic-check "WARNING: ${USED_GB} GB of ${LIMIT_GB} GB used this month (${PCT}%)"
else
  logger -t traffic-check "ok: ${USED_GB} GB of ${LIMIT_GB} GB used (${PCT}%)"
fi

Run it daily from /etc/cron.d/traffic-check:

15 8 * * * root /usr/local/sbin/traffic-check.sh

Make the script executable with sudo chmod 700 /usr/local/sbin/traffic-check.sh, and read its history with journalctl -t traffic-check. To be told rather than having to look, replace the warning line with a call to whatever already notifies you: an email command, or a webhook to n8n, Slack or Telegram.

Step 5: Find what is using the traffic

vnStat tells you how much, not what. When the daily figures jump, these three commands find the cause.

Which program, right now:

sudo apt install -y nethogs
sudo nethogs

Which URLs sent the most data today (Nginx’s default log format, where the tenth field is the response size):

sudo awk '{bytes[$7] += $10} END {for (u in bytes) printf "%8.1f MB  %s\n", bytes[u]/1048576, u}' /var/log/nginx/access.log | sort -rn | head -15

Which visitors took the most:

sudo awk '{bytes[$1] += $10} END {for (ip in bytes) printf "%8.1f MB  %s\n", bytes[ip]/1048576, ip}' /var/log/nginx/access.log | sort -rn | head -15

A single address at the top of that list with hundreds of megabytes is usually a scraper or someone hotlinking your files, not a customer.

Step 6: Bring the number down

  • Put a CDN in front of static files. Images, CSS, JavaScript and downloads served from Cloudflare’s cache never leave your server a second time. This is usually the biggest single saving, and our guide to a Cloudflare cache rule for WordPress extends it to whole pages.
  • Check compression. Text sent without gzip or Brotli is three to five times larger than it needs to be. curl -sI -H 'Accept-Encoding: gzip' https://example.com/ | grep -i content-encoding should print a line.
  • Resize and convert images. A page with four 3 MB photos costs more traffic than a hundred visits to a well-built page.
  • Send off-site backups as differences, not full copies. A nightly 20 GB upload is 600 GB a month by itself. Tools such as restic, borg or rclone sync send only what changed.
  • Block the heaviest bots. If the log shows a crawler you gain nothing from, block its user agent in Nginx or at Cloudflare.
  • Host video elsewhere. A video platform or object storage with its own CDN is the right place for large media.

Common mistakes to avoid

  • Installing vnStat after the warning email. It cannot see the past.
  • Watching only tx. Restores, imports and large uploads arrive as rx, and some providers count both.
  • Comparing GiB with GB without thinking. vnStat shows binary units (1 GiB = 1.074 GB). Near a limit, that 7% matters.
  • Assuming traffic means visitors. Backups, software updates and bots all count.
  • Reinstalling the server mid-month and trusting the new total. The count starts again from zero, but your provider’s does not.

Traffic on SiteHarbour VPS plans

On a SiteHarbour VPS, traffic is unlimited in our European and North American locations. In Mumbai, Singapore and Sydney each plan includes a monthly allowance: 500 GB on VPS-1, 1 TB on VPS-2 and VPS-3, and 3 TB on VPS-4. Beyond it the connection is limited to 10 Mbps until the next month, so the server stays online. If your audience is in India, Mumbai gives the lowest latency; if you expect very heavy transfer, tell us before you order and we will help you choose a location.

Frequently asked questions

Does vnStat slow the server down?

No. It does not inspect packets. It reads counters the kernel already maintains and writes to its database every few minutes.

Why does vnStat disagree with my provider’s figure?

Small differences are normal: the provider measures at its network edge, may count from a different day of the month, and may use decimal units. A large difference usually means vnStat was installed part-way through the month.

What happens to my site at 10 Mbps?

Pages still load, more slowly when several visitors arrive together. 10 Mbps moves about 4.5 GB an hour, which is enough for ordinary browsing but not for large downloads or video.

Does traffic through Cloudflare count?

Only the part Cloudflare fetches from your server. Anything it serves from its cache does not touch your VPS, which is why caching static files there saves so much.

Can I reset the counter each billing date?

You do not need to. Set the day the month starts in /etc/vnstat.conf with MonthRotate, then restart vnStat. Monthly totals will follow your billing cycle.

The short version: install vnStat on day one, read vnstat -m and its estimate, let a small daily script warn you at 80%, and when the number climbs, the Nginx log tells you exactly which files and visitors are responsible.

Share this guide