Kubernetes distributions built for general-purpose Linux still carry a lot of baggage: SSH daemons, package managers, shells, and a sprawling attack surface that has nothing to do with running containers. Talos Linux throws all of that away. It is an immutable, API-managed operating system designed for exactly one job — running Kubernetes — and it pairs unusually well with Proxmox VE, which already gives you the templating, cloning, and automation hooks to stand a cluster up in minutes instead of hours.
This guide walks through deploying a real, three-node (or larger) Kubernetes cluster on Proxmox VE using Talos Linux: preparing the image, configuring VMs correctly the first time (a few settings are non-negotiable or the node won't boot), generating machine configs, bootstrapping etcd, and scaling out control-plane and worker nodes with Proxmox's own cloning tools.
Why Talos Linux on Proxmox VE
Talos has no SSH server, no shell, and no package manager. Every configuration change goes through a gRPC API (talosctl) and is applied as an immutable machine config — either the whole node reconciles to the new state, or it doesn't apply at all. That has three practical consequences for a homelab or small production cluster running on Proxmox:
- Smaller attack surface. There's no shell to harden, no SSH keys to rotate, no package CVEs to patch individually — you just run new Talos/Kubernetes versions.
- Reproducibility. A machine config is a YAML file. Rebuilding a node (or an entire cluster) is "apply the config again," not "remember which packages I installed by hand."
- Proxmox-native scaling. Because there is no OS state to preserve per node, Proxmox's clone-from-template workflow maps almost perfectly onto adding Talos nodes — clone, boot, apply config, done.
The tradeoff is that everything is declarative and API-driven from the start, so this guide assumes basic comfort with YAML and the command line, but no prior Talos experience.
Prerequisites
- A working Proxmox VE 8.x or 9.x host or cluster, with a storage pool for VM disks and ISO/image uploads.
- Outbound internet access from the Proxmox host (to download the Talos image) and from the VMs (to pull container images).
- A workstation (Linux, macOS, or WSL) to run
talosctlandkubectl— these tools do not need to run on the Proxmox host itself. - At least three VMs' worth of headroom for a minimal HA control plane (2 vCPU / 4 GB RAM each is a safe minimum; 4 vCPU / 8 GB is more comfortable), plus however many worker nodes you plan to add.
- A free static IP (or DHCP reservation) per node, since Talos nodes are addressed directly by
talosctland Kubernetes.
Step 1: Build a Talos Image With the Image Factory
Talos ships a hosted Image Factory that lets you assemble a custom install image with only the system extensions you need — this matters on Proxmox because the stock Talos ISO does not include the QEMU guest agent, and you want that extension baked in so Proxmox can see the VM's IP address and report it correctly in the UI.
Visit factory.talos.dev and walk through the wizard:
- Choose the latest stable Talos version (1.x).
- Select the
qemu-guest-agentsystem extension. - Choose the ISO installer for the initial platform, targeted at
metal(this is correct for VMs, not just bare metal — Talos's "metal" platform simply means "no specific cloud provider"). - Copy the generated ISO download URL at the end of the wizard.
On the Proxmox host, download it straight into your ISO storage so you don't have to upload it through the browser:
cd /var/lib/vz/template/iso
wget -O talos-amd64.iso "<factory-generated-iso-url>"
If your ISO storage isn't the default local directory storage, adjust the path accordingly (check Datacenter → Storage for the content path).
Step 2: Create the First Control-Plane VM
Create the VM either through the Proxmox GUI or the CLI. The CLI version is reproducible and worth using even if you normally click through the wizard:
qm create 9000 \
--name talos-cp-1 \
--memory 4096 \
--cores 2 \
--cpu host \
--machine q35 \
--bios ovmf \
--efidisk0 local-lvm:1,efitype=4m,pre-enrolled-keys=0 \
--net0 virtio,bridge=vmbr0 \
--scsihw virtio-scsi-pci \
--scsi0 local-lvm:32 \
--ide2 local:iso/talos-amd64.iso,media=cdrom \
--boot order=scsi0 \
--agent enabled=1 \
--ostype l26
Three of these flags are not optional if you want a reliable boot:
--cpu host— Talos 1.x requires the x86-64-v2 microarchitecture baseline. Proxmox's defaultkvm64CPU type does not expose the necessary instruction set flags (it deliberately targets maximum migration compatibility over feature exposure), and Talos will fail to boot or panic early with the generic type. Setting the CPU type tohostpasses through your physical CPU's real flags. If you need to keep migration compatibility across dissimilar hardware in a cluster, use a custom CPU model that guarantees at least thex86-64-v2feature set rather than falling back tokvm64.virtiofor disk and network — Talos includes the VirtIO drivers in its kernel by default, and virtio devices are dramatically faster than emulated IDE/e1000 devices. There's no driver-injection step like there is for Windows; it works out of the box.--agent enabled=1together with theqemu-guest-agentextension from Step 1 — without both sides, Proxmox's summary tab won't show the VM's IP address, and features like graceful shutdown notifications won't work.
Boot the VM (qm start 9000) and open its console. Talos boots into a maintenance shell that prints its current network configuration — note the IP address; you'll need it in the next step.
Step 3: Generate Machine Configuration
Install talosctl on your workstation:
# Linux
curl -sL https://talos.dev/install | sh
# macOS (Homebrew)
brew install siderolabs/tap/talosctl
Decide on a cluster name and a virtual IP (VIP) that will float across control-plane nodes — this is Talos's built-in alternative to running a separate load balancer (HAProxy/keepalived) in front of the Kubernetes API. Pick an unused address on the same subnet as your VMs, e.g. 192.168.10.50.
Generate the base configs, pointing the cluster endpoint at the VIP rather than any single node's address:
talosctl gen config talos-proxmox-cluster https://192.168.10.50:6443 \
--output-dir _out
This produces three files in _out/: controlplane.yaml, worker.yaml, and talosconfig. Before applying, patch controlplane.yaml to add the VIP to the node's network interface. Create a patch file:
# cp-patch.yaml
machine:
network:
interfaces:
- interface: eth0
dhcp: true
vip:
ip: 192.168.10.50
If you'd rather use static addressing than DHCP (recommended for control-plane nodes), replace dhcp: true with an explicit addresses and routes block instead — static addressing avoids any dependency on DHCP lease renewal for nodes that etcd and the API server depend on.
Merge the patch when generating (or apply it at apply-time with --config-patch):
talosctl gen config talos-proxmox-cluster https://192.168.10.50:6443 \
--output-dir _out \
--config-patch-control-plane @cp-patch.yaml
Step 4: Apply Configuration and Bootstrap
With the first control-plane VM's maintenance-mode IP noted from Step 2, apply the config to it:
talosctl apply-config --insecure \
--nodes 192.168.10.11 \
--file _out/controlplane.yaml
The node reboots and reconciles to the declared state. Point talosctl at it going forward and bootstrap etcd — this only needs to run once, against the first control-plane node:
export TALOSCONFIG=_out/talosconfig
talosctl config endpoint 192.168.10.11
talosctl config node 192.168.10.11
talosctl bootstrap
After a minute or two, pull the kubeconfig:
talosctl kubeconfig .
kubectl --kubeconfig=./kubeconfig get nodes
You should see a single control-plane node in NotReady state — that's expected until a CNI is installed (Talos does not ship one by default). Install Flannel, Cilium, or your CNI of choice; Cilium in kube-proxy-replacement mode is a common pairing with Talos since Talos already runs without a traditional init system getting in the way.
Alternative: Skipping the ISO With the Nocloud Image
The ISO method above is the clearest way to understand what's happening, but it requires attaching a virtual CD-ROM and manually reading the maintenance-mode IP off the console for every single node — tedious once you're past three or four machines. The Image Factory also publishes a nocloud disk image that accepts cloud-init-style metadata, letting you inject network configuration and even a full machine config at first boot with no console interaction at all.
Download the qcow2 nocloud image instead of the ISO, then import it directly as a VM disk rather than booting from cdrom:
wget -O talos-nocloud-amd64.qcow2 "<factory-generated-nocloud-image-url>"
qm create 9001 --name talos-cp-2 --memory 4096 --cores 2 --cpu host \
--machine q35 --bios ovmf --efidisk0 local-lvm:1,efitype=4m,pre-enrolled-keys=0 \
--net0 virtio,bridge=vmbr0 --scsihw virtio-scsi-pci --ostype l26
qm importdisk 9001 talos-nocloud-amd64.qcow2 local-lvm
qm set 9001 --scsi0 local-lvm:vm-9001-disk-0 --boot order=scsi0
qm set 9001 --cicustom "user=local:snippets/talos-metadata.yaml"
The referenced snippet can carry a base64- or gzip-encoded machine config directly, so the VM comes up already configured instead of sitting in maintenance mode waiting for apply-config. This is the approach worth adopting once you're comfortable with the manual flow and want to script out an entire cluster (e.g., from Terraform) rather than clicking through node-by-node.
Installing a CNI
Talos deliberately ships with no CNI so you aren't locked into one. Cilium is a common choice because it can fully replace kube-proxy, which pairs well with Talos's minimal-surface philosophy. A basic install via Helm looks like:
helm repo add cilium https://helm.cilium.io/
helm install cilium cilium/cilium --version 1.16.0 \
--namespace kube-system \
--set kubeProxyReplacement=true \
--set k8sServiceHost=192.168.10.50 \
--set k8sServicePort=6443
Point k8sServiceHost at the same VIP used for the control plane so Cilium's agents can reach the API server even while a specific control-plane node is down. Once the Cilium pods report Running, the earlier NotReady nodes should flip to Ready within a minute or two.
Step 5: Add Control-Plane and Worker Nodes via Proxmox Cloning
Rather than repeating Step 2 by hand for every node, convert the first VM's disk into a reusable template once you've confirmed the base image boots correctly (before applying any config), or simply repeat the qm create command with new VM IDs and names for each additional node — Talos machine configs are per-node artifacts, so the underlying VM creation doesn't need to be "templated" the way a traditional Linux VM does.
For each additional control-plane node, create the VM (same hardware profile as Step 2, new VMID/name/MAC), boot it into Talos maintenance mode, note its temporary IP, and apply controlplane.yaml the same way:
talosctl apply-config --insecure \
--nodes 192.168.10.12 \
--file _out/controlplane.yaml
Do this for a third control-plane node (192.168.10.13) to get proper etcd quorum — Talos, like any etcd-backed control plane, needs an odd number of members (3 or 5) to tolerate a node failure without losing quorum. A two-node control plane offers no more fault tolerance than a single node.
For worker nodes, drop memory/CPU to whatever your workloads need, skip the VIP patch entirely, and apply worker.yaml instead:
talosctl apply-config --insecure \
--nodes 192.168.10.21 \
--file _out/worker.yaml
Register each new node's endpoint so talosctl can talk to the whole cluster:
talosctl config endpoint 192.168.10.11 192.168.10.12 192.168.10.13
Confirm everything joined correctly:
kubectl --kubeconfig=./kubeconfig get nodes -o wide
talosctl -n 192.168.10.11 etcd members
Storage: What Talos Doesn't Give You
Talos has no local package manager to install NFS clients, iSCSI initiators, or a CSI driver by hand — that's by design, and it means storage needs to be handled either through a CSI plugin deployed as a Kubernetes workload, or through Talos system extensions baked in at the Image Factory stage if a kernel module is required (iSCSI, for example, needs the extension added back in Step 1 if you plan to use it).
Two options work well on top of Proxmox-hosted Talos nodes:
- Longhorn — a Kubernetes-native distributed block storage CSI that only needs an
iscsi-toolsextension added to the Talos image, no host-level packages. - A Proxmox CSI driver — provisions Proxmox-backed virtual disks directly as Kubernetes PVs via the Proxmox API, letting Kubernetes pods consume storage from the same pools (ZFS, LVM-thin, Ceph) your other VMs use.
Pick based on whether you want storage replication handled inside Kubernetes (Longhorn) or delegated to Proxmox's own storage layer (Proxmox CSI, which is a thinner layer but ties pod storage to a specific Proxmox node unless the backing storage is shared, like Ceph or NFS).
Upgrading the Cluster
Talos and Kubernetes version upgrades are both handled through talosctl, not through a package manager, and both are designed to be done one node at a time with zero manual SSH involved:
# Upgrade Talos itself on a single node
talosctl upgrade --nodes 192.168.10.11 \
--image factory.talos.dev/installer/<schematic-id>:v1.x.x
# Upgrade the Kubernetes control plane version cluster-wide
talosctl upgrade-k8s --to 1.xx.x
talosctl upgrade cordons and drains the node, applies the new install image, reboots, and uncordons it automatically — repeat per node for a rolling upgrade with no downtime on a 3+ node control plane.
Troubleshooting
VM won't boot past the Talos splash screen / immediately panics
Almost always the CPU type. Confirm qm config <vmid> shows cpu: host (or a custom type guaranteeing x86-64-v2), not kvm64 or qemu64.
Proxmox summary tab shows no IP address for the VM
The qemu-guest-agent extension either wasn't included when building the image in the Factory, or --agent enabled=1 wasn't set on the VM. Both are required together; rebuild the image or edit the VM config (qm set <vmid> --agent enabled=1) and reboot.
talosctl commands time out or refuse to connect
Talos's API listens on TCP port 50000; confirm nothing between your workstation and the VM (a Proxmox firewall rule, a VLAN ACL, a home router's client-isolation feature) is blocking it. If you applied a Proxmox VE firewall ruleset to the VM, explicitly allow inbound 50000/tcp from your management subnet.
etcd never reaches quorum after adding a third control-plane node
Check that all three nodes can reach each other over the network Talos was configured to use (etcd traffic isn't proxied through the API server) and that clocks aren't badly skewed — Talos runs NTP by default, but a VM cloned with a paused/suspended state can start with a stale clock large enough to break etcd's leader election.
Nodes stay NotReady indefinitely
No CNI has been installed yet — this is expected immediately after bootstrap. Check with kubectl get pods -n kube-system; if CoreDNS and kube-proxy (or your CNI's replacement) pods are stuck Pending, install a CNI.
FAQ
Do I need a separate load balancer in front of the Kubernetes API?
No — Talos's built-in VIP feature (configured in Step 3) handles control-plane failover without an external HAProxy/keepalived setup, as long as all control-plane nodes sit on the same Layer 2 network segment.
Can I run Talos as an LXC container instead of a VM?
No. Talos is a full immutable operating system with its own kernel; it requires real (or hardware-assisted virtual) hardware, which means a VM, not an LXC container that shares the Proxmox host's kernel.
How many resources does a minimal cluster actually need?
Three control-plane nodes at 2 vCPU / 4 GB RAM / 20–32 GB disk each is enough for etcd and the core control-plane components at idle; add worker node capacity separately based on your workloads.
Can control-plane nodes also run regular workloads?
By default Talos taints control-plane nodes so ordinary pods won't schedule there, matching standard Kubernetes practice. You can remove the taint for small clusters where dedicating nodes purely to the control plane isn't worthwhile, at the cost of workloads competing with etcd/API-server for CPU and I/O.
How is this different from just running k3s on a regular Debian VM?
k3s (or any distribution) on a general-purpose Linux VM still carries a full OS you're responsible for patching, hardening, and managing via SSH. Talos removes that layer entirely — there's no OS-level surface to maintain outside of the machine config file itself, at the cost of losing the ability to SSH in or install arbitrary packages on the host.
Conclusion
Talos Linux and Proxmox VE complement each other unusually well: Proxmox handles fast, repeatable VM provisioning, and Talos handles a minimal, API-driven, immutable node OS with none of the traditional Linux maintenance burden. Once the first cluster is up, adding capacity is just "create a VM with the right hardware profile, apply a config file" — no image customization, no configuration management tooling, no SSH keys to distribute. For anyone running Kubernetes on Proxmox for more than a quick test, it's worth the (small) learning curve of working entirely through talosctl instead of a shell.