---
type: "article"
title: "Talos Kubernetes on Proxmox with Traefik"
summary: "Why This Matters\n\nRunning Kubernetes at home has traditionally meant dealing with the overhead of full Linux distributions, manual cluster setup, and the complexity of production-grade networking. This repository solves those pain points by leveraging Talos Linux a minimal, immutable, API-driven OS built specifically for Kubernetes - combined with Traefik for seamless ingress routing.\n\n\nProblems this solves:\n\n * No OS maintenance overhead - Talos is immutable and managed entirely via API\n * Full"
newsletter: "VillaBytes"
newsletter_handle: "villabytes"
newsletter_url: "https://usecommune.com/n/villabytes"
author: "Carlos Villanua Fernandez (@carlosvillanua)"
published: "2026-01-21T20:25:44.000Z"
canonical_url: "https://usecommune.com/n/villabytes/a/talos-kubernetes-on-proxmox-with-traefik-2"
markdown_url: "https://usecommune.com/n/villabytes/a/talos-kubernetes-on-proxmox-with-traefik-2.md"
chat_url: "https://usecommune.com/n/villabytes/a/talos-kubernetes-on-proxmox-with-traefik-2/chat"
source_url: "https://carlosvillanua.com/talos-kubernetes-on-proxmox-with-traefik/"
body_source: "imported"
likes: 0
replies: 0
body_words: 850
---

# Talos Kubernetes on Proxmox with Traefik

## Why This Matters

Running Kubernetes at home has traditionally meant dealing with the overhead of full Linux distributions, manual cluster setup, and the complexity of production-grade networking. This repository solves those pain points by leveraging **Talos Linux** a minimal, immutable, API-driven OS built specifically for Kubernetes - combined with **Traefik** for seamless ingress routing.

### Problems this solves:

- **No OS maintenance overhead** - Talos is immutable and managed entirely via API
- **Fully reproducible** - Destroy and rebuild your entire cluster in minutes with simple scripts
- **Production-grade networking** - MetalLB LoadBalancer + Traefik ingress
- **Automated workflows** - Scripts handle VM creation, node provisioning, and cluster joining automatically
- **Zero cloud costs** - Kubernetes on your own hardware without monthly bills
- **Secure by default** - Minimal attack surface with no SSH, shell access, or unnecessary packages
- **Built-in observability** - Traefik dashboard and Headlamp UI for cluster management out of the box

***

Production-ready Kubernetes cluster using Talos Linux on Proxmox VE with Traefik ingress controller.

## Features

- **Immutable OS**: Talos Linux provides API-driven infrastructure
- **High Availability**: Multi-node setup with MetalLB load balancing
- **Ingress**: Traefik with high availability load balancing
- **Web UI**: Headlamp dashboard for cluster management
- **Automated**: Scripts for quick worker node deployment

