Skip to main content

Architecture

Comprehensive architecture reference for the woodhead.tech Proxmox homelab. Covers network topology, service dependencies, traffic flow, storage, DNS/TLS, and resource allocation.

Network Topology

+-----------+
| Internet |
+-----+-----+
|
+-----+-----+
| ISP Modem |
+-----+-----+
|
+----------+----------+
| Google Nest WiFi |
| Pro (router/mesh) |
| 192.168.86.1 |
| NAT / DHCP / DNS / |
| WiFi |
+----------+----------+
|
192.168.86.0/24 (flat LAN)
|
+----------+----------+----------+----------+
| | | | |
+-----+----+ +--+-------+ +--+------+ +--+-----+ +--+------+
| Proxmox | | Proxmox | | Proxmox | | Proxmox| | Proxmox |
| Node 1 | | Node 2 | | Node 3 | | Node 4 | | Node 5 |
| .29 | | .30 | | .31 | | .130 | | .147 |
| think- | | think- | | think- | | tower1 | | zotac |
| centre1 | | centre2 | | centre3 | | | | |
+-----+----+ +--+-------+ +--+------+ +--+-----+ +--+------+
| | | | |
+------- Ceph Storage Mesh (3-way replication) ------+
|
| +----- VMs + LXCs distributed across nodes -----+
| | |
+----+---+----+ +----------+ +----------+ +--------+---+
| Traefik | | Recipe | | ARR | | K8s Cluster|
| LXC 200 | | Site | | Stack | | |
| .86.20 | | LXC 201 | | LXC 202 | | CP: .101 |
| :80 :443 | | .21 :80 | | .22 | | W1: .111 |
+------+------+ +----------+ +----------+ | W2: .112 |
| | W3: .113 |
| +----------+ +----------+ | VIP: .100 |
| | Plex | | Jellyfin | +------------+
| | LXC 203 | | LXC 204 |
| | .23 | | .24 |
| | :32400 | | :8096 |
| | iGPU | | iGPU |
| +----------+ +----------+
|
| +----------+ +--------------+
| | TrueNAS | | Home |
| | VM 300 | | Assistant |
| | .40 | | VM 301 |
| | NFS:2049 | | .41 :8123 |
| +----------+ +--------------+
|
| +----------+ +----------+ +-----------+
| | Monitoring| | OpenClaw | | Authentik |
| | LXC 205 | | LXC 206 | | LXC 207 |
| | .25 | | .26 | | .28 |
| | :9090 | | :18789 | | :9091 |
| | :3000 | +----------+ +----------+
| | :9093 |
| | -> Discord| +-----------+ +-----------+
| | + Dexcom | | WireGuard | | Libby |
| | glucose | | LXC 208 | | Alert |
| +----------+ | .39 | | LXC 209 |
| | UDP:51820 | | .27 :80 |
| +-----------+ +-----------+
|
| +----------+
| | SDR |
| | Scanner |
| | LXC 210 |
| | .32 |
| | :3000 |
| | RTL-SDR |
| +----------+
|
+------- Standalone Devices (not Proxmox-managed) -------+
| |
+----+----------+ +----------------+
| Piboard | | Klipper | Raspberry Pi 3B
| 192.168.86.131| | Ender 5 Pro | MainsailOS + Klipper
| :8080 | | 192.168.86.136 | Moonraker + Mainsail
| Waveshare 5" | | :80 :7125 | USB -> printer MCU
+---------------+ +----------------+

IP Address Allocation

