A segmented home network built on used enterprise gear: a Cisco Catalyst 2960-X, OPNsense on a decommissioned OptiPlex, a Proxmox hypervisor, five VLANs with firewall rules between them, and remote access over a WireGuard mesh. Around $450 in hardware, most of it acquired during a DRAM shortage that made the usual advice wrong.
It works. Getting there involved a run of problems that presented as dead hardware and mostly weren't:
| What it looked like | What it was |
|---|---|
| Dead router | Stale DHCP lease on the modem |
| Dead console port | Charge-only USB cable, no data pins |
| Dead network card, returned as faulty | Motherboard quirk — RAM in the wrong slot |
| Broken Proxmox install | System clock five months off |
| Bricked access point | A documented default I hadn't read |
| Firewall rule breaking the network | Two interfaces holding the same IP |
One of those was genuinely dead. The other five cost more time than the real failure did.
The thread: the symptom is rarely where the fault is. Every one of these was found by working down the stack from the layer that was complaining rather than the layer that was broken — and in two cases, by reading vendor documentation I should have read first.
The default advice for a home lab is a prosumer ecosystem — UniFi or TP-Link Omada. Clean UI, single pane of glass, everything matched. I went the other way, for one reason: a managed Cisco switch lets you attack layer 2 and then defend it.
DHCP snooping, Dynamic ARP Inspection, IP Source Guard, port security, private VLANs, 802.1X. Those aren't just features to configure — they're a loop. Run ARP poisoning, watch it work, turn on DAI, watch it fail. A prosumer switch does VLANs and ACLs but doesn't give you that.
Timing also mattered. A global DRAM shortage had roughly tripled memory prices over a few months — 32GB DDR4 kits that ran $60–90 in late 2025 were $150–180 by early 2026, and DDR5 was hit harder. That inverts the usual build-versus-buy calculus. A barebones mini PC plus your own RAM stopped being the cheap option; used enterprise gear ships with its memory already installed at pre-shortage prices.
| Part | Source | Cost |
|---|---|---|
| 3 × Cisco WS-C2960X-48FPD-L | Used, bulk listing | $109 total |
| Dell OptiPlex 7060 SFF (OPNsense) | Used | ~$150 |
| Dell OptiPlex 7060 SFF (Proxmox) | Used, i7 | $90 |
| Intel i350-T4 quad NIC | Used | ~$35 |
| TP-Link EAP720 (Wi-Fi 7 AP) | New | $90 |
Three 48-port PoE switches for $109 is roughly $36 each against a used market of $80–150. The catch is running cost, not purchase price: at ~60W idle each, running all three continuously works out to about $220/year in electricity — the hardware pays for itself in power every six months. So one runs as the daily driver and the others come up only for multi-switch topology work, which is the situation that makes STP root election and inter-switch VLAN hopping worth practicing rather than reading about.
Five VLANs, routed and filtered by OPNsense:
| VLAN | Purpose |
|---|---|
| 10 | Trusted — desktop, workstations |
| 20 | IoT |
| 30 | Lab — attack and victim machines |
| 40 | Wireless |
| 99 | Management — switch SVI, firewall, hypervisor, AP |
| 999 | Blackhole — unused ports, shut |
Two hygiene decisions made at the start rather than retrofitted:
Nothing on VLAN 1. It's the default everything lands on, and leaving it populated makes a whole class of misconfiguration invisible.
Unused ports shut and parked in a dead VLAN. A cable in an unused port gets you nothing. The default — every port live in VLAN 1 — is the opposite posture.
Trunk native VLAN set to an unused, shut VLAN. Double-tagged VLAN hopping depends on the native VLAN being real. Building the defense in from the start means the attack can be demonstrated later by deliberately removing it, rather than discovering it's already possible.
Firewall rules are default-deny per segment with explicit exceptions, and the block rules log — which is half the point of segmentation. The logs are how you find the IoT device phoning home.
Before any of the real gear arrived, an old router "died." It hadn't — the cable modem was holding a DHCP lease bound to the previous device's MAC and refusing to hand out another. A full cold cycle with the new device already connected fixes it. Two minutes unplugged, not thirty seconds.
This recurred at every WAN-side change. It's now the first thing I check when a device that should have internet doesn't, and it's the reason the eventual modem bridge was scheduled as a deliberate evening rather than tacked onto the end of another task.
The 2960-X has a USB mini-B console port, which is convenient — no serial adapter, just a cable from a drawer. Except mini-B cables that shipped with cameras and external drives are frequently charge-only, with the data pins unpopulated. They look identical.
The switch enumerated nothing, Device Manager showed nothing, and the obvious conclusion was a driver problem. Cisco's USB console driver is genuinely awkward to find — it's filed under a generic software type that isn't reachable from the 2960-X product page, so people locate it via a different model's downloads entirely. I went a long way down that path before swapping cables.
The diagnostic that would have saved it: plug into a Linux box and watch dmesg. The
in-kernel CDC ACM driver binds the Cisco console without any download, so enumeration either
happens or it doesn't — and that single test separates "driver" from "cable" in about ten
seconds.
Moving OPNsense's management interface from the parent NIC onto a tagged VLAN child looked successful in the UI and broke connectivity completely. The web interface was unreachable, but so was ping — and yet ARP resolved, which shouldn't happen if nothing was answering.
That contradiction was the clue. ARP resolving means OPNsense received the frame and replied. Something was wrong with the return path, not the delivery.
netstat -rn | grep 10.0.99
ifconfig -a | grep 10.0.99
The route still pointed at the parent interface, and the address was bound to both interfaces. Inbound tagged frames were processed; replies went out untagged on the parent, into a trunk whose native VLAN was a blackhole. Clearing the stale alias moved the route and fixed it.
The lesson: ARP working while ICMP fails is a specific signature, not generic breakage. It means delivery works and return doesn't, which points at routing or interface binding rather than the firewall.
Four VLAN interfaces, configured and apparently working, were gone after a restart. OPNsense separates Save (writes the form) from Apply (commits to the running config), and the banner prompting for Apply is easy to miss. A saved-but-unapplied interface looks correct in the UI and doesn't persist.
The same class of problem bit Tailscale's subnet routes. They'd been set from the shell with
tailscale up --advertise-routes=..., which works immediately but isn't the plugin's
configuration. A service restart weeks later dropped them silently — remote access simply stopped
working, with the admin console still showing the routes as approved.
Both have the same shape: runtime state and saved configuration diverging, with no error and no symptom until a restart. Now I reboot after any significant config change specifically to find out, rather than discovering it three weeks later from somewhere I can't fix it.
Fresh Proxmox install, and the web interface rendered as a broken shell — no node in the tree, no
menus. The shell worked, and systemctl status pve-cluster showed the service healthy but
spewing RRD update errors: illegal attempt to update using time 1776110010 when last update time
is 1789567456.
The system clock was set to April. It was September. Every graph update was being rejected as arriving from the past, and TLS certificate validation — which the UI loads over — was equally unhappy.
timedatectl set-ntp true
Plus clearing the poisoned RRD data. The root cause was a dead CMOS battery on a decommissioned machine, which is worth checking on any used hardware before it causes something subtler.
The worst of them, and entirely self-inflicted.
The AP was reachable and working. I set a static IP on it, moved its management VLAN, and lost it — then reset it and repeated the same sequence twice more, each time concluding something different was wrong. At one point I was ready to send back working hardware.
The actual answer was in TP-Link's documentation the whole time: Layer-3 Accessibility, under Management → Web Server, disabled by default for safety reasons. With it off, only hosts on the AP's own subnet can reach the management page. Everything I'd been doing — reaching it from a routed VLAN — was blocked by a documented default I hadn't read.
The vendor guidance also specifies the order: enable Layer-3 Accessibility before configuring a management VLAN. Doing it the other way round locks you out, which is precisely what happened.
The rule I took from it: read the vendor documentation before changing management-plane settings on a device you can only reach over the network. There's no console cable on an access point. If the setting that governs remote management is the setting you're changing, you get exactly one attempt.
The Proxmox host wouldn't POST with an Intel i350 installed. Amber LED code 2,7 — which Dell's table for that generation documents as a memory failure. Reseating RAM didn't help, removing the card did, so the card was clearly bad.
It wasn't. The OptiPlex 7060 has a documented quirk: it will not POST with a multi-port NIC installed while DIMM slot 4 is populated. Others have reported it with Intel X710 and Broadcom quad-port cards, same LED code, and on equivalent HP models. No BIOS update fixes it. Moving one DIMM from slot 4 to slot 3 resolved it with no memory lost.
A previous i350 had already been returned as defective on the same symptom. It was almost certainly fine.
Read the docs for management-plane changes first. Two of the six problems were documented defaults or documented quirks. Both were findable in a single search, and both cost an evening because I diagnosed before I read.
Prefer DHCP reservations over static addresses on anything whose management interface you reach over the network. A reservation lives in one place you can edit from a machine that still works. A static lives on the device, and if it's wrong, you've lost your way in.
Reboot after config changes, deliberately. Runtime state and saved config diverging is a silent failure class, and the only cheap way to catch it is to force the question immediately.
Assume the symptom is at the wrong layer. ARP resolving while ping fails. A clean log while generation fails. A memory error code caused by a PCIe card. Working down from the complaining layer rather than fixating on it was what actually resolved every one of these.