Skip to main content

Helix9 Homelab — Architecture Overview

Reference documentation for the Helix9 homelab. This page is the orientation map: what runs where, how traffic flows, and how the moving parts compose. Drill into the section docs for details.


At a glance

  • One DSL line (Telekom VDSL) terminates on a dedicated modem, with PPPoE handled by VyOS itself (post-Draytek migration).
  • One Proxmox node (pve02) hosts every internal service as an LXC container or VM. A second node (pve01) is bootstrapped but not yet in inventory.
  • One VPS (vyos-edge) acts as the public-facing front door, reverse-tunneling traffic to home over IPsec for services that need to be reachable from outside.
  • All host config is code. Terraform provisions LXCs from inventory; Ansible configures everything inside them. No clicks, no drift.
  • Identity is centralised. Authentik fronts every service that needs more than IP-based gating, via Traefik forward-auth.

Layered architecture

┌──────────────────────────────────────────────────────────────────────┐
│ Layer 6 — Identity │
│ Authentik (10.69.20.68) │
│ ─ forward-auth for *.home.helix9.org behind Traefik │
│ ─ OIDC/SAML for services that speak it natively │
└──────────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────┐
│ Layer 5 — Ingress / TLS │
│ Traefik (10.69.20.40) — single reverse proxy + ACME via Cloudflare │
│ DNS-01. File-provider config rendered by Ansible. │
└──────────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────┐
│ Layer 4 — Services │
│ SERVERS (VLAN 20): Paperless, Pulse, Uptime-Kuma, OneDev, │
│ Docusaurus, Authentik, Traefik, Copyparty, │
│ Mediastack (Jellyfin/Sonarr/Radarr/Sabnzbd) │
│ DMZ (VLAN 70): Synapse, Mumble, Minecraft, OpenClaw, │
│ Hookshot │
│ HOMELAB (VLAN 30): Home Assistant (HAOS VM) │
│ MGMT (VLAN 10): Proxmox, PBS, UniFi │
└──────────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────┐
│ Layer 3 — Network │
│ VyOS home router (vyos-fw) │
│ ─ 8 zones (LOCAL, WAN, MGMT, SERVERS, HOMELAB, TRUSTED, IOT, │
│ GUEST, DMZ, VPN), zone-based stateful firewall │
│ ─ DNS forwarder, DHCP server per zone, NAT, IPsec to VPS │
│ ─ Site-to-site IPsec (10.255.255.0/30) → vyos-edge VPS │
└──────────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────┐
│ Layer 2 — Hypervisor │
│ Proxmox VE — pve02 (active), pve01 (bootstrap only) │
│ ─ LXC for everything Linux-y, VM only for HAOS │
│ ─ Backups → PBS (pbs01) │
└──────────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────┐
│ Layer 1 — Physical │
│ Telekom VDSL → Draytek Vigor 167 (bridge mode) → VyOS eth1.7 │
│ Switch trunk → eth0 (carrier of all VLANs) │
│ UniFi AP trunk → eth2 │
└──────────────────────────────────────────────────────────────────────┘

Network zones

VyOS enforces a strict zone-based firewall. Every interface belongs to exactly one zone; cross-zone traffic is dropped by default.

ZoneVLANSubnetWhat lives here
MGMT1010.69.10.0/24Proxmox, PBS, UniFi controller — admin plane
SERVERS2010.69.20.0/24Internal services accessed via Traefik
HOMELAB3010.69.30.0/24Home Assistant + IoT bridges
TRUSTED4010.69.40.0/24Personal devices (laptops, phones, AppleTV)
IOT5010.69.50.0/24Untrusted IoT (printer, sensors)
GUEST6010.69.60.0/24Guest WiFi, internet-only
DMZ7010.69.70.0/24Public-facing services (port-forwarded via VPS)
VPN10.255.255.0/30IPsec tunnel to VPS
WANdynamicPublic PPPoE interface

Trust direction summary:

  • TRUSTED → everywhere with ALLOW-ALL. The owner's devices are fully trusted.
  • MGMT → everywhere. Admin operations need full reach.
  • SERVERS / HOMELAB / IOT / GUEST / DMZ → internet via ALLOW-INTERNET (with RFC1918 cross-pivot blocked); cross-zone is established-only by default, with explicit per-service holes (e.g. Pulse → MGMT for Proxmox API, NetBox → everywhere for scanning).
  • WAN → only ALLOW-ESTABLISHED returning to internal zones. No unsolicited inbound.

Full zone matrix and per-policy rules in Home Router.


Traffic flows

Internal client → internal service

laptop (TRUSTED)
│ https://paperless.home.helix9.org

VyOS DNS forwarder
│ static mapping: paperless.home.helix9.org → 10.69.20.40 (Traefik)

Traefik (10.69.20.40)
│ TLS terminate, route by Host header
│ middleware: authentik (or local-only for LAN-only services)

backend (10.69.20.72:8000 — paperless)

