Context & Why You Need vnStat
Most network monitoring tools show you what’s happening right now — packet rates, active connections, current throughput. That’s useful for diagnosing a spike, but it tells you nothing about your bandwidth consumption over the past three months. When a cloud provider sends a surprise overage bill, or your ISP throttles you without warning, you need historical data — not a live graph.
That’s the gap vnStat fills. It runs as a lightweight daemon, reading interface statistics from the kernel’s own counters and accumulating them into a local database. Query usage by hour, day, month, or year — no packet capturing required, and no root access needed just to pull a report.
Running vnStat in production — on both VPS instances and bare-metal servers — has been reliable enough that I’ve stopped thinking about it. After a year on a busy web server handling ~50K requests/day, I had clean per-month traffic data I could cross-reference against CDN invoices to catch billing discrepancies. The resource footprint is tiny: around 1–2 MB of RAM, with periodic disk writes.
One thing that sets vnStat apart from alternatives like iftop or nethogs: it survives reboots. Because it reads kernel counters rather than sniffing the wire, it reconstructs totals correctly even after an interface restart — as long as the daemon was running when the counter rolled over.
Installation
vnStat packages are available in every major distro’s default repositories. No PPAs or third-party sources needed.
Debian / Ubuntu
sudo apt update
sudo apt install vnstat -y
RHEL / CentOS / Rocky Linux / AlmaLinux
# Enable EPEL first if not already done
sudo dnf install epel-release -y
sudo dnf install vnstat -y
Arch Linux
sudo pacman -S vnstat
Before going further, check your version. vnStat 2.x (released 2019) overhauled the database format and added JSON export — two things this guide depends on:
vnstat --version
Expected output looks like:
vnStat 2.12 by Teemu Toivola <tst at iki dot fi>
Configuration
Starting the Daemon
The daemon — vnstatd — handles all the data collection. Enable and start it with systemd:
sudo systemctl enable vnstat
sudo systemctl start vnstat
sudo systemctl status vnstat
By default, it polls each configured interface every 5 minutes. Data lands in /var/lib/vnstat/ — one database file per interface.
Adding Interfaces to Monitor
The daemon auto-detects interfaces on startup. If you add a new interface later — a VPN tunnel, a second NIC — you can register it manually:
# List available interfaces
ip link show
# Add a specific interface manually
sudo vnstat --add -i eth0
# Or for cloud instances where the interface name may differ
sudo vnstat --add -i ens3
After adding, wait a few minutes for the daemon to start collecting. The first query might come back empty or sparse — that’s normal. Give it 15–30 minutes before expecting meaningful hourly data.
Editing the Configuration File
The main config lives at /etc/vnstat.conf. A few settings worth adjusting:
sudo nano /etc/vnstat.conf
Key options to review:
# Interface to monitor by default (useful when you have only one)
Interface "eth0"
# How often the daemon polls (in seconds, default 300)
UpdateInterval 300
# How many days/months/years to keep in the database
SaveInterval 5
OfflineSaveInterval 30
# Maximum days to store in daily stats (0 = unlimited)
DailyDays 365
# Maximum months
MonthlyMonths 25
On any server I plan to run for more than a year, I set DailyDays to 730 and MonthlyMonths to 36. The database stays compact — under 500 KB even with three years of daily records. No reason to throw away history.
After editing, restart the daemon:
sudo systemctl restart vnstat
Verification & Monitoring
Basic Usage Queries
Once the daemon has been running for a while, start querying. Running vnstat with no arguments prints a summary for all monitored interfaces:
vnstat
Sample output:
rx / tx / total / estimated
eth0:
2024-05 45.23 GiB / 12.67 GiB / 57.90 GiB / 61.20 GiB
2024-06 3.10 GiB / 0.87 GiB / 3.97 GiB / 63.52 GiB
estimated 63.52 GiB / 17.83 GiB / 81.35 GiB
The estimated row extrapolates the current month’s usage — useful for spotting whether you’ll blow past a monthly cap before the billing cycle resets.
Detailed Per-Period Reports
# Daily breakdown (last 30 days)
vnstat -d
# Hourly breakdown (last 24 hours)
vnstat -h
# Monthly summary
vnstat -m
# Yearly totals
vnstat -y
# 5-minute intervals (most granular, last few hours)
vnstat -5
# Specify interface explicitly
vnstat -i eth0 -m
Live Traffic Rate
Need a quick read on current throughput? Skip iftop — vnStat’s built-in live mode is good enough for a simple sanity check:
# Live view — updates every second
vnstat -l -i eth0
Lighter than iftop, and perfectly fine for a “is traffic flowing?” gut-check.
Exporting Data to JSON
One feature I keep coming back to: JSON export. Pipe the output straight into a script or dashboard — no regex, no fragile text parsing.
# Full JSON dump for an interface
vnstat -i eth0 --json
# Monthly data only in JSON
vnstat -i eth0 --json m
# Daily data in JSON
vnstat -i eth0 --json d
A minimal Python script to parse monthly totals and print them:
import subprocess
import json
result = subprocess.run(
["vnstat", "-i", "eth0", "--json", "m"],
capture_output=True, text=True
)
data = json.loads(result.stdout)
for entry in data["interfaces"][0]["traffic"]["month"]:
year = entry["date"]["year"]
month = entry["date"]["month"]
rx_gb = entry["rx"] / 1024**3
tx_gb = entry["tx"] / 1024**3
print(f"{year}-{month:02d} RX: {rx_gb:.2f} GB TX: {tx_gb:.2f} GB")
Setting Up a Simple Bandwidth Alert
Got a metered VPS with a monthly cap? Wire up this cron script before you hit your limit. It fires an email when monthly RX crosses 80 GB:
#!/bin/bash
# /usr/local/bin/check_bandwidth.sh
LIMIT_GB=80
RX_BYTES=$(vnstat -i eth0 --json m | python3 -c "
import sys, json
d = json.load(sys.stdin)
entries = d['interfaces'][0]['traffic']['month']
if entries: print(entries[-1]['rx'])
else: print(0)
")
RX_GB=$(echo "scale=2; $RX_BYTES / 1073741824" | bc)
if (( $(echo "$RX_GB > $LIMIT_GB" | bc -l) )); then
echo "WARNING: Monthly RX is ${RX_GB} GB (limit: ${LIMIT_GB} GB)" \
| mail -s "Bandwidth Alert: eth0" [email protected]
fi
Add it to cron to run daily:
crontab -e
# Add:
0 9 * * * /usr/local/bin/check_bandwidth.sh
Viewing Historical Data After Database Migration
Moving servers or doing a clean reinstall? Copy /var/lib/vnstat/ to the new machine before starting the daemon and your full history comes with it. The data format is portable across identical vnStat versions.
Jumping from 1.x to 2.x is a different story — you’ll need to export and reimport. The vnStat 2.x package usually ships a migration tool for exactly this.
Practical Tips from Ongoing Use
- Pin your interface names. If your cloud provider renames interfaces on reboot (e.g.,
ens3becomesens4), vnStat creates a new database for the new name and your history splits in two. Use udev rules to lock the name, or check your provider’s docs. - Monitor multiple interfaces separately. On a server with both a public and a private NIC, track them independently. Internal traffic — say, between Docker containers on a private VLAN — can inflate totals if you’re watching the wrong interface.
- Pair with
ssornethogsfor per-process attribution. vnStat gives you totals per interface, not per process. When a number spikes, usess -tulnpornethogsto find what’s responsible, then cross-reference vnStat’s hourly data to see when it started. - Check the database directory periodically. With default settings,
/var/lib/vnstat/stays well under 10 MB even after years of data. Unexpected growth usually means a misconfiguredInterfaceentry is tracking a loopback or virtual interface with inflated counters.