IPHostnameTypeVM IDPurpose
192.168.86.1nest-gatewayRouter--Google Nest WiFi Pro (NAT, DHCP, DNS)
192.168.86.29pve1 (thinkcentre1)Host--Proxmox node 1
192.168.86.30pve2 (thinkcentre2)Host--Proxmox node 2
192.168.86.31pve3 (thinkcentre3)Host--Proxmox node 3
192.168.86.130tower1Host--Proxmox node 4
192.168.86.147zotacHost--Proxmox node 5
192.168.86.20traefikLXC200Reverse proxy, TLS termination
192.168.86.21recipe-siteLXC201Go + SQLite recipe app
192.168.86.22arr-stackLXC202Docker: Sonarr, Radarr, etc.
192.168.86.23plexLXC203Plex Media Server + iGPU
192.168.86.24jellyfinLXC204Jellyfin Media Server + iGPU
192.168.86.25monitoringLXC205Prometheus, Grafana, Alertmanager
192.168.86.26openclawLXC206OpenClaw AI agent framework
192.168.86.27libby-alertLXC209Libby life alert QR site + alerts
192.168.86.28authentikLXC207Identity provider (Authentik SSO, OIDC)
192.168.86.32sdrLXC210SDR scanner (Trunk Recorder + rdio-scanner)
192.168.86.39wireguardLXC208WireGuard VPN tunnel (UDP 51820)
192.168.86.40truenasVM300NAS, ZFS, NFS/SMB shares
192.168.86.41homeassistantVM301Home Assistant OS, smart home
192.168.86.131piboardPi--Raspberry Pi 3B monitoring dashboard
192.168.86.136klipper-ender5proPi--Klipper 3D printer (Ender 5 Pro)
192.168.86.100k8s-vipVIP--Kubernetes API endpoint
192.168.86.101talos-cp-0VM400K8s control plane (Talos Linux)
192.168.86.111-113talos-worker-*VM410-412K8s workers (Talos Linux, 3 nodes)
192.168.86.150-199metallb-poolK8s--MetalLB LoadBalancer IPs
192.168.86.200-254dhcp-poolDHCP--Dynamic client addresses

Traffic Flow: External

An external request to https://recipes.woodhead.tech:

1. CLIENT DNS query: recipes.woodhead.tech
|
v
2. CLOUDFLARE DNS Returns public IP (WAN) via A record
| (Updated every 5 min by DDNS)
v
3. ISP MODEM Passes traffic to Google Nest
|
v
4. GOOGLE NEST Receives on public IP :443
| Port forward: :443 -> 192.168.86.20:443
v
5. TRAEFIK (192.168.86.20) Terminates TLS (wildcard *.woodhead.tech cert)
| Matches route: Host(`recipes.woodhead.tech`)
| Proxies to backend: http://192.168.86.21:80
v
6. RECIPE SITE (192.168.86.21) Nginx :80 -> Go app :8080
| Returns HTML response
v
7. TRAEFIK Wraps response in TLS, sends back
|
v
8. GOOGLE NEST Reverse NAT: 192.168.86.20 -> public IP
|
v
9. CLIENT Receives HTTPS response with valid cert

Port forwarding (Google Nest -> LAN):

WAN PortDestinationProtocolPurpose
80192.168.86.20:80TCPHTTP -> Traefik
443192.168.86.20:443TCPHTTPS -> Traefik
51820192.168.86.39:51820UDPWireGuard VPN tunnel

Traffic Flow: Internal

Internal clients resolve *.woodhead.tech via Cloudflare DNS (upstream from Google Nest). The Nest supports hairpin NAT, so traffic loops back to Traefik without leaving the network.

1. CLIENT (192.168.86.x) DNS query: recipes.woodhead.tech
|
v
2. GOOGLE NEST DNS Forwards to upstream (8.8.8.8 / 1.1.1.1)
| Returns public IP from Cloudflare
v
3. CLIENT Connects to public IP :443
|
v
4. GOOGLE NEST Hairpin NAT: public IP -> 192.168.86.20:443
|
v
5. TRAEFIK (192.168.86.20) Terminates TLS, routes to backend
|
v
6. RECIPE SITE (192.168.86.21) Responds directly on LAN
note

Unlike a dedicated firewall with local DNS overrides, internal requests still depend on external DNS resolution. Services are unreachable during internet outages unless clients have static hosts file entries.

DNS Resolution

