The one project
Homelab
Home infrastructure as code โ the same rigour I'd expect in production, on hardware that lives in my flat.
- 23 Compose stacks
- 13 OpenTofu modules
- 52 Containers
- 1 Repo of record
Everything I run at home lives in one repository. Not a folder of compose files I edit over SSH and forget about โ modules, pinned versions, runbooks, and a review step. If it isn’t in git, it isn’t in the lab.
The rule I hold myself to is that I should be able to lose any box and rebuild it from the repo. That’s why the router config, the identity provider, the dashboards and the alert rules are all code. The interesting part isn’t the list of services; it’s that almost nothing in it was set up by clicking.
It’s also where I get to make the mistakes I don’t want to make at work. When I moved monitoring to config-as-code, my first alert rule fed a == 0 expression into a > 0 threshold โ so a dead service produced a 0 that never crossed the line and the rule sat there looking healthy. I found it by stopping Sonarr and watching the probe read zero for several minutes while nothing fired. Both rules now threshold the raw metric, and I verified the full cycle: stop the service, alert fires, start it, alert resolves.
How it's put together
Edge
Traefik terminates TLS for every hostname on the domain, CrowdSec sits in front of it, and port 80 is a permanent redirect to HTTPS.
- Traefik
- CrowdSec
- Cloudflare Tunnel
Identity
Authentik is the single sign-on for the whole lab โ OAuth, SAML and LDAP, down to the NAS logins.
- Authentik
- OIDC
- LDAP
Compute
Proxmox runs the LXC containers and VMs, declared in OpenTofu instead of clicked together in the web UI.
- Proxmox VE
- LXC
- OpenTofu
Kubernetes
A Talos cluster provisioned from the Proxmox module, holding the platform workloads that outgrew Compose.
- Talos
- ArgoCD
- Calico
Network
RouterOS is code as well โ firewall rules and the WireGuard peers I use to get back in from outside.
- MikroTik
- RouterOS
- WireGuard
Inventory
NetBox is the source of truth for devices, prefixes and VLANs, and it is managed as code like everything else.
- NetBox
- IPAM
- DCIM
Secrets
Vault hands out the credentials stacks need at runtime, so nothing sensitive sits in git or in Terraform state.
- Vault
- Vaultwarden
Observability
Grafana and VictoriaMetrics are provisioned from config, Blackbox probes 25+ endpoints, and alerts route to Telegram and email.
- Grafana
- VictoriaMetrics
- Blackbox
- Gatus
Home
Home Assistant with Zigbee2MQTT and Mosquitto, plus n8n for the automations that stitch services together.
- Home Assistant
- Zigbee2MQTT
- n8n
Media
Jellyfin and the *arr stack, with the downloaders routed through a VPN gateway container.
- Jellyfin
- Sonarr
- Radarr
- Gluetun
The metal
- Main server
- FIREBAT T8 Pro Plus mini PC โ Intel N100, 16GB DDR5, 512GB SSD, running Proxmox VE
- Secondary
- Dell PowerEdge R610 โ the experiment box, mostly powered down
- Storage
- Synology DS220+, 2 ร 4TB โ primary storage and backups
- Router
- MikroTik hAP ac3 on RouterOS, handling DHCP and NTP
- Wireless
- TP-Link Deco M4R ร3 mesh
- Uplink
- 300 Mb/s symmetric fibre
How it's run
One way to change things
Every OpenTofu module carries the same Makefile โ init, plan, apply, validate, fmt โ and remote state lives in a GCS bucket.
Nothing on :latest
Images and providers are pinned to explicit versions and bumped by Renovate, so an upgrade arrives as a reviewable diff instead of a surprise at 2am.
Guardrails before merge
Pre-commit hooks run alongside consistency and security-invariant checks, so the obvious mistakes never reach the host.
Restore from the repo
Stacks ship env templates and seed config, so a service comes back from git rather than from memory.
Next on the list
- Move backups off Proxmox and onto the NAS
- NUT/UPS integration so the lab survives a power cut
- Isolate IoT devices onto their own subnet
- Self-hosted LLM running on the cluster