The Problem Space
Homelabs evolve. You start with one Docker container, add some LXCs, then Kubernetes, and suddenly your infrastructure is a house of cards held together by scripts you wrote two years ago and don’t remember.
This architecture solves that through:
- Everything in code — from VM provisioning to Kubernetes bootstrap
- Versioned modules — each update is a code review opportunity
- Self-service via Backstage — templated provisioning, no Slack threads
Numbers: 3 Proxmox nodes, 2 production clusters (Docker Swarm + Talos K8s), ~50 resources defined across 24+ YAML configurations.
Running in production:
- 3 Proxmox nodes (alpha, charlie, foxtrot)
- Docker Swarm clusters with Keepalived HA
- Talos Kubernetes clusters with Flux GitOps
- GPU passthrough for hardware acceleration
- Multi-network topology (dmz + vmbr1)
- Private container registry (Harbor)
- Private Terraform registry (Cloudflare Workers)
Start with the basic template. All custom modules derive from it — maintaining consistency across the infrastructure.
Module Hierarchy
graph TB
subgraph "Root Module"
A[tf-infra-homelab]
end
subgraph "Compute Modules"
B[tf-module-proxmox-lxc]
C[tf-module-proxmox-vm]
D[tf-module-proxmox-talos]
E[tf-module-proxmox-docker]
end
subgraph "Application Layer"
F[applications-homelab]
end
subgraph "Platform"
G[Proxmox VE]
end
A --> B
A --> C
A --> D
A --> E
D --> F
E --> F
B --> G
C --> G
D --> G
E --> G
| Module | Purpose |
|---|---|
| terraform-basic-template | Foundation for all modules |
| tf-module-proxmox-lxc | LXC container provisioning |
| tf-module-proxmox-vm | Full VM provisioning |
| tf-module-proxmox-docker | Docker Swarm clusters |
| tf-module-proxmox-talos | Talos Kubernetes clusters |
| tf-infra-homelab | Root orchestration |
| applications-homelab | Kustomize deployments |
| github-management-plane | GitHub org management |
The Dependency Graph
graph TB
T[terraform-basic-template]
L[tf-module-proxmox-lxc]
V[tf-module-proxmox-vm]
DT[tf-module-proxmox-docker]
TT[tf-module-proxmox-talos]
RH[tf-infra-homelab]
AH[applications-homelab]
P[ProxmoxVE]
T --> L
T --> V
L --> DT
V --> DT
L --> TT
V --> TT
DT --> RH
TT --> RH
RH --> P
DT --> AH
TT --> AH
Key observations:
- Template is foundational — all modules derive from the same template
- LXC and VM are leaf modules — no dependencies on other custom modules
- Docker and Talos are composite — build on LXC/VM modules
- Root module is orchestrational — composes modules based on configurations
- Applications deploy post-provisioning — GitOps ties into Docker/Talos clusters
Configuration-Driven
All infrastructure is defined in YAML configurations, not ad-hoc Terraform runs:
configurations/
├── docker/
│ ├── dev-docker-lxc.yaml
│ └── prod-docker-lxc.yaml
├── kubernetes/
│ ├── dev-k8s.yaml
│ └── prod-k8s.yaml
└── virtual_machine/
└── ...Each config has an enabled flag for gradual rollout:
name: prod-k8s
enabled: true # Set to false to disable without deletion
cluster:
name: prod-k8s
datastore:
id: nas
node: alphaWhat’s Running
| Cluster | Type | Nodes | VIP | Purpose |
|---|---|---|---|---|
| prod-docker-lxc | Docker Swarm | 3x medium (8vCPU/32GB) | 192.168.61.20 | Container workloads |
| prod-k8s | Talos K8s | 3x CP (4vCPU/8GB) + 3x worker (10vCPU/48GB) | 192.168.62.20 | Kubernetes workloads |
Both clusters span all 3 Proxmox nodes for high availability.
Design Principles
This architecture follows specific principles:
| Principle | Implementation |
|---|---|
| Single configuration object | All modules use unified configuration input |
| Host pools | Resilience through multi-node distribution |
| Versioned modules | Each module has explicit versions |
| YAML configurations | Infrastructure as data, not ad-hoc apply |
| Private registry | Distribution without Terraform Cloud cost |
| Secrets integration | Bitwarden for credential storage |
| GitOps | Flux bootstrapped during cluster creation |
| Multi-network | Separate DMZ and backend networks |
| GPU passthrough | Device mapping in host pool |
What Most People Get Wrong
-
“More modules = better architecture” — I started with 10+ modules. Consolidated to 5. Over-modularization creates maintenance overhead.
-
“YAML = Terraform” — Terraform is the engine, YAML is the fuel. Don’t embed YAML in
.tffiles; load from external files. -
“GitOps replaces Terraform” — They work together: Terraform provisions, Flux manages apps. Both are declarative.
Related Posts
Each component has its own detailed post:
| Post | Focus |
|---|---|
| Talos Kubernetes on Proxmox | tf-module-proxmox-talos deep dive — image factory, machine config, bootstrap |
| Docker Swarm on Proxmox | tf-module-proxmox-docker deep dive — Keepalived HA, provisioning |
| LXC & VM Modules | tf-module-proxmox-lxc + tf-module-proxmox-vm basics |
| Backstage Integration | Catalog generation, software templates |
| Private Terraform Registry | Module distribution via Cloudflare Workers |
| GitHub Management Plane | Managing GitHub org via Terraform |