Skip to content

Lab Infrastructure

Complete documentation of Emil's homelab: hardware, network, Kubernetes clusters, services, and operational patterns.


Overview

The homelab runs on three Proxmox hosts (lab-node01, lab-node02, lab-node03) with one active Kubernetes cluster:

Cluster Nodes Purpose Status
K3s 3 nodes Active cluster — servarr stack running 🟢 Active

Network

Subnet VLAN Purpose Gateway
192.168.10.0/24 10 General WLAN — end devices, clients 192.168.10.1
192.168.20.0/24 20 Infrastructure (agent, DNS, NAS, runner, secrets) 192.168.20.1
192.168.30.0/24 30 Kubernetes & virtualization 192.168.30.1
192.168.99.0/24 99 Management (router, switch, Intel AMT/ME) 192.168.99.1

Key Hosts

IP Hostname Role
192.168.20.20 dns.bear.casa Technitium DNS
192.168.20.21 nas.bear.casa Synology NAS
192.168.20.31 — GitLab CI runner
192.168.20.100 agent.bear.casa Hermes AI agent (LXC)
192.168.20.151 — Infisical secrets
192.168.30.104 — k3s VIP (kube-vip ARP)
192.168.30.105-107 k3s-node-1/2/3 K3s cluster nodes
192.168.30.201 lab-node01 Proxmox VE — primary
192.168.30.202 lab-node02 Proxmox VE — secondary
192.168.30.203 lab-node03 Proxmox VE — tertiary

Proxmox

  • Hosts:
  • lab-node01 at 192.168.30.201:8006 — primary
  • lab-node02 at 192.168.30.202:8006 — secondary
  • lab-node03 at 192.168.30.203:8006 — tertiary
  • API Token: hermes@pve!hermes-token (Infisical prod)
  • Storage: data-nfs (NFS), data-ssd (local SSD), isos-nfs
  • Bridge: vmbr0 on VLAN 30
  • VM IDs: k3s nodes at 110-112, template at 101

K3s Cluster

  • Version: v1.30.2+k3s1
  • HA: Embedded etcd (3-node)
  • VIP: 192.168.30.104 via kube-vip (ARP mode)
  • Ingress: nginx-ingress on hostNetwork (ports 80/443 on node IPs)
  • Storage: NFS-backed nfs-client (default) + OpenEBS Local PV for config
  • LoadBalancer: MetalLB (pool 192.168.30.160-240)

Installed Charts

Chart Namespace Notes
ingress-nginx ingress-nginx HostNetwork bare-metal
nfs-subdir-external-provisioner nfs-provisioner Default StorageClass
cert-manager cert-manager Let's Encrypt (prod + staging)
MetalLB metallb-system FRR mode, L2 advertisement

Dashboards & Management

Dashboard URL Purpose
🖥️ Hermes Agent agent.bear.casa:9119 Hermes Agent runtime dashboard
🧠 Mnemosyne Memory agent.bear.casa:8766 AI memory browser & search
🔐 Infisical secrets.emilsturzenegger.ch Secret vault management
📋 Vikunja board.emilsturzenegger.ch Task management
⚙️ Proxmox VE 192.168.30.201:8006 Hypervisor management
🐳 Technitium DNS dns.bear.casa Local DNS management
🗄️ Synology NAS nas.bear.casa Network storage

Services

Media Stack (servarr namespace)

Service URL Status
🎬 Radarr radarr.emilsturzenegger.ch 🟢
📺 Sonarr sonarr.emilsturzenegger.ch 🟢
🔎 Prowlarr prowlarr.emilsturzenegger.ch 🟢
📥 SABnzbd sabnzbd.emilsturzenegger.ch 🟢
🎞️ Jellyfin jellyfin.emilsturzenegger.ch 🟢
📝 Bazarr bazarr.emilsturzenegger.ch 🟢
🎫 Seerr seerr.emilsturzenegger.ch 🟢

Home Automation

Service URL Status
🏠 Home Assistant home-assistant.emilsturzenegger.ch 🟢
🔄 Node-RED node-red.emilsturzenegger.ch 🟢
🐝 Zigbee2MQTT zigbee2mqtt.emilsturzenegger.ch 🟢
📡 Mosquitto (MQTT) mosquitto.emilsturzenegger.ch:31883 (TCP) 🟢

Infrastructure

Service URL Status
🔐 Infisical secrets.emilsturzenegger.ch 🟢
📋 Vikunja board.emilsturzenegger.ch 🟢
📶 UniFi Controller unifi.emilsturzenegger.ch 🟢
🔑 Vaultwarden bitwarden.emilsturzenegger.ch 🟢
📖 Wiki wiki.emilsturzenegger.ch 🟢
🖥️ Hermes Dashboard agent.bear.casa:9119 🟢
🧠 Mnemosyne Memory agent.bear.casa:8766 🟢

Git Repositories

Repo URL Purpose
k3s-helm-deployments GitLab Helm values and deployment manifests
k3s-proxmox GitLab IaC: Terraform + Ansible for k3s
Wiki GitLab This wiki source
Hermes Workflow GitHub Multi-agent pipeline framework

All secrets are stored in Infisical at secrets.emilsturzenegger.ch:

  • Workspace: homelab (slug: homelab-a-rye)
  • Environments: dev, staging, prod
  • Key secrets: Proxmox API tokens, GitLab PAT, Cloudflare credentials, Discord tokens, SSH passwords, API keys
  • Auth: Universal Auth (client ID + client secret)

Access pattern:

# Login
curl -s -X POST "https://secrets.emilsturzenegger.ch/api/v1/auth/universal-auth/login" \
  -H "Content-Type: application/json" \
  -d '{"clientId":"...","clientSecret":"..."}' | jq -r '.accessToken'

# Get secrets
curl -s "https://secrets.emilsturzenegger.ch/api/v3/secrets/raw?workspaceSlug=homelab-a-rye&environment=prod" \
  -H "Authorization: Bearer $TOKEN..."

Technitium DNS at 192.168.20.20 (dns.bear.casa):

  • API: Port 80, Authorization: Bearer $TOKEN
  • Read: GET /api/zones/list, GET /api/zones/records/get?domain=<zone>&listZone=true
  • Write: POST /api/zones/records/add (form-encoded, not JSON)
  • Zones: bear.casa, emilsturzenegger.ch, reverse zones for VLANs
  • Token: In Infisical prod as TECHNITIUM_TOKEN