Same VLAN-to-VLAN passes the SERVERS-LOCAL / SERVERS-MGMT / etc. zone policies; cross-zone only because Traefik is the gateway.

External client → public service (DMZ)

internet
│ https://openclaw.helix9.org

Cloudflare DNS → 152.53.173.192 (VPS secondary IP)


vyos-edge (VPS, 159.195.87.143)
│ DNAT 152.53.173.192:443 → 10.69.20.40:443 (via vti0)

IPsec tunnel (10.255.255.0/30)


vyos-fw (home)
│ routed via vti0 → SERVERS zone

Traefik (10.69.20.40)
│ Authentik forward-auth

backend (e.g. OpenClaw 10.69.70.50)

This is the only path public traffic takes. Home does not expose any port on its own public IP — every external service rides through the VPS tunnel.

Why the VPS

Three reasons:

  1. Stable public IP — Telekom hands out a dynamic IPv4 with daily forced reconnect. The VPS has a static 159.195.87.143 and a secondary 152.53.173.192.
  2. DDoS / scan absorption — bad traffic terminates on the VPS edge, never crosses the home WAN.
  3. Per-service public IP isolation — Mumble/Minecraft/Matrix-federation get the secondary IP; the primary IP is reserved for Matrix HTTPS / federation. Lets the same backend ports coexist.

Infrastructure as Code

Two-stage pipeline. Terraform creates infrastructure, Ansible configures it.

inventory/host_vars/<host>/vars.yml (single source of truth per host)
│ ├─ lxc_cores, lxc_memory, lxc_disk ← Terraform reads
│ └─ <service-specific config> ← Ansible reads

Terraform (terraform/proxmox/) provisions LXC on Proxmox
│ uses bpg/proxmox provider; one .tf file per host

Ansible (playbooks/) configures inside the LXC
│ roles/common, roles/ssh, roles/users → base hardening
│ roles/<service> → service-specific

Service running, registered in DNS via roles/vyos_dns

Adding a new host

The end-to-end flow (full detail in New Host):

  1. Add to inventory/hosts.yml with IP + VMID.
  2. Create inventory/host_vars/<host>/vars.yml with LXC sizing + service vars.
  3. Add an lxc_<host>.tf in terraform/proxmox/ (or use lxc_managed.tf).
  4. terraform apply → LXC exists.
  5. ansible-playbook playbooks/<service>.yml → LXC configured + service running.
  6. ansible-playbook playbooks/vyos_dns.yml → shortname → IP mapping pushed to VyOS DNS.
  7. If the service has a web UI, add a Traefik router (roles/traefik/templates/services.yml.j2) and re-run playbooks/traefik.yml.

Repos

  • /home/marko/code/ansible — inventory, playbooks, roles, terraform/. Hosted at onedev.home.helix9.org/Ansible.
  • /home/marko/code/docusaurus — these docs. Hosted at docs.home.helix9.org, auto-deployed via webhook on push.

Identity, ingress, DNS

These three layers compose end-to-end:

ConcernComponentNotes
Authoritative DNSCloudflarehelix9.org zone — public records + ACME DNS-01 token
Recursive DNSVyOS forwarderPer-zone :53 listener; static mappings for *.home.helix9.org and shortnames; (Technitium LXC at 10.69.20.53 is dormant)
Split horizonVyOS static-host overridespaperless.home.helix9.org10.69.20.40 internally vs. VPS public IP externally
TLS / ingressTraefikOne cert per host via Cloudflare DNS-01; file-provider config rendered by Ansible
AuthN/AuthZAuthentikForward-auth via outpost.goauthentik.io/auth/traefik; OIDC for native integrations

Detailed flow walk-throughs:


Hosts at a glance

HostIPVMIDZoneRole
pve0210.69.10.20MGMTProxmox hypervisor (active)
pbs0110.69.10.25200MGMTProxmox Backup Server
unifi10.69.10.15115MGMTUniFi controller
traefik10.69.20.40240SERVERSReverse proxy + TLS
authentik10.69.20.68268SERVERSIdentity provider
paperless10.69.20.72272SERVERSDocument management
pulse10.69.20.60260SERVERSProxmox monitoring
uptime-kuma10.69.20.75275SERVERSService monitoring
onedev10.69.20.76276SERVERSSelf-hosted Git + CI
docusaurus10.69.20.77277SERVERSThese docs
copyparty10.69.20.20220SERVERSFile server
podman10.69.20.10100SERVERSGeneric container host
technitium10.69.20.53253SERVERSDNS resolver (dormant)
synapse10.69.70.30730DMZMatrix homeserver
hookshot10.69.70.40740DMZMatrix bridge
mumble10.69.70.10710DMZVoice server
minecraft10.69.70.20720DMZMinecraft server
openclaw10.69.70.50750DMZMatrix-integrated game
haos(VLAN 30)101HOMELABHome Assistant OS (VM, not Ansible-managed)
vyos-fwgateways .1LOCALHome router
vyos-edge159.195.87.143(VPS)Public edge router

Source of truth: inventory/hosts.yml.