How to monitor network traffic on Linux: by interface, process and container

Most network monitoring mistakes aren't about the tool. You're looking at the wrong interface or the wrong namespace. Here's how to find the right one, then see exactly who is using it.

Share
Network Interface Traffic Monitoring Linux

Preview of the post body. Title goes in Ghost's title field. Select from the first paragraph below to the end, copy, paste into Ghost.

How to monitor network traffic on Linux: by interface, process and container

Most wrong answers in network monitoring come from watching the wrong interface, not from a bad tool.

Your VPS panel says you pushed 800 GB this month. eth0 looks quiet. The traffic is actually on docker0, inside a container's own namespace, or on a bridge you forgot existed. So the order matters: find the right interface, watch its rate, find who is using it, then decide whether you need history.

If you're in the middle of an incident, this is the short version:

ip -s link show            # which interface has counters moving
sudo nethogs eth0          # which process is using it
docker stats --no-stream   # which container, if you run Docker

Swap eth0 for your interface name. The rest of this post is the longer version, with example output, Docker and Proxmox specifics, and the reasons the numbers sometimes disagree.

Which tool answers which question

Each tool answers one question well and the others badly. This is the map I'd keep in my head.

Question Tool Needs root
Which interface is moving? ip -s link no
What is the live rate? ifstat, nload, sar -n DEV no
Which remote hosts? iftop yes
Which process? nethogs yes
Which container? docker stats Docker access
How much this month? vnstat no

I wrote about a few of these before in 5 great commands to monitor network bandwidth. This post goes deeper on interfaces, containers and history.

How do I find the right network interface?

List the interfaces and their state first:

ip -br link

Then look at the byte counters:

ip -s link show eth0

Example output (yours will differ):

2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
    link/ether 52:54:00:12:34:56 brd ff:ff:ff:ff:ff:ff
    RX:  bytes packets errors dropped  missed   mcast
    9876543210 7654321      0       0       0       0
    TX:  bytes packets errors dropped carrier collsns
    1234567890 4321098      0       0       0       0

Run it twice, ten seconds apart. The interface whose RX or TX bytes grow is the one carrying traffic. If eth0 barely moves, you're looking at the wrong one.

Names vary: eth0, ens3, enp0s3, ens5 on many cloud images. On a host with Docker or Proxmox, also check what hangs off the bridges:

bridge link

You'll see members of docker0, br-xxxxxxxx or vmbr0. Traffic from guests usually shows up on those, and on the physical NIC as well.

How do I watch live traffic per interface?

ifstat prints one line per second and nothing else:

sudo apt install ifstat
ifstat -i eth0 1

Example output:

       eth0
 KB/s in  KB/s out
  412.31     87.45
  398.02     91.10

nload draws a graph in the terminal, which is nicer when you want to see a spike come and go:

sudo apt install nload
nload eth0

Watch the units. ifstat here is in kilobytes per second. nload shows bits by default, so the same traffic looks eight times bigger. That alone causes half the "my tools disagree" questions I see.

If you don't know the interface yet, sar from the sysstat package prints every interface at once:

sudo apt install sysstat
sar -n DEV 1 5

The rxkB/s, txkB/s and %ifutil columns tell you quickly where the load is and how close the link is to its limit.

Which process or host is using the bandwidth?

Two tools, two different answers. iftop shows remote hosts and ports. nethogs shows processes.

sudo apt install iftop nethogs
sudo iftop -i eth0 -nP
sudo nethogs eth0

-n skips DNS lookups and -P shows ports. Example nethogs output:

    PID USER     PROGRAM                  DEV      SENT      RECEIVED
   2210 www-data /usr/sbin/nginx          eth0   85.210     1.402 KB/sec
   1873 root     /usr/bin/rsync           eth0  402.118     0.311 KB/sec

nethogs can't map every connection. Lines marked unknown TCP are traffic it saw but couldn't tie to a process, and that happens a lot with containers. Treat it as a strong hint, not a court record. The nethogs project page explains how it matches connections to processes.

If what you find looks like an attack instead of a busy service, count connections per source IP before anything else. I covered that in how to verify a DDoS attack with netstat. iptraf-ng is another option, and if it shows no interfaces, there's a fix for IPTraf not showing an interface.

How do I monitor traffic per Docker container?

The fastest answer is built in:

docker stats --no-stream

Example output (trimmed):

CONTAINER ID   NAME   CPU %   MEM USAGE / LIMIT   MEM %   NET I/O          BLOCK I/O   PIDS
3f2a1b9c8d7e   web    0.35%   48.2MiB / 1.9GiB    2.48%   1.82GB / 640MB   0B / 0B     5

NET I/O is received / sent. It's a running total since the container started, not a rate. To get only the network columns for every container:

docker stats --no-stream --format "table {{.Name}}\t{{.NetIO}}"

The format placeholders are listed in the docker stats reference. Because the numbers reset when a container is recreated, they're useful for "which one is the heavy one", less so for monthly totals.

For a live rate from inside a container's network namespace, use nsenter from the host. It runs the host's tools in the container's namespace, so nothing needs to be installed in the image:

PID=$(docker inspect -f '{{.State.Pid}}' web)
sudo nsenter -t "$PID" -n ifstat -a 1

