LXC 129 network is the home for the lab's network visibility and protection tools. Created 2026-10-06 (see IP Plan for the address map this was built to support).
| Tool | What it does | URL |
|---|---|---|
| LAN Orangutan (v3.3.8, native) | Labeled device inventory: scans 192.168.86.0/24 + Dad's house 192.168.30.0/24, lists Tailscale peers, CSV/JSON export. Table UI, not a map |
http://192.168.86.225:291 |
| Scanopy (v0.17.22: server + Postgres in Docker, daemons native) | Auto-drawn network diagrams (L3 subnets, workloads, applications); SVG/Mermaid export. Covers both sites, Home 192.168.86.0/24 and Dad's house 192.168.30.0/24; every host is named and tagged (see Configuration) |
http://192.168.86.225:60072 |
| Smokeping (Docker) | Latency + packet-loss graphs: router, extender, 3 nodes, key service LXCs, internet DNS, Dad's house. Alerts via ntfy | http://192.168.86.225:8081/smokeping/ |
| OpenCanary (Docker) | Tripwire honeypot: fake FTP/Telnet/HTTP/MySQL/Redis/RDP/VNC/MSSQL services. Any touch alerts via ntfy | decoys on .225 (not a UI) |
| Pi-hole v6 (native) | DNS filtering + Local DNS for *.codycodez.com -> NPM. Built and tested, not yet the household resolver |
http://192.168.86.225:8082/admin |
Everything is LAN/Tailscale-only (no public NPM hosts). Alerts go to the existing ntfy topic homelab-alerts.
Shows what is on the network and when something stops answering or touches a decoy. If this LXC is down, nothing else breaks. The one exception is after the Pi-hole DNS cutover: if the router hands out .225 as the only DNS server, name resolution for the whole house depends on this LXC (see Pi-hole cutover below).
| Field | Value |
|---|---|
| Hostname | network |
| VMID / Type | 129, LXC, unprivileged (nesting=1,keyctl=1) |
| Proxmox Node | SuperPC (created on NAS, now runs on SuperPC) |
| IP Address | 192.168.86.225/24 (gw .1) |
| Tailscale IP | 100.116.29.4 (--accept-routes --accept-dns=false) |
| OS | Debian 13 |
| CPU / RAM | 2 cores / 4 GiB / 1 GiB swap |
| Storage | rootfs ceph-storage:vm-129-disk-0 16 GiB; bind mount /mnt/pve/cephfs/network -> /opt/network |
.1): ARP/DHCP neighborhood being scanned.hanna-household subnet route: reaches Dad's house 192.168.30.0/24 (this LXC has accept-routes on). hanna-household also runs the Scanopy daemon for that site and polls this LXC's Scanopy server over Tailscale (100.116.29.4:60072).192.168.86.202:8080: alert delivery (OpenCanary forwarder, Smokeping).| Port | Protocol | Purpose | Exposed to |
|---|---|---|---|
| 22 | tcp | sshd (real) | LAN |
| 53 | tcp+udp | Pi-hole DNS | LAN (not yet used by clients) |
| 291 | tcp | LAN Orangutan | LAN/Tailscale |
| 8081 | tcp | Smokeping | LAN/Tailscale |
| 8082 | tcp | Pi-hole admin (/admin) |
LAN/Tailscale |
| 60072 | tcp | Scanopy UI/API | LAN/Tailscale |
| 60073 | tcp | Scanopy daemon API (host network) | LAN (see Known Issues) |
| 21, 23, 80, 1433, 3306, 3389, 5900, 6379 | tcp | OpenCanary decoys, not real services; any connection alerts | LAN |
/etc/lan-orangutan/config.ini (original kept as config.ini.orig): extra network 192.168.30.0/24, exclude_networks = 172.16.0.0/12 (Docker bridges), scan every 900 s, service detection on. Data in /var/lib/lan-orangutan. Service lan-orangutan./opt/network/scanopy/docker-compose.yml (upstream file minus the bundled "integrated" daemon; upstream original kept as docker-compose.upstream.yml). .env (mode 600) holds the generated Postgres password.scanopy-daemon-home on this LXC (systemctl status scanopy-daemon, config /etc/scanopy/daemon/scanopy-daemon/config.json, directory mode 700) scans 192.168.86.0/24; scanopy-daemon-dads-house on hanna-household (same paths; its server_url is the Tailscale address because Dad's house cannot reach 192.168.86.225) scans 192.168.30.0/24. Scans: home Sun/Tue/Thu/Sat 06:00 America/New_York, Dad's house Sundays 00:00 UTC.Home or Dad's House). Scanopy allows only one role ("Application" group) tag per host and rejects edits to a host that has two; the Site tags live in a separate named group so they don't clash. Services carry their own role tags (decoys = Honeypot, Pi-hole = DNS/Ad Blocking, Ollama = AI). Hosts tagged Unidentified are the ones still to name./opt/network/scanopy/backups/*.sql (manual pg_dump, taken before each upgrade or bulk edit; on cephfs, not in vzdump)./opt/network/addons/docker-compose.yml. Smokeping config in addons/smokeping/config/ (Targets, Alerts, Database = 60 s step x 10 pings; ntfy-alert.sh). OpenCanary config addons/opencanary/opencanary.conf (real SSH decoy is off because sshd owns :22; ip.ignorelist skips the LXC itself and Docker gateways). addons/forwarder/forward.sh tails the OpenCanary JSON log -> ntfy, one alert per source IP per 10 minutes./etc/pihole/pihole.toml (web port 8082, upstreams 1.1.1.1 + 8.8.8.8, Local DNS in dns.hosts). Local records -> 192.168.86.201 (NPM): auth, blog, frigate, homepage, immich, jellyfin, n8n, odysseus, project, storj, ntfy, email (.codycodez.com) and email.hanna.properties. Deliberately not overridden: mail.* (go straight to Stalwart) and www (Vercel)./opt/network/ntfy.env (mode 600; URL, topic homelab-alerts, token). Helper: /opt/network/bin/ntfy-send "Title" "message" [prio] [tags].pct exec: /usr/local/bin/orangutan, /usr/local/bin/pihole (not on PATH there).SCANOPY_DISABLE_REGISTRATION=true in /opt/network/scanopy/.env (not set). Daemon API keys are shown only once in the Create Daemon wizard and stored hashed on the server./opt/network/secrets/pihole-admin.pw (mode 600). Read it with pct exec 129 -- cat /opt/network/secrets/pihole-admin.pw (run on the NAS node); change it with pihole setpassword.cody user's token. A dedicated write-only user (like n8n-publisher) would be tidier; swap the token in ntfy.env.LXC 129 is in the weekly vzdump job backup-0343c483-22ec (Sun 06:00 -> backup-storage; the job lists VMIDs explicitly) and its first backup ran 2026-10-11. Note Proxmox never backs up bind-mount paths: /opt/network (compose files, Smokeping RRDs, secrets) is not in vzdump; the rootfs is (Scanopy Postgres volume, Orangutan data, /etc/pihole). Everything under /opt/network is reproducible from this page except the secrets and Smokeping history.
# Docker stacks (run inside the LXC)
# Scanopy: back up first, update the SERVER first, then the daemons. Server and daemons must be on the same version
# (a newer daemon is rejected by an older server with "missing field network_id").
cd /opt/network/scanopy && docker exec scanopy-postgres-1 pg_dump -U postgres scanopy > backups/scanopy-$(date +%F).sql
cd /opt/network/scanopy && docker compose pull && docker compose up -d
# then each daemon host (this LXC, and hanna-household): re-run the install script's download step so /usr/local/bin/scanopy-daemon
# is the latest release (untested), and `systemctl restart scanopy-daemon`; check versions with the Daemons table in the Scanopy UI
cd /opt/network/addons && docker compose pull && docker compose build --pull && docker compose up -d
# Pi-hole
pihole -up
# LAN Orangutan: download the new .deb from github.com/291-Group/LAN-Orangutan/releases,
# verify against SHA256SUMS.txt (sha256sum -c), then: apt install ./lan-orangutan_<ver>_amd64.deb
OS security updates: unattended-upgrades is enabled.
Smokeping watches the network from here (router, extender, nodes, key service LXCs, the four Apartment cameras, smart plugs, internet DNS and Dad's house; cameras and hosts alert, plugs only graph). Uptime Kuma has six monitors for this LXC, added 2026-10-10 and all UP: Network Tools - Ping, LAN Orangutan - Local, Scanopy - Local, Smokeping - Local, Pi-hole - Admin, Pi-hole - DNS (resolves auth.codycodez.com through .225). They have no notification channel attached, matching the existing monitors. OpenCanary and Smokeping alerts arrive on ntfy topic homelab-alerts.
:60073) listens on all interfaces because it runs on host networking, so it is reachable from the LAN. Its authentication behavior was not verified; if that matters, block :60073 from everything except localhost/Docker with an in-LXC firewall rule.:80 on .225 (fake NAS login page), so Pi-hole's UI is on :8082.GET / (no User-Agent, Host: 192.168.86.225) every 6 hours at about :30 UTC that arrives from the home WAN IP 72.81.141.19 (so it was NAT-translated by the Fios router). Identified 2026-10-11 as the Fios router itself: a packet capture (/opt/network/capture/wan-src-80.pcap) showed the router's own MAC (78:67:0e:45:51:a6) as the Ethernet source, an IP TTL of 64 (not decremented, so not forwarded from a LAN device) and a minimal request (GET /, Host: 192.168.86.225:80, Content-Length: 0, no User-Agent): most likely its periodic device-identification probe, sent from its WAN address. Harmless. 72.81.141.19 is in the forwarder's IGNORE_SRC (alerts only; OpenCanary still logs it). If the ISP changes the WAN IP the alerts return: update IGNORE_SRC in addons/docker-compose.yml.nmap found 40 hosts and arp-scan 38 from inside the LXC, against 39 from the Proxmox host (differences are just devices coming and going).| Symptom | Check | Fix |
|---|---|---|
| Orangutan shows nothing for 30.x | tailscale status, ping 192.168.30.1 from the LXC |
tailscale up --accept-routes --accept-dns=false --hostname=network |
Scanopy daemon registration rejected (missing field network_id / site_id) |
Daemon and server on different versions: scanopy-daemon --version vs the Daemons table |
Update the server first (docker compose pull && up -d), then the daemon |
| Scanopy daemon "site_id not configured" / "waiting for /api/initialize" | An integrated container daemon that lost its identity | Replace it with a native daemon from the Create Daemon wizard (paste the command yourself; the key is shown once) |
| Dad's house daemon cannot connect | journalctl -u scanopy-daemon on hanna-household; server_url in its config.json |
It must use http://100.116.29.4:60072 (Tailscale), not the LAN address |
| No ntfy alerts | /opt/network/bin/ntfy-send test test returns http 200? |
Check ntfy.env, ntfy LXC 127 (.202:8080) |
| Honeypot alert flood | docker logs canary-forwarder |
Add the noisy scanner IP to IGNORE_SRC in compose + ip.ignorelist |
| Pi-hole not answering | systemctl status pihole-FTL, ss -lntup | grep :53 |
systemctl restart pihole-FTL |
# from the NAS node
pct enter 129
pct exec 129 -- docker compose -f /opt/network/addons/docker-compose.yml ps
pct exec 129 -- docker logs --tail 20 canary-forwarder
pct exec 129 -- /opt/network/bin/ntfy-send "test" "hello" 3
pct exec 129 -- /usr/local/bin/pihole status
dig @192.168.86.225 auth.codycodez.com +short # -> 192.168.86.201
Pi-hole answers correctly but no device uses it yet. Test with one device first: set that device's DNS manually to 192.168.86.225, then browse and check the Pi-hole query log. When happy, set the DNS handed out by the Fios router to 192.168.86.225 (the router menu has Network Settings -> DNS Server and IPv4 Address Distribution; check which one controls what DHCP hands out). Consider a secondary DNS so the house still resolves if this LXC is down, knowing that some queries will then bypass filtering. Rollback: restore the router's default DNS.
| Date | Change |
|---|---|
| 2026-10-06 | LXC 129 created on NAS. Installed LAN Orangutan 3.3.8, Scanopy 0.17.21, Smokeping, OpenCanary + ntfy forwarder, Pi-hole 6.4.3. Tailscale joined with accept-routes. Wiki IP plan rebuilt. |
| 2026-10-10 | Cameras (.90-.93) and smart plugs (.86-.89) added to Smokeping and the IP plan. Honeypot: the WAN-IP source silenced for alerts (logging kept). Uptime Kuma monitors added. Scanopy server upgraded 0.17.21 -> 0.17.22 (to match the latest daemon); native daemon installed on hanna-household for Dad's house; all hosts named and tagged (role + site tags). |
| 2026-10-11 | The bundled Scanopy daemon (identity lost in the upgrade) replaced by a native scanopy-daemon-home with its old scan schedule; stale daemon entry, placeholder host and unused credentials removed; compose file trimmed to server + Postgres. LXC 129 now on SuperPC; first vzdump backup ran. |