![Article content](https://media.licdn.com/dms/image/v2/D4E12AQG-yCRaiJ8WPA/article-inline_image-shrink_1500_2232/B4EZueLWRuJQAU-/0/1767885335231?e=1770854400&v=beta&t=Jgjp3w6P7nAe_Ns-tUq3Sf3ti9IROTdFjRk3-jPznY4)

*Diagram*

## Prerequisites

- Proxmox VE running
- Talos ISO downloaded to Proxmox (default path: /var/lib/vz/template/iso/metal-amd64.iso)
- Available IP addresses for nodes in your network
- kubectl installed on your workstation
- Helm 3 installed on your workstation

First of all clone the Github repository

```
git clone https://github.com/traefik-workshops/traefik-on-prem-proxmox-talos
```

### 1. Install talosctl

```
curl -sL https://github.com/siderolabs/talos/releases/latest/download/talosctl-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/') -o ~/bin/talosctl
chmod +x ~/bin/talosctl
export PATH="$HOME/bin:$PATH"
```

### 2. Create Control Plane VM

Create VM in Proxmox UI or via CLI:

```
# On Proxmox server
# Adjust storage (local-lvm), bridge (vmbr0), and ISO storage (local) to match your setup
qm create 101 \
  --name talos-cp-1 \
  --memory 2048 \
  --cores 2 \
  --cpu x86-64-v2-AES \
  --sockets 1 \
  --numa 0 \
  --net0 virtio,bridge=vmbr0,firewall=1 \
  --scsihw virtio-scsi-single \
  --scsi0 local-lvm:32,iothread=1 \
  --ide2 local:iso/metal-amd64.iso,media=cdrom \
  --boot order=scsi0\;ide2\;net0 \
  --ostype l26

qm start 101
```

Note the VM's IP address from console.

![Article content](https://media.licdn.com/dms/image/v2/D4E12AQEom1Ha5Qwjqw/article-inline_image-shrink_1000_1488/B4EZueLr_LGQAQ-/0/1767885423955?e=1770854400&v=beta&t=0LOrtyZNIMa925OA7W-YmE8tN3txzguIzmpd3oa8D_M)

*talos_controlplane_ip*

### 3. Bootstrap Cluster

```
# Generate configs
talosctl gen config homelab-cluster https://<control-plane-ip>:6443

# Configure talosctl
export TALOSCONFIG=$(pwd)/talosconfig
talosctl config endpoint <control-plane-ip>
talosctl config node <control-plane-ip>

# Apply config
talosctl apply-config --insecure --nodes <control-plane-ip> --file controlplane.yaml

# Wait 60 seconds, then bootstrap
talosctl bootstrap

# Get kubeconfig
talosctl kubeconfig .
export KUBECONFIG=$(pwd)/kubeconfig

# Wait for control plane to be Ready (~60 seconds)
kubectl get nodes
# Node will show "NotReady" initially, wait until it shows "Ready"

# Keep these environment variables set for all following steps
echo "TALOSCONFIG: $TALOSCONFIG"
echo "KUBECONFIG: $KUBECONFIG"
```

![Article content](https://media.licdn.com/dms/image/v2/D4E12AQEc0RZky-EEkQ/article-inline_image-shrink_1500_2232/B4EZueL6SeIwAY-/0/1767885482073?e=1770854400&v=beta&t=Hg3lxEmM5LHD-KiLaposSDM2FQwoVomHZN6tas8iXx0)

*talos-controlplane-k8s*

### 4. Add Worker Nodes

**Note:** Ensure TALOSCONFIG environment variable is still set from Step 3.

### Option A: Automated (Recommended)

```
# Setup SSH to Proxmox
scripts/setup-proxmox-ssh.sh <proxmox-ip>

# Add worker (replace <proxmox-node> with your Proxmox node name, usually 'pve')
scripts/add-talos-worker.sh -n talos-worker-1 -i <worker-ip> -p <proxmox-node> -v 201
```

### Option B: Manual

```
# Create VM in Proxmox, then:
scripts/add-worker-manual.sh
# Enter worker IP when prompted
```

![Article content](https://media.licdn.com/dms/image/v2/D4E12AQFRlfdNPnfwRg/article-inline_image-shrink_1000_1488/B4EZueMFuBIgAQ-/0/1767885529363?e=1770854400&v=beta&t=N36Z288ULxIk2gNfMtP4fiZl9htVpUK_4eenZqloXoI)

*talos_workernode_k8s*

### 5. Install MetalLB

```
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.5/config/manifests/metallb-native.yaml
kubectl wait --namespace metallb-system --for=condition=ready pod --selector=app=metallb --timeout=90s

# Update the IP range below to match your network
kubectl apply -f - <<EOF
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: default-pool
  namespace: metallb-system
spec:
  addresses:
  - 192.168.1.200-192.168.1.250  # Change to your available IP range
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: default
  namespace: metallb-system
spec:
  ipAddressPools:
  - default-pool
EOF
```

### 6. Install Traefik

```
helm repo add traefik https://traefik.github.io/charts
helm repo update

helm install traefik traefik/traefik --wait \
  --set ingressRoute.dashboard.enabled=true \
  --set ingressRoute.dashboard.matchRule='Host(`dashboard.localhost`)' \
  --set ingressRoute.dashboard.entryPoints={web} \
  --set providers.kubernetesGateway.enabled=true \
  --set gateway.listeners.web.namespacePolicy.from=All

kubectl apply -f - <<EOF
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
  name: traefik-dashboard
  namespace: default
spec:
  entryPoints:
  - web
  routes:
  - kind: Rule
    match: PathPrefix(\`/dashboard\`) || PathPrefix(\`/api\`)
    services:
    - kind: TraefikService
      name: api@internal
EOF

kubectl scale deployment traefik -n default --replicas=3  # Adjust replica count as needed
kubectl wait --namespace default --for=condition=ready pod -l app.kubernetes.io/name=traefik --timeout=60s

# Access at http://<external-ip>/dashboard/
kubectl get svc traefik 
```

![Article content](https://media.licdn.com/dms/image/v2/D4E12AQHRyhq0yAQSNw/article-inline_image-shrink_1000_1488/B4EZueMPh3KkAQ-/0/1767885569526?e=1770854400&v=beta&t=i7pB0V6eUZ3EZZHvq7eWInxFYu7tqwCc8_Pq52bt8eE)

*traefik_dashboard*

### 7. Install Headlamp (Kubernetes UI)

```
helm repo add headlamp https://kubernetes-sigs.github.io/headlamp/
helm repo update

helm install headlamp headlamp/headlamp \
  --namespace kube-system \
  --create-namespace \
  --set config.baseURL=/headlamp \
  --wait

kubectl apply -f - <<EOF
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
  name: headlamp
  namespace: kube-system
spec:
  entryPoints:
  - websecure
  routes:
  - kind: Rule
    match: PathPrefix(\`/headlamp\`)
    services:
    - name: headlamp
      port: 80
  tls: {}
EOF

kubectl create token headlamp -n kube-system --duration=87600h > headlamp-token.txt
cat headlamp-token.txt

# Access at https://<external-ip>/headlamp/
# Login with token from headlamp-token.txt
```

![Article content](https://media.licdn.com/dms/image/v2/D4E12AQES0_dfgQBzzA/article-inline_image-shrink_1500_2232/B4EZueMYxLLYAY-/0/1767885606656?e=1770854400&v=beta&t=9dRnkMJhpeHLGNCRw40a5LCZN1VIn69Kpz88rL4Rc3g)

*headlamp_login*

![Article content](https://media.licdn.com/dms/image/v2/D4E12AQEJhqpfPUMaSA/article-inline_image-shrink_1000_1488/B4EZueMcq.HsAQ-/0/1767885623120?e=1770854400&v=beta&t=Dihb560sB30ed6Ob0zjfD8G9B3oKULI9uiQNWkKVSGM)

*headlamp_dashboard*

### Quick Reference

### Access Points

- Traefik Dashboard: http://\<external-ip>/dashboard/
- Headlamp: https://\<external-ip>/headlamp/

### Useful Commands

```
# Cluster status
kubectl get nodes
kubectl get pods -A

# Talos health
talosctl health
talosctl dashboard

# Scale workers
scripts/add-talos-worker.sh -n talos-worker-2 -i <ip> -p <proxmox-node> -v 202
```

***

## Discussion

No replies yet.
