Why this matters
It’s easy to add services to whichever node has an open LXC slot and never step back to check whether that’s actually where they should live. This audit was that step back, and the answer was uncomfortable.
The numbers
Node-A is the newest and by far the most capable box in the fleet: a 24-core/24-thread CPU, 64GB of DDR5, a discrete GPU passed through for inference work. It runs exactly two guests and idles around 3% CPU with roughly 40% of its memory unused.
Node-B, an 8-core APU with 64GB of RAM, carries the actual weight: 12 guests, RAM committed enough that several of them are running memory-tight, though CPU stays idle.
Node-C is the oldest hardware in the cluster, a 2017 quad-core with 32GB of RAM that can’t be expanded further. It runs 5 guests. Those 5 happen to include the DNS resolver for the entire network, the reverse proxy in front of every *.tima.dev service, and the SIEM. CPU-idle, technically fine on paper, but everything that would make a bad day catastrophic instead of just annoying lives here.
The actual problem
None of this is a performance issue today. Every node is running comfortably within its means. The problem is what happens on the day Node-C’s motherboard finally gives out: DNS resolution for the whole network, every reverse-proxied service, and the SIEM all go down in the same instant, on the single weakest and oldest piece of hardware in the fleet, while a 24-core GPU-equipped machine sits three feet away doing almost nothing.
That’s not a capacity problem. It’s a blast-radius problem. The node most likely to fail first is carrying the services least survivable to lose.
The direction
Superseded: the plan below changed. See the update at the end of this post.
The fix isn’t rebalancing for CPU or RAM headroom, there’s plenty of that everywhere. It’s rebalancing for consequence. The plan moves the RAM-heavy guests, particularly the domain controller and the agent workload that already depends on Tantive-III’s GPU, onto Node-A where there’s room and where colocating with the GPU it already talks to cuts out a network hop. Node-C gets no new load going forward, on purpose. And a second DNS resolver goes in elsewhere in the fleet, so DNS specifically stops being a single point of failure regardless of what else happens to Node-C.
The lesson
Workload placement decisions made one service at a time, whichever node had room at the time, tend to drift into something nobody would design on purpose. The fix isn’t a bigger box, it’s periodically asking which node would take the whole fleet down if it died today, and whether that’s actually the node you’d choose for that job if you were starting over.
Update, October 2026
The direction changed once live data replaced the documentation. Pulling current resource figures showed several RAM numbers in the runbook were wrong, and the capacity argument behind moving guests to Node-A didn’t hold. The case that did hold was blast radius: too many important guests on one node.
So the fix was a fourth node, not Node-A. Four guests moved to Node-D: the domain controller, Yavin-IV, Home Assistant, and Coruscant. Node-B dropped from twelve guests to eight, and Node-A stayed dedicated to the GPU and AI work. Node-C was left unchanged, and the second DNS resolver was deferred to the Raspberry Pi cluster project instead of being built twice. Node-C’s own network path got a second NIC in an active-backup bond. The full account is in A Fourth Node for Maintenance, Not Capacity.