Skip to content

Architecture

Network

Eight VLANs, all /24 under 192.168.0.0/16. Each VLAN reserves its first ~10 IPs for network infrastructure and its tail for a DHCP pool; everything in between is registry-allocated.

VLANIDSubnetPurpose
trusted1192.168.1.0/24Primary network — trusted devices, workstations
mgmt5192.168.5.0/24Network gear, hypervisors, platform services
proxmox10192.168.10.0/24Proxmox cluster
transfer11192.168.11.0/24Transfer network
speed12192.168.12.0/24Speed network
kids20192.168.20.0/24Content-filtered
iot30192.168.30.0/24IoT, restricted outbound
guest50192.168.50.0/24Guest wifi, internet only

Naming: hostnames are dot-separated, general→specific (prod.primary.standard.dns); the FQDN appends the VLAN's DNS zone (….mgmt.home.arpa). VMIDs are always 1000 + host octet, so 192.168.5.95 ⇒ container 1095 — one number to remember per instance.

Tiers

jacaranda-inventoryregistry (YAML)jacaranda-modulesgit:: pinned tagsFoundation — standalone repojacaranda-homelab — monorepopihole ×4DNSsecrets-server ×31Password Connectstep-ca ×3SSH CAplatform/postgres · ingress · observability · autheliahosted-apps/musa · inbox-zero · maxwells-walletphysical/bare-metal Ansible

Foundation deploys first and depends on nothing above it. Platform services are what apps build on. Physical hosts get SSH-CA trust and DNS only — no VM creation from that tier.

DNS flow

registryallocations + recordsfull-dns-syncfoundation, Ansiblepihole ×4every VLAN's clientsgather-dns-entries.sh(registry query / dns-export)pihole.toml API

All DNS intent lives in the registry — service allocations produce A records, standalone records cover infrastructure devices, CNAMEs must point at declared A records. Foundation's full-dns-sync publishes the entire registry (both envs) to every Pi-hole via the API. Nothing edits Pi-hole by hand, and no stack owns DNS records through Terraform anymore.

State

Every stack's OpenTofu state is encrypted (PBKDF2/AES-GCM, passphrase in 1Password) and stored out-of-band via terraform-backend-git on a tfstate branch of its own repo — foundation on its branch, monorepo stacks on theirs, one state path per stack env (<tier>/<service>/<env>). A wrapper script (tofu-run.sh) supplies the passphrase, the backend deploy key, and a local backend proxy for every OpenTofu invocation; running bare tofu against these stacks fails by design.

Secrets

1Password is the only secret store. Interactive use goes through the desktop app; unattended use goes through the self-hosted Connect Server (which is itself a foundation service). Secrets enter tooling exclusively via op read in justfiles — Terraform sees them as TF_VAR_*, Ansible as extra-vars, and neither ever persists them.