+-------------------+
| External Client |
+--------+----------+
|
+--------v----------+
| Cloudflare DNS | Authoritative for woodhead.tech
| (free tier) | A record: *.woodhead.tech -> public IP
+-------------------+ Updated by DDNS every 5 min


+-------------------+
| Internal Client |
+--------+----------+
|
+--------v----------+
| Google Nest DNS | Forwards to upstream resolvers
| (192.168.86.1:53)|
+-------------------+
  • Registrar: Squarespace (nameservers pointed to Cloudflare)
  • Authoritative DNS: Cloudflare (free tier)
  • DDNS updates: Cron script on Proxmox node (every 5 min)
  • Internal resolution: Google Nest forwards to upstream DNS; hairpin NAT loops traffic back to Traefik

TLS Certificate Flow

Traefik handles all TLS termination using Let's Encrypt certificates obtained via Cloudflare DNS-01 challenges.

1. TRAEFIK detects new route requiring TLS
|
v
2. Requests cert from LET'S ENCRYPT
| Challenge type: DNS-01
v
3. TRAEFIK creates TXT record via CLOUDFLARE API
| _acme-challenge.woodhead.tech = <token>
v
4. LET'S ENCRYPT validates TXT record
| Verifies domain ownership
v
5. Certificate issued
| Wildcard: *.woodhead.tech
| Stored: /etc/traefik/acme.json (0600)
| Auto-renewal: 30 days before expiry
v
6. TRAEFIK applies cert to all matching routes

Why DNS-01? Supports wildcard certs, works before port forwarding is configured, works with internal-only IPs, and Cloudflare free tier supports it.

Service Dependency Graph

