TL;DR
My production homelab runs on Lenovo M920q tinies, and I still think those are the sweet spot. But if I were starting over today with a tight budget, I’d buy a stack of government-surplus Dell OptiPlex 7060 and 7070 desktops instead. They go for around $150 each refurbished — 6-core 8th/9th-gen Intel, an SSD, and Windows 11 already on them — and they make excellent Kubernetes nodes with exactly two cheap upgrades: a bit more RAM and a second network card.
Three of them gets you an 18-core, 96 GB, all-SSD, x86 k3s cluster for about $600 all-in. No fan noise that matters, ~20 W idle per node, and none of the ARM surprises you hit with a pile of Raspberry Pis. Here’s the whole build.
Why surplus OptiPlex desktops
I’ve written before about why tiny enterprise PCs are the homelab sweet spot. Surplus full-size OptiPlex desktops are the same argument with the volume turned up: more DIMM slots, real PCIe expansion, and an even lower price because nobody wants a “boring beige business desktop.”
These come out of school districts, county offices, and university refreshes by the pallet. They were bought for reliability and managed in the thousands, which is exactly what you want in a node:
- x86, not ARM. Every Helm chart, every container image, every
amd64binary just works. I love a Pi, but I’ve lost enough evenings to “no arm64 image for this” that I now pay the small x86 premium on purpose. - 6 real cores. The 7060 ships a Core i7-8700 (6C/12T), the 7070 a Core i5-9500 (6C/6T). Either one runs a node’s worth of pods without breaking a sweat.
- An NVMe/SATA SSD already in it. No spinning rust, fast etcd, instant boots.
- vPro / AMT on most of them. 8th/9th-gen vPro means out-of-band remote management — power on, KVM, and BIOS access over the network on a headless box. This is the feature you don’t know you wanted until the first time a node wedges and you don’t have to walk over to it.
- It’s data-center-quiet and sips power. ~15–30 W idle. Three of them draw less than a single old rack server’s fans.
The catch is the spec they ship with: 8 GB of RAM and a single gigabit NIC. That’s the whole reason this is a build post and not a shopping link. Two parts fix it.
The machines I’m selling
I refurbish and test these in batches. The two models I have on the bench right now:
| Model | CPU | Form factor | RAM (stock) | Storage | OS |
|---|---|---|---|---|---|
| OptiPlex 7070 SFF | i5-9500 (6C) | Small form factor | 8 GB | 256 GB SSD | Win 11 |
| OptiPlex 7060 | i7-8700 (6C/12T) | Tower / SFF | 8 GB | 256–512 GB SSD | Win 11 |
Every unit is wiped, tested, and reloaded with a clean, activated Windows 11 off the embedded Dell license — which you’ll promptly blow away for Linux, but it proves the board, the storage, and the license are all healthy. If you want a few to follow this build, they’re in my store (local pickup around Philadelphia, or shipped).
Upgrade 1 — Memory
Stock 8 GB is fine for a single throwaway VM and miserable for a Kubernetes node once you’ve layered on the control plane, a CNI, an ingress controller, monitoring, and whatever you actually came here to run.
The good news: these are full-size desktops, so you get full DDR4 DIMMs, not the cramped laptop SO-DIMM situation. Both the 7060 and 7070, in tower and SFF, have:
- 4 DDR4 DIMM slots
- 64 GB maximum (4 × 16 GB)
- DDR4-2666 (2400/2666), non-ECC, dual-channel
My recommendation per node is 32 GB as two 16 GB sticks — it’s the value pick, runs in proper dual-channel, and leaves two slots open if you want to push to 64 GB later. Grab a 32 GB (2×16) DDR4-2666 desktop kit per machine, or a 64 GB (4×16) kit if you want it maxed from day one.
Two things to get right when you buy:
- UDIMM, not SO-DIMM. Desktop OptiPlex (SFF and tower) take full-length 288-pin DDR4 DIMMs. The Micro model is the one that uses laptop SO-DIMMs — don’t buy those for these.
- DDR4-2666 non-ECC. Faster kits will down-clock to 2666; that’s fine, just don’t overpay for 3200. ECC won’t post.
Installation is a tool-less side panel and four clips. Five-minute job.
Upgrade 2 — A second NIC
You can absolutely run a cluster on the single onboard NIC, and plenty of people do. But the one “card” I add to every node is a second network interface, and it’s the upgrade that makes the cluster feel intentional instead of improvised. Reasons I bother:
- A clean LoadBalancer story. I run MetalLB in L2 mode and like keeping service VIP traffic off the same interface as node/management traffic.
- Separating storage/replication traffic. If you run Longhorn or any replicated storage, giving it its own NIC keeps a rebuild from starving everything else.
- Bonding for redundancy if you’ve got the switch ports.
Get an Intel-based card and save yourself a driver fight — the igb/igc drivers are in-tree and Just Work on any Linux you’ll install here. A low-profile Intel 2.5GbE card is my default; a dual-port Intel gigabit card is the move if you want two extra ports for bonding.
One sizing gotcha: the SFF needs a low-profile bracket (most cards ship with both brackets in the box — check before you buy). The tower takes full-height cards with room to spare, which is the other reason I like the towers for this. There’s an open PCIe x16 and an x1 sitting empty on every one of these.
Optional third part if you’re feeling it: drop a 1 TB NVMe in the M.2 slot for Longhorn or local-path storage. Not required for the build — but the slot’s right there.
BIOS: five settings, done headless
Before you install anything, set the firmware up so these behave like servers instead of desktops. You can do this from the F2 BIOS menu, but if you’re doing three (or thirty) of them, Dell’s cctk (Command | Configure) lets you script it. The five that matter:
# Virtualization on (for Proxmox/VMs, or just good hygiene)
cctk --VirtualizationTechnology=Enable
cctk --VtForDirectIo=Enable
# Come back up by itself after a power blip — critical for headless
cctk --AcPwrRcvry=On
# Wake-on-LAN so you can power the fleet on remotely
cctk --WakeOnLan=LanOnly
# Boot straight off the SSD, no menu pauses
cctk --BootOrder=hdd
AcPwrRcvry=On is the one people forget. The default is “stay off after power loss,” which means a flicker takes your whole cluster down until you physically press buttons. Set it to On and the nodes self-heal after an outage.
If your distro of choice still wants legacy boot or trips on Secure Boot, toggle those here too — but modern Ubuntu/Debian boot fine UEFI + Secure Boot, so I leave them on.
Install k3s
Pick your base. I run Debian stable on cluster nodes — minimal, boring, stable, exactly what I want under Kubernetes. (If you’d rather virtualize and carve VMs, put Proxmox VE on instead and run k3s in guests; same idea, more flexibility, a little more overhead.)
On the node you want as the control plane:
curl -sfL https://get.k3s.io | sh -
# grab the join token
sudo cat /var/lib/rancher/k3s/server/node-token
On each of the other two, join them as agents:
curl -sfL https://get.k3s.io | \
K3S_URL=https://<control-plane-ip>:6443 \
K3S_TOKEN=<token-from-above> sh -
That’s a working three-node cluster. From your workstation:
kubectl get nodes -o wide
A couple of things I learned the hard way and wrote up separately — worth knowing before you scale this past three:
- The k3s installer overwrites the agent env file on every run, including upgrades. If you script joins, restore
K3S_URL/K3S_TOKENafter each install or you’ll spend an evening confused. - Disable the bits you’re replacing. I run MetalLB instead of klipper-lb and Traefik from my own manifests, so I install the server with
--disable servicelb --disable traefikand bring my own. Decide that on day one, not after.
For the second NIC, point MetalLB’s L2 pool at the subnet on that interface and your LoadBalancer services get real IPs on a network you actually chose.
What it costs
A representative 3-node build, maxed at the value tier:
| Part | Per node | × 3 |
|---|---|---|
| OptiPlex 7060/7070 (refurb, tested) | ~$150 | $450 |
| 32 GB DDR4-2666 (2×16) | ~$40 | $120 |
| Low-profile Intel NIC | ~$25 | $75 |
| Total | ~$215 | ~$645 |
For roughly $645 you get 18 cores / 36 threads, 96 GB RAM, three SSDs, and out-of-band management, drawing under 100 W for the whole cluster at idle. Compare that to a single mid-tier cloud VM’s monthly bill, or to a pile of Pis that’ll cost nearly as much once you add cases, PoE, and decent storage — and still can’t run half the images you’ll want. (I did the full on-prem-vs-cloud power-and-cost math here if you want the receipts.)
The honest caveats
I’m selling these, so let me be the one to tell you what they’re not:
- 8th/9th-gen, not current. Plenty for a homelab; not a render farm. The i7-8700 is genuinely quick, the i5-9500 is fine.
- DDR4, capped at 64 GB, non-ECC. If you need ECC or 128 GB+ per node, this isn’t your platform — go buy a real workstation and pay for it.
- Gigabit onboard. Hence the NIC. The PCIe slot gets you to 2.5/10GbE if you care.
- They’re used. That’s the entire value proposition. Buy from someone who actually tested them (cough), or budget for the one in five that needs a new fan or a reseat.
For a learning cluster, a homelab that runs real services, or a CI/build farm that doesn’t need to be pretty, this is the most performance-per-dollar I know of right now.
Get the hardware
If you want to follow this build, the tested OptiPlex 7060 and 7070 units are in my store — local pickup around Philadelphia or shipped, and I’ll throw in a keyboard and mouse if you ask. Grab three, add the RAM and a NIC from the links above, and you’ll have a cluster running by the end of the afternoon.
If you build one, I’d genuinely like to see it. kubectl get nodes screenshots welcome.