Two things trip people up. docker0 is only the default bridge. Compose projects and user-defined networks get their own br-xxxxxxxx bridges, so list them with docker network ls and ip -br link | grep br-. And a container's traffic is counted on the host's veth interface too, which is why the host totals and the container's own view can look different.

How do I monitor VMs and LXC containers on Proxmox?

Guests are attached to a bridge, usually vmbr0. Each guest gets its own interface on the host:

  • VMs: tap<VMID>i<N>, for example tap100i0
  • LXC containers: veth<CTID>i<N>, for example veth101i0
ip -br link | grep -E 'tap|veth'
ifstat -i tap100i0 1

Read the columns backwards. On the host side of a tap or veth interface, RX is what the guest sent and TX is what the guest received. Forgetting this makes a download look like an upload.

If you'd rather see the guest's own view, run the command inside an LXC container without leaving the host:

pct exec 101 -- ip -s link

How do I check for dropped packets and errors?

High traffic isn't the only problem. Drops mean the interface or the path behind it can't keep up. Start with the same command as before and look at the errors, dropped and missed columns:

ip -s link show eth0
ethtool -S eth0 | grep -Ei 'drop|err|miss|fifo'

Counter names in ethtool -S depend on the driver, and many VPS virtual NICs report very little, so an empty result there doesn't mean all is well. A handful of drops on a machine that has been up for months is normal. Drops that grow during load are the thing to chase.

The usual causes:

  • the receive ring buffer is too small (check with ethtool -g eth0, raise with ethtool -G eth0 rx 4096 if the driver allows it)
  • the CPU is saturated handling network interrupts (look at the si column in top)
  • the provider is capping bandwidth or bursts on a virtual NIC

How do I keep a history of traffic?

I used to log /proc/net/dev with a shell loop. Don't. vnstat does the same job properly: it reads the same kernel counters, stores them in a small database and gives you hourly, daily and monthly totals.

sudo apt install vnstat
sudo systemctl enable --now vnstat

It starts empty, so give it a few hours before the numbers mean anything. Then:

vnstat -i eth0        # summary
vnstat -l -i eth0     # live rate
vnstat -h             # per hour
vnstat -d             # per day
vnstat -m             # per month

Example vnstat -d output:

 eth0  /  daily

       day        rx      |     tx      |    total    |   avg. rate
   ------------------------+-------------+-------------+---------------
   2026-10-30     1.21 GiB |  310.40 MiB |    1.51 GiB |    1.47 Mbit/s
   2026-10-31     1.05 GiB |  288.12 MiB |    1.33 GiB |    1.29 Mbit/s

vnStat 2.x can also print JSON with --json, which is handy for scripts. The full option list is in the vnStat manual.

If you compare these totals with your provider's panel, expect small differences. Providers often meter at the hypervisor, and they don't always count the same traffic you do.

Why don't the numbers match between tools?

Almost always one of four reasons.

Units. Bytes versus bits, as above. Providers and nload talk in bits, ifstat and vnstat totals in bytes.

Rate versus total. Some tools show a rate right now, others show a counter since boot or since start. You can't compare them directly.

Namespaces. A container has its own interfaces. Host tools see the other end of the veth pair, and container tools see their own.

Offloading. NIC features like GRO, GSO and TSO merge packets before the kernel counts them, so packets per second can look strange. Byte counters stay trustworthy, so use bytes when you want a straight answer.

When two tools disagree, go to the source: grep eth0 /proc/net/dev. The first number after the interface name is received bytes and the ninth is transmitted bytes. If that file is moving and a tool says zero, the tool is wrong.

What I'd actually set up

On any server I care about, I'd install vnstat on day one and learn nethogs before I need it. During an incident the sequence is ip -s link, then nethogs, then docker stats if containers are involved. That covers most cases in a few minutes.

I'd skip dashboards until something needs more history than vnstat keeps. Grafana is great, but it's a project. vnstat is a package.

And one honest limit: iftop and nethogs are for troubleshooting. On very fast links they can miss bursts, and they need root. If you need line-rate accuracy on 10G and up, you want flow data, not these.

FAQ

How do I see which process is using the most bandwidth on Linux?

Use sudo nethogs <interface>. It groups traffic by process and updates live. Traffic it can't match shows up as unknown TCP, which is common with containers.

How do I check how much bandwidth my VPS has used this month?

Install vnstat, let it collect for a while, then run vnstat -m. Compare the result with your provider's panel, since providers meter on their side and may count differently.

Why does the host show traffic but my Docker container shows none?

You're probably reading the wrong end. The container's traffic is counted on its own interface inside its namespace, and on a veth interface on the host. Use docker stats for a quick answer, or nsenter to look from inside the container.

Is tcpdump good for measuring traffic?

It's for inspecting packets, not for measuring volume. Use it when you need to see what is actually on the wire, like in my tcpdump examples for SIP and RTP. For rates and totals, stick to ifstat, nload and vnstat.

What's the difference between iftop and nethogs?

iftop shows which remote hosts and ports you're talking to. nethogs shows which local processes are doing the talking. When a server is busy and you don't know why, start with nethogs, then use iftop to see where the traffic is going.