21 March 2026

📌 Built a network monitoring setup tonight. Two LXC containers on Proxmox, ntopng for traffic analysis, ntfy for push notifications. Sakis Tolis in the headphones throughout.

The question was simple: who is on my network, and what are they doing? The router gives you a list. It does not give you behaviour, traffic patterns, or alerts when something new shows up.

proxmox

Proxmox CLI is the right way to do this. One command, everything set:

pct create 133 local:vztmpl/ubuntu-24.04-standard_24.04-2_amd64.tar.zst \
  --hostname netmon \
  --memory 1024 \
  --cores 2 \
  --net0 name=eth0,bridge=vmbr0,gw=192.168.0.101,ip=192.168.0.133/24,type=veth \
  --storage local \
  --rootfs local:8 \
  --nameserver 192.168.0.101 \
  --unprivileged 0 \
  --start 0

--unprivileged 0 is required for raw packet capture.

apparmor

Docker 28 on Ubuntu 24.04 inside a privileged LXC fails with this:

AppArmor enabled on system but the docker-default profile could not be loaded
apparmor_parser: Unable to replace "docker-default". Access denied.
error: exit status 243

The fix is two lines in /etc/pve/lxc/133.conf:

lxc.apparmor.profile: unconfined
lxc.mount.entry: /dev/null sys/module/apparmor/parameters/enabled none bind 0 0

The first relaxes the AppArmor profile. The second binds /dev/null over the file Docker reads to check if AppArmor is active - without it Docker still fails on every container start even with the profile set to unconfined. That's because of the new Ubuntu/Docker update. That's ok, I like security.

ntopng

Traffic analysis with a decent web UI. Community edition is free and covers everything a homelab needs. Runs with Redis as backend. The interface must be passed via command in compose - the config file gets ignored by the official container.

network_mode: host is not optional. ntopng needs to see the physical interface.

Active Network Discovery enabled - ARP scan + mDNS + SSDP every 15 minutes.

ntfy

Self-hosted push notification server. Android client on F-Droid, UnifiedPush support. No Firebase. No Google Services. Notifications arrive instantly with the app closed.

The auth-file directive in server.yml is required before you can create users. Without it the user management commands fail silently.

netwatch

A bash script on a 5-minute cron. arp-scan scans the local network, compares MACs against a whitelist, sends an ntfy alert if something unknown appears.

Two non-obvious details:

The arp-scan output includes summary lines starting with numbers. The right filter:

awk '/^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\t/ {print $1"\t"$2}'

Commented lines in the whitelist must be explicitly excluded, otherwise grep matches them:

if ! grep -v "^#" "$KNOWN" | grep -qi "$MAC"; then
    # unknown device - fire alert
fi

and then...

First scan showed a IoT device (Shenzhen Meigao Electronic Equipment) I didn't recognise at the first step. Check, double check, what aliases do I have in bashrc? Ah, here it is! It was local AI server (Mistral powered). Paranoia resolved in thirty seconds. The point stands. Without this setup it would have been a question mark indefinitely.