Setting Up a Homelab - Part 1: Proxmox and a Talos Linux Kubernetes Cluster
- Intro
- Hardware
- What you’ll need
- Installing Proxmox VE
- Getting Talos Linux ready
- Creating the VMs
- Bootstrapping the Kubernetes cluster
- If something goes wrong
- What’s next
Intro
I’ve wanted a proper homelab for a long time. Somewhere I can break things without worrying about a cloud bill, or about messing something up at work. Over time I’ve ended up with a small pile of machines at home, and I finally decided to put them to real use.
This is the first post in a series where I write down how the whole thing comes together. I’ll start with the hardware I have, and then get into the one machine that’s actually doing something right now: a Dell OptiPlex 7070 running Proxmox, with a small Kubernetes cluster on top of it. In this part I’ll go through:
- The hardware, and what each piece does (or will do)
- Installing Proxmox VE on the OptiPlex 7070
- Creating two VMs, one for a Kubernetes control plane (master) node and one for a worker node
- Installing Talos Linux on both and bootstrapping the cluster
So why Talos? It’s a small, locked-down Linux distribution that exists only to run Kubernetes. There’s no SSH, no shell and no package manager. You manage everything through an API with a CLI called talosctl. I’ll admit that sounded a bit scary to me at first. But the more I thought about it, the more I liked it: there’s very little to configure, very little to patch, and not much I can accidentally break. That’s exactly what I want from something I don’t want to babysit.
Hardware
My homelab is a bit of a mixed bag. Here’s everything I have right now:
| Device | CPU | RAM | What it does right now |
|---|---|---|---|
| Dell OptiPlex 7070 | Intel Core i5-9500 (9th gen, 6 cores) | 24 GB | Proxmox, running the Kubernetes master and worker |
| Dell OptiPlex 7050 (×2) | Intel Core i5 (7th gen) | 24 GB each | Nothing yet, more on these in part 2 |
| Old desktop PC | Intel Core i5-2400 (upgrading to an i7-3770) | 32 GB | Nothing yet, also part 2 |
| Raspberry Pi 1 Model B (2011.12 board) | Single-core ARM11 | 512 MB | Pi-hole, my DNS resolver and ad blocker |
| Raspberry Pi 5 | Quad-core Arm | 8 GB | Home Assistant |
The OptiPlex 7070
For now, this is the only machine with Proxmox on it, and it’s where the Kubernetes cluster lives. It’s small, quiet and doesn’t use much power, which matters when something is going to run 24/7.
24 GB of RAM turns out to be plenty for a two-node cluster. This is how I split it up:
| VM | vCPU | RAM | Disk |
|---|---|---|---|
| talos-cp-01 | 2 | 4 GB | 20 GB |
| talos-wk-01 | 4 | 8 GB | 50 GB |
| Proxmox host | - | ~2 GB | - |
That still leaves around 10 GB free, so there’s room to try other things later.
The two Raspberry Pis
The old Raspberry Pi 1, a Model B with “2011.12” printed on the board, is the DNS server for the whole house. It runs Pi-hole, which answers DNS queries for everything on the network and blocks ads and trackers along the way. It’s been doing that job quietly for a long time.
The problem is that it’s old, and it runs off an SD card. SD cards don’t love constant writes, and one could die on me any day. When that happens, DNS goes down, and from the point of view of everyone else at home, “the internet is broken”.
The Raspberry Pi 5 runs Home Assistant. Home Assistant can run add-ons, and there’s one for Pi-hole. So the plan is to run a second Pi-hole on the Pi 5, right next to Home Assistant, and give both Pis out as DNS servers on the network. If the old Pi gives up one day, the Pi 5 keeps things running while I sort out a replacement.
The rest: two OptiPlex 7050s and an old desktop
The two OptiPlex 7050s and the old desktop aren’t doing anything yet. Between them there’s a lot of CPU and 80 GB of RAM sitting around, so they definitely won’t stay idle for long. The desktop is due for a CPU upgrade from the i5-2400 to an i7-3770 first. Both chips use the same socket (LGA 1155), so if the motherboard’s BIOS supports it, it should be a straight swap. I’ll get into what I’m doing with all three in part 2.
What you’ll need
If you want to follow along with the Proxmox and Talos setup, you’ll need:
- A USB stick (8 GB or bigger) for the Proxmox installer
- A monitor and keyboard, just for the first install
- A laptop or desktop on the same network, with
kubectlinstalled - Two free IP addresses on your network for the Talos VMs. It’s worth setting up DHCP reservations for them in your router, so they don’t move around.
Installing Proxmox VE
Step 1: Sort out the BIOS
Before installing anything, press F2 while the OptiPlex boots to get into the BIOS setup, and check these settings:
- Virtualization Support → Virtualization: Enabled (Intel VT-x)
- Virtualization Support → VT for Direct I/O: Enabled (VT-d). You’ll want this later if you ever pass a device through to a VM.
- Storage → SATA/NVMe Operation: set it to AHCI/NVMe, not RAID On. A lot of OptiPlexes ship with RAID On, and with that setting the Proxmox installer might not see your NVMe drive at all.
- Power Management → AC Recovery: set it to Power On, so the machine turns itself back on after a power cut.
Save and exit.
Step 2: Make a bootable USB stick
Grab the latest Proxmox VE ISO Installer from the Proxmox downloads page. Then write it to the USB stick with balenaEtcher, Rufus, or dd if you’re on Linux:
# Replace /dev/sdX with your USB stick. Double-check it, dd will happily wipe the wrong disk!
sudo dd if=proxmox-ve_*.iso of=/dev/sdX bs=4M status=progress conv=fsyncStep 3: Install Proxmox
Plug the USB stick into the OptiPlex, turn it on and press F12 for the one-time boot menu. Pick the USB stick, then Install Proxmox VE (Graphical).
The installer is pretty painless:
- Target disk: your NVMe SSD. The default
ext4is fine for a single disk.ZFS (RAID0)gets you snapshots and compression, but ZFS likes to use a good chunk of RAM for caching, so keep that in mind. - Country, timezone and keyboard: whatever matches where you are
- Password and email: this is the root password for the web UI and SSH
- Management network:
- Hostname (FQDN): something like
pve.home.lan - IP address: a static IP outside your router’s DHCP range, e.g.
192.168.1.10/24 - Gateway: your router, e.g.
192.168.1.1 - DNS: your router, your Pi-hole, or a public resolver
- Hostname (FQDN): something like
Once it’s done, pull the USB stick out and let it reboot. You won’t need the monitor and keyboard anymore. Everything from here happens from your laptop at:
https://192.168.1.10:8006Log in as root with the Linux PAM realm. You’ll see a certificate warning and a “No valid subscription” pop-up. Both are normal, so don’t worry about them.
Step 4: Switch to the free update repository
Out of the box, Proxmox gets its updates from the enterprise repository, which needs a paid subscription. For a homelab, the free no-subscription repository is all you need:
- In the web UI, click your node, then Updates → Repositories
- Select the
pve-enterpriseentry and click Disable. Do the same for the enterprisecephentry. - Click Add, choose No-Subscription, then Add
Then update everything from the node’s Shell:
apt update && apt full-upgrade -y
rebootThat’s it, Proxmox is ready for some VMs.
Getting Talos Linux ready
Step 1: Build an image with the QEMU guest agent
Since Talos has no package manager, anything extra has to be baked into the image itself. Talos calls these system extensions. On Proxmox you want the QEMU guest agent, so Proxmox can see each VM’s IP address and shut it down cleanly.
Head over to the Talos Image Factory and:
- Pick Bare-metal Machine
- Pick the latest Talos version
- Choose amd64
- Under system extensions, select
siderolabs/qemu-guest-agent - Click through the rest with the defaults
At the end you’ll get two things you need:
- A link to the ISO (
metal-amd64.iso) - The installer image, which looks like
factory.talos.dev/installer/<schematic-id>:<version>. Copy this somewhere safe. You’ll need it later so the guest agent is still there after Talos installs itself to disk.
Step 2: Get the ISO into Proxmox
In Proxmox, go to local (pve) → ISO Images → Download from URL, paste the ISO link from the Image Factory, click Query URL and then Download.
Step 3: Install talosctl on your laptop
# Linux / macOS
curl -sL https://talos.dev/install | sh
# or with Homebrew
brew install siderolabs/tap/talosctlMake sure your talosctl version matches the Talos version you picked in the Image Factory.
Creating the VMs
Create two VMs with the Create VM button in the top right of the Proxmox UI. Talos is fussy about a few settings, so here’s what I used:
| Tab | Setting | Value |
|---|---|---|
| General | Name | talos-cp-01 / talos-wk-01 |
| OS | ISO image | the Talos metal-amd64.iso |
| OS | Guest OS | Linux, 6.x - 2.6 Kernel |
| System | Qemu Agent | ✅ Enabled |
| System | SCSI Controller | VirtIO SCSI single |
| Disks | Size | 20 GB (control plane) / 50 GB (worker) |
| Disks | Discard / IO thread | ✅ / ✅ |
| CPU | Cores | 2 (control plane) / 4 (worker) |
| CPU | Type | host |
| Memory | Memory | 4096 MB (control plane) / 8192 MB (worker) |
| Memory | Ballooning Device | ❌ Disabled |
| Network | Model | VirtIO (paravirtualized), bridge vmbr0 |
Two of these really matter:
- CPU type = host: newer Talos releases need CPU features (x86-64-v2) that the old default
kvm64CPU type doesn’t have. Leave it onkvm64and the VM might not boot, or might crash early. - Ballooning off: Kubernetes expects its memory to stay put, and Talos doesn’t support memory hot-plug. Give each VM a fixed amount and leave it at that.
Start both VMs. Each one boots the Talos ISO into maintenance mode and shows a little dashboard on the Proxmox console, with its IP address on it. Write both IPs down. For the rest of this post I’ll use:
- Control plane:
192.168.1.21 - Worker:
192.168.1.22
If you’re setting up DHCP reservations for the VMs (you can find their MAC addresses under Hardware → Network Device), reboot them now so they pick up the right IPs.
Bootstrapping the Kubernetes cluster
Step 1: Check the install disk
Talos is still running from the ISO at this point, so it needs to be told which disk to install to. In maintenance mode it’ll answer questions without any credentials, so you can just ask it:
talosctl get disks --insecure --nodes 192.168.1.21With the VirtIO SCSI controller, the VM’s disk shows up as /dev/sda.
Step 2: Generate the machine configs
I like to set a few variables first so the commands are easier to read. Then generate the configs, using the installer image from the Image Factory instead of the default one:
export CLUSTER_NAME=homelab
export CP_IP=192.168.1.21
export WORKER_IP=192.168.1.22
export INSTALL_IMAGE=factory.talos.dev/installer/<schematic-id>:<version>
mkdir -p ~/homelab/talos && cd ~/homelab/talos
talosctl gen config $CLUSTER_NAME https://$CP_IP:6443 \
--install-disk /dev/sda \
--install-image $INSTALL_IMAGEYou’ll end up with three files:
controlplane.yaml: the config for the control plane nodeworker.yaml: the config for worker nodestalosconfig: the credentialstalosctluses to talk to your cluster
These files hold your cluster’s secrets and certificates. Keep them somewhere safe, like a password manager or an encrypted backup, and please don’t commit them to a public git repo.
Step 3: Apply the configs
Send each node its config. You only need --insecure this one time, because the nodes are still in maintenance mode and don’t have any certificates yet:
talosctl apply-config --insecure --nodes $CP_IP --file controlplane.yaml
talosctl apply-config --insecure --nodes $WORKER_IP --file worker.yamlEach node installs Talos to /dev/sda and reboots. Once that’s done, go to Hardware → CD/DVD Drive for each VM in Proxmox and set it to Do not use any media, so they boot from the disk from now on.
Step 4: Point talosctl at the cluster
export TALOSCONFIG=~/homelab/talos/talosconfig
talosctl config endpoint $CP_IP
talosctl config node $CP_IPStep 5: Bootstrap etcd
This is the step that’s easiest to forget. The control plane won’t start Kubernetes until you tell it to bootstrap etcd. Run this once, against one control plane node:
talosctl bootstrapThen watch it come up. I really like Talos’s live dashboard for this:
talosctl dashboardGive it a few minutes, then check that everything is healthy:
talosctl healthStep 6: Grab the kubeconfig
talosctl kubeconfig ~/.kube/config --merge
kubectl get nodes -o wideYou should see both nodes, and both should be Ready:
NAME STATUS ROLES AGE VERSION
talos-cp-01 Ready control-plane 6m v1.x.x
talos-wk-01 Ready <none> 5m v1.x.xFor a quick sanity check, run something on the worker:
kubectl create deployment hello --image=nginx
kubectl get pods -o wideThe pod should land on talos-wk-01. By default the control plane node has a taint that keeps regular workloads off it. Clean up with kubectl delete deployment hello when you’re done.
If something goes wrong
- The Proxmox installer doesn’t see the NVMe drive: change the BIOS storage mode from RAID On to AHCI/NVMe.
- A Talos VM crashes or hangs on boot: check that the CPU type is host and not
kvm64. apply-configtimes out: the node has probably picked up a different IP after rebooting. Check the Proxmox console for its current IP, and set up DHCP reservations so it doesn’t happen again.- A node boots back into maintenance mode after installing: the ISO is still attached and first in the boot order. Remove it from the CD/DVD drive.
kubectl get nodesjust hangs: you most likely skippedtalosctl bootstrap.- Proxmox can’t see the VM’s IP: the guest agent is missing. Check that you passed the Image Factory installer image to
gen config.
What’s next
So that’s part 1. The OptiPlex 7070 is running Proxmox, and on top of it there’s a two-node Kubernetes cluster on Talos. It’s small, but it works, and it’s a good base to build on.
In part 2 I’ll get into what I’m planning for the two OptiPlex 7050s and the old desktop, and walk through how my Kubernetes cluster is actually set up.
Thanks for reading! If you have questions or ideas, find me on twitter.
