Building a Multi-Node K3s Cluster on Proxmox VE

Welcome to the ultimate guide on setting up a self-hosted Kubernetes cluster in your homelab! For developers and data engineers alike, having a local sandbox that mirrors cloud-native production environments is game-changing.
In this article, we’ll walk through provisioning lightweight virtual machines on Proxmox VE, installing K3s (Rancher’s highly optimized, lightweight Kubernetes distribution), and setting up a basic LoadBalancer and StorageClass.
1. Why K3s and Proxmox VE?
- Proxmox VE provides enterprise-grade virtualization using QEMU/KVM and LXC containers, allowing you to maximize your homelab hardware resources.
- K3s packages Kubernetes into a single binary (< 100MB) that consumes a fraction of the memory of standard k8s (kubeadm), making it perfect for budget homelabs, NUCs, or cluster nodes.
2. Infrastructure Setup (Proxmox VMs)
We’ll deploy a 3-node cluster:
k3s-master(1 CPU, 2GB RAM, 20GB Disk)k3s-worker-1(2 CPU, 4GB RAM, 40GB Disk)k3s-worker-2(2 CPU, 4GB RAM, 40GB Disk)
We recommend using Debian 12 Bookworm or Ubuntu Server 22.04 LTS as the base OS. Ensure you assign static IPs or set DHCP reservations on your router.
# Example static IP allocations
192.168.1.150 k3s-master
192.168.1.151 k3s-worker-1
192.168.1.152 k3s-worker-2
3. Installing the Control Plane (Master Node)
SSH into k3s-master and run the installation script. We will disable the default Traefik ingress controller (so we can deploy our own Nginx Ingress or Cloudflare Tunnels later) and disable the default local-path storage if desired:
curl -sfL https://get.k3s.io | sh -s - \
--disable traefik \
--write-kubeconfig-mode 644
Once finished, verify that the control plane is active:
kubectl get nodes
# Output:
# NAME STATUS ROLES AGE VERSION
# k3s-master Ready control-plane,master 10s v1.28.2+k3s1
Now, retrieve the node token from /var/lib/rancher/k3s/server/node-token. You will need this to join the workers:
sudo cat /var/lib/rancher/k3s/server/node-token
# Save this long hash!
4. Joining the Worker Nodes
SSH into k3s-worker-1 and k3s-worker-2, then run the installation script with the token and master URL:
# Run this on both workers
export K3S_URL="https://192.168.1.150:6443"
export K3S_TOKEN="K10f...YOUR_TOKEN...e0a2"
curl -sfL https://get.k3s.io | K3S_URL=$K3S_URL K3S_TOKEN=$K3S_TOKEN sh -
Back on the master node, run:
kubectl get nodes
You should now see all 3 nodes marked as Ready!
5. Storage and Load Balancing
By default, K3s provides a local-path storage provider. For shared, persistent storage, you can set up Longhorn or mount NFS shares from your NAS.
For a LoadBalancer, K3s ships with Klipper, which works out of the box. However, if you want full Control Plane IPs, look into installing MetalLB:
# Add MetalLB repository
helm repo add metallb https://metallb.github.io/metallb
helm install metallb metallb/metallb --namespace metallb-system --create-namespace
6. What’s Next?
With your cluster up and running, you can now deploy:
- Prometheus & Grafana for monitoring your homelab infrastructure.
- Pi-hole / AdGuard Home for network-wide DNS filtering.
- Nextcloud or Jellyfin for media hosting.
Happy self-hosting!