Hard dependencies (service won't function without):

  • All services -> Google Nest gateway (routing, DHCP, DNS)
  • All external access -> Traefik (TLS, routing)
  • Protected services -> Authentik (forwardAuth SSO, OIDC)
  • Remote VPN access -> WireGuard (UDP 51820 port forward required)
  • ARR stack media storage -> TrueNAS (NFS at /media)
  • Plex/Jellyfin media library -> TrueNAS (NFS at /media, read-only)
  • Plex/Jellyfin transcoding -> iGPU (/dev/dri passthrough from Proxmox host)

Soft dependencies (service works but with reduced functionality):

  • Monitoring without PVE token: Proxmox metrics unavailable
  • Monitoring without Dexcom credentials: glucose exporter starts but can't poll API
  • Monitoring without Twilio credentials: glucose SMS alerts silently fail
  • Piboard without Prometheus: dashboard shows "connection lost" overlay
  • Services without Traefik: accessible via direct IP:port (no TLS)

Boot Order

OrderServiceVM IDDelayWhy
1TrueNAS30030sNFS shares must be ready before consumers
2Home Assistant30115sSmart home should always be running
autoAll LXCs200-210--Start on boot, no ordering constraint
manualK8s Cluster400+--Bootstrapped via make bootstrap

Storage Architecture

+-- Proxmox Node -----------------------------------------+
| |
| Physical Disks: |
| +----------+ +----------+ +----------+ +----------+ |
| | sda | | sdb | | sdc | | sdd | |
| | Proxmox | | Ceph OSD | | TrueNAS | | TrueNAS | |
| | OS + | | | | data 1 | | data 2 | |
| | local-lvm| | | | (pass- | | (pass- | |
| +----------+ +----------+ | through)| | through) | |
| +----------+ +----------+ |
+----------------------------------------------------------+
StorageTypeUsed By
local-lvmLVM (SSD)TrueNAS OS, HAOS, all LXC disks
ceph-poolCeph (3x)K8s control plane, K8s workers
PassthroughPhysicalTrueNAS ZFS data pool

Resource Allocation

CPU & Memory

ServiceCoresRAM (MB)Notes
TrueNAS48192ZFS ARC cache
Home Assistant22048USB passthrough
K8s Control Plane24096Per node
K8s Workers48192Per node, 3 nodes
Traefik LXC1256Lightweight proxy
Monitoring LXC22048Prometheus, Grafana, exporters
ARR Stack LXC240967 Docker containers
Plex / Jellyfin LXC22048iGPU passthrough
Authentik LXC22048Postgres + Redis + server + worker
SDR Scanner LXC22048Trunk Recorder + rdio-scanner
WireGuard LXC1256Kernel WireGuard

Total Budget

ResourceTotalNotes
CPU~36 coresShared across 5 Proxmox nodes
RAM~47.25 GBTrueNAS benefits from more (ZFS ARC)
local-lvm~146 GBOS disks for VMs + all LXCs
ceph-pool~250 GB rawK8s VMs (3x replication)

Traefik Routing Table

SubdomainBackendPortStatus
recipes.woodhead.tech192.168.86.2180Active
prowlarr.woodhead.tech192.168.86.229696Active (Authentik SSO)
sonarr.woodhead.tech192.168.86.228989Active (Authentik SSO)
radarr.woodhead.tech192.168.86.227878Active (Authentik SSO)
bazarr.woodhead.tech192.168.86.226767Active (Authentik SSO)
requests.woodhead.tech192.168.86.225055Active (Authentik SSO)
sabnzbd.woodhead.tech192.168.86.228080Active (Authentik SSO)
plex.woodhead.tech192.168.86.2332400Active
jellyfin.woodhead.tech192.168.86.248096Active
nas.woodhead.tech192.168.86.40443Active (Authentik SSO)
home.woodhead.tech192.168.86.418123Active
grafana.woodhead.tech192.168.86.253000Active
prometheus.woodhead.tech192.168.86.259090Active (Authentik SSO)
scanner.woodhead.tech192.168.86.323000Active (Authentik SSO)
auth.woodhead.tech192.168.86.289000Active
docs.woodhead.tech192.168.86.258081Active
resume.woodhead.tech192.168.86.258082Active
woodhead.tech192.168.86.258083Active
ender5.woodhead.tech192.168.86.13680Active
traefik.woodhead.techlocalhost--Active (Authentik SSO)

Terraform Resource Map

ResourceFileTypeID
proxmox_virtual_environment_container.traefiklxc-traefik.tfLXC200
proxmox_virtual_environment_container.recipe_sitelxc-recipe-site.tfLXC201
proxmox_virtual_environment_container.arrlxc-arr.tfLXC202
proxmox_virtual_environment_container.plexlxc-plex.tfLXC203
proxmox_virtual_environment_container.jellyfinlxc-jellyfin.tfLXC204
proxmox_virtual_environment_container.monitoringlxc-monitoring.tfLXC205
proxmox_virtual_environment_container.openclawlxc-openclaw.tfLXC206
proxmox_virtual_environment_container.authelialxc-authelia.tfLXC207
proxmox_virtual_environment_container.wireguardlxc-wireguard.tfLXC208
proxmox_virtual_environment_container.libby_alertlxc-libby-alert.tfLXC209
proxmox_virtual_environment_container.sdrlxc-sdr.tfLXC210
proxmox_virtual_environment_vm.truenasvm-truenas.tfVM300
proxmox_virtual_environment_vm.homeassistantvm-homeassistant.tfVM301
proxmox_virtual_environment_vm.controlplane[*]control-plane.tfVM400+
proxmox_virtual_environment_vm.worker[*]workers.tfVM410+

Provider: bpg/proxmox ~0.66.0

Backup Strategy

WhatWhereMethodFrequency
Proxmox VMsTrueNAS /pool/backupsProxmox backup job -> NFSWeekly
Home AssistantTrueNAS /pool/backups/haBuilt-in snapshots -> NFSDaily
ARR stack configsTrueNAS /pool/backupsBackup /opt/arr/ directoryWeekly
Traefik certsIncluded in LXC backupacme.json auto-renews if lost--
K8s stateetcd (on control plane disk)Velero (future)--
Recipe site DBIncluded in LXC backupSQLite file in /opt/Weekly