Something Is Eating Your Upload
You spent $40 on a smart switch. You added a VLAN. You installed Pi-hole. You are, objectively, a person who has their home network together.
And yet — your upload is pegged at 95% and you have no idea which device is responsible. The smart switch dashboard shows you blinking LEDs. Very helpful.
Two open-source tools can actually answer that question, and they answer it in completely different ways. ntopng goes deep — DPI, per-flow charts, GeoIP, NetFlow ingestion, alerts, the whole observatory. darkstat is a single C binary that captures packets and renders a plain HTML page showing you the top talkers. That’s it.
Neither is wrong. They just solve different problems, and knowing which one to reach for saves you from standing up a Redis instance on a Pi 4 at midnight when all you needed was “which host is hammering my NAS.”
Install Footprint
darkstat: Embarrassingly Small
darkstat ships as a single binary with no external dependencies. On Debian/Ubuntu:
sudo apt install darkstatThat’s roughly 120 KB of binary. It links against libpcap. It reads packets, tallies counters in RAM, and serves the HTML page on port 667 by default. The entire config is a handful of flags.
Systemd unit to run it on an interface:
[Unit]Description=darkstat network statsAfter=network.target
[Service]ExecStart=/usr/sbin/darkstat -i eth0 -p 667 --no-dns --daylog /var/lib/darkstat/daylogRestart=on-failureUser=root
[Install]WantedBy=multi-user.targetsudo systemctl daemon-reloadsudo systemctl enable --now darkstatBrowse to http://your-host:667 and you’ll see host traffic counters within seconds. RAM usage on a Pi 4 at moderate home-lab traffic: roughly 8–12 MB. CPU: negligible.
ntopng: A Whole Stack
ntopng is not a single binary. The community edition pulls in Redis (for persistence), nDPI (the deep packet inspection library), and optionally GeoIP databases. The Docker Compose route is the sanest install path:
services: redis: image: redis:7-alpine restart: unless-stopped volumes: - redis_data:/data
ntopng: image: ntop/ntopng:stable restart: unless-stopped network_mode: host # needs raw access to the interface cap_add: - NET_ADMIN - NET_RAW volumes: - ntopng_data:/var/lib/ntopng - ./ntopng.conf:/etc/ntopng/ntopng.conf:ro depends_on: - redis ports: - "3000:3000"
volumes: redis_data: ntopng_data:-i=eth0-r=redis://redis:6379--community--http-port=3000--disable-login=1 # remove in prod; handy for lab testingdocker compose up -dOn a Pi 4 with moderate traffic, ntopng will idle around 120–200 MB RAM with Redis adding another 30–50 MB. Under active DPI load that climbs. On a mini PC (N100 / N5105) it barely registers. On a Pi 4 with a busy LAN and NetFlow ingestion, you’ll feel it.
What Each Tool Actually Sees
darkstat: Host and Port Counters
darkstat operates at layer 3. It sees source IP, destination IP, protocol, and byte counts. That’s the entire data model. The UI gives you:
- Total traffic in/out per host
- Per-host breakdown by port
- Daily graph (if you enable
--daylog)
What it does not give you: application identification, DNS names resolved against flows, per-flow timelines, GeoIP, alerts, or any form of historical drill-down beyond the in-RAM ring buffer (which resets when the daemon restarts).
This is not a limitation so much as a design goal. darkstat answers “which host sent the most bytes in the last hour?” It does not answer “what application on that host was doing it.”
One underrated use: pipe the darkstat HTTP output into a cron job or healthcheck. Because it’s plain HTML with predictable structure, you can scrape the top-talkers table with a five-line Python script and fire an alert when a single host crosses a threshold. You won’t find that workflow in any docs because it’s technically an abuse of a stats page — but it works, and sometimes duct tape is the right material.
ntopng: Full Flow Visibility
ntopng runs nDPI on every packet. nDPI is a layer-7 classification library that identifies application protocols — not just port 443 but specifically “this is Netflix,” “this is BitTorrent,” “this is WireGuard.” It currently recognizes over 300 protocols.
What you get on top of that:
- Per-flow records stored in Redis: src/dst IP, port, protocol, bytes, duration, L7 application, country
- Per-host intelligence: device fingerprinting, DNS activity, geolocation, top-talked peers
- Alerts: threshold-based alerts for anomalous hosts, blacklisted IPs, data volume spikes
- NetFlow / IPFIX / sFlow ingestion: point your router at ntopng and get whole-network visibility without a span port
- Flow export: ntopng Pro/Enterprise can export nFlow data; community edition reads it
The community edition is genuinely useful. The Pro tier ($49/year as of writing) unlocks historical flow export, SNMP polling, and more alert types. For a home lab the community tier covers most use cases.
Getting Whole-Network Visibility
Both tools need to see traffic. That’s the hard part, especially if you want more than just the traffic hitting the host running the tool.
Option 1 — Port Mirror / SPAN Port
Most managed switches support port mirroring. You mirror all traffic to one port, plug a Pi or mini PC into that port, and run darkstat or ntopng on the mirror interface. This gives you full visibility into everything crossing the switch.
# Confirm the mirror interface is receiving traffictcpdump -i eth0 -c 20 -nOption 2 — In-line / Bridge Mode
Some setups insert the monitoring host inline between the router and the switch. Traffic passes through the monitoring host. Adds latency; works when a span port isn’t available.
The cleanest bridge setup on Linux uses two NICs and a software bridge:
# Create a bridge between eth0 (WAN side) and eth1 (LAN side)ip link add name br0 type bridgeip link set eth0 master br0ip link set eth1 master br0ip link set br0 upip link set eth0 upip link set eth1 up# Now run darkstat or ntopng on br0Traffic flows through unmodified; the monitoring daemon sees everything on br0. Latency added is microseconds unless your monitoring host is already CPU-bound.
Option 3 — NetFlow from the Router (ntopng only)
If your router runs OPNsense or pfSense, this is the cleanest option for ntopng. Enable the NetFlow exporter plugin on the router, point it at ntopng’s collector port.
On OPNsense: Services → NetFlow → Settings
Listening Interfaces: WAN, LAN (or all)Destination Host: <ntopng-host-ip>Destination Port: 2055In ntopng.conf, add the NetFlow collector interface:
-i=eth0-i=nf:0 # NetFlow collector on UDP 2055-r=redis://redis:6379--community--http-port=3000Restart ntopng and you’ll start seeing aggregated flow data from the entire network without needing a span port. darkstat cannot consume NetFlow — it needs raw packets on a local interface.
Pi-hole Integration
ntopng has a Pi-hole DNS-over-HTTPS bridge that lets it resolve hostnames from Pi-hole’s query log. In ntopng.conf:
--dns-mode=1With that enabled, ntopng uses passive DNS to label hosts by name rather than IP. darkstat has a --dns mode that does real-time reverse DNS lookups, but it’s blocking and can slow down packet capture — leave --no-dns on by default.
UI Quality
Let’s be honest. darkstat’s UI looks like it was designed during the Bush administration. It probably was. That’s not an insult — it’s a plain HTML table with host IPs, byte counts, and sparklines. Loads in 200ms. Works without JavaScript. You can curl it and grep the output if you want. The aesthetic is “sysadmin tool from 2003 that still works in 2026.”
ntopng’s UI is a full dashboard — charts, traffic flows, a world map showing geolocated connections, per-host timelines, alert tables. The community edition is polished. It auto-refreshes. There’s a search bar. You can drill from a country code down to a specific flow in three clicks.
If you need to hand a network report to someone who is not you, ntopng. If you just need to squint at top talkers at 2 AM, darkstat loads faster than ntopng’s React app initializes.
History and Retention
darkstat keeps counters in memory. If the process restarts, the counters reset. The --daylog option writes a daily traffic summary to a file for rough trending, but there’s no queryable history beyond “bytes since daemon start.”
ntopng stores flows in Redis (community edition) and SQLite/MySQL (Pro). You can query flows from the last 24 hours, 7 days, or whatever your retention window is. Historical drill-down is one of its most useful features — you can pull up yesterday’s 10pm traffic spike and see exactly which host connected to which destination.
Resource Usage Summary
| Metric | darkstat | ntopng (community) |
|---|---|---|
| RAM (idle, Pi 4) | ~10 MB | ~150–200 MB + Redis |
| CPU (moderate traffic) | < 1% | 5–15% |
| Disk | Negligible | Redis + SQLite (grows with retention) |
| Dependencies | libpcap | Redis, nDPI, GeoIP |
| Install time | 30 seconds | 5–10 minutes |
Layering Into a Wider Stack
darkstat and ntopng sit in the middle of a monitoring hierarchy:
- Below them:
iftop,nethogs,ss -tunp— per-process or per-connection spot checks from the command line - At their level: darkstat (always-on lightweight), ntopng (periodic deep investigation)
- Above them: Prometheus + node_exporter + Grafana for long-term bandwidth trending at the machine level; Loki + Promtail for log correlation
- Packet-level: Wireshark /
tcpdumpwhen you need to see the actual bytes and ntopng’s L7 classification isn’t enough
A practical home-lab stack: darkstat running 24/7 on a Pi as a lightweight always-on watch, ntopng spun up via Docker Compose when something weird shows up in darkstat and you need to identify the actual application. You don’t need both running permanently unless you’re building a proper home NOC — and if you are, you probably already know this.
The Verdict
Pick darkstat if:
- You want “show me top talkers” on a Pi 4 without allocating 200 MB of RAM to the problem
- You don’t need flow history or application identification
- You want something running five minutes from now with zero config
- You need the stats page accessible from a shell with
curl
Pick ntopng if:
- You want application-level identification (is this Netflix or is this something weird?)
- Your router exports NetFlow and you want whole-network visibility without a span port
- You need flow history — not just “who’s busy now” but “who was busy three hours ago”
- You want alerts when a new device starts chatting with a sketchy IP
- You’re running OPNsense or pfSense and want the data to stay in one place
The real answer: run both. darkstat costs you nothing. Keep it on the same Pi you’re already running Pi-hole. When darkstat’s host table shows something unexpected, pull up ntopng to identify the actual application and correlation.
Your upload is still pegged. But now you’ll know it’s your NAS backup job, not a compromised IoT device — and that distinction matters at 2 AM when you’re deciding whether to fix it or go to bed.