π homelab docs
all pages
+ new
3D topology
Edit page
Title
Tags (comma-separated)
Body (Markdown β supports raw HTML inside
html
blocks via the
superfences
extension)
# Homelab Topology & Service Routing Three-tier Traefik architecture β browser β service request flow, all hosts and networks, all routed services. State as of 2026-07-06 (post-grizzley-replacement migration complete). ## 1. Physical Hosts ### Public Edge | Host | IP | Role | |------|-----|------| | **Internet / Public DNS** | `47.156.104.83` (apex tophermayor.com) | Cloudflare authoritative DNS for `*.tophermayor.com` | | **UCG Ultra** | LAN `192.168.1.1`, gateway `192.168.50.1` | UniFi OS 5.1.x Β· Network App 10.4.57 Β· 3 internal VLANs (10, 30, 50) Β· LAN DNS resolver + DHCP + DNS Policies | ### Tier 1 β Public Traefik Ingress (LXC) | Host | IP | Role | |------|-----|------| | **CT 102 traefik-lxc** | `192.168.50.115` (LAN) Β· public IP via UCG Ultra | Debian 13 LXC Β· `traefik:v3.x` systemd service Β· 4 entrypoints: `web:80`, `websecure:443`, `sshclone:2222`, `metrics:8080` Β· ~70 HTTP routers + 1 TCP router | ### Tier 2 β Forwarder Layer | Host | IP | Role | |------|-----|------| | **VM 9003 ubuntu** | `192.168.50.61` | Ubuntu 26.04 on PVE Β· own Traefik (public ingress) Β· file-provider forwarders (priority 250) Β· **12 non-migrated containers** + postgres-shared (kept for 30-day rollback until 2026-08-06) | ### Tier 3 β New Primary Compute | Host | IP | Role | |------|-----|------| | **Grizzley (NEW)** | `192.168.50.144` (eth0) Β· `192.168.10.145` (wlan0, VLAN 10) | Raspberry Pi 5 Β· Ubuntu 26.04 LTS (Resolute Raccoon, arm64) Β· Docker 29.6.1 + Compose 5.3.0 Β· bare Traefik 3.0.0 (systemd) Β· NOPASSWD sudo for `bear` | ### Tier 0 β Storage & Other Compute | Host | IP | Role | |------|-----|------| | **TrueNAS** | `192.168.50.12` | NFS server Β· mediadata, backups, traefik-certs | | **Ice** | `192.168.50.197` | Pi 4 Β· Ubuntu 26.04 Β· Immich + traefik-ice + jump host to PVE | | **Panda** | `192.168.30.196` (VLAN 30) | Home Assistant OS (smart home control plane) | | **PVE hypervisor** | `192.168.50.11` | Proxmox VE Β· runs CT 102, CT 104, CT 200, VM 9003 (ubuntu) | | **CT 104 (this machine)** | `192.168.50.x` | Where the docs webapp is hosted Β· LXC container on PVE Β· Hermes default profile | | **CT 200 media-lxc** | `192.168.50.200` | 6c/16GB Β· GPU-passthrough GTX 1080 Β· Jellyfin (29.7x HEVC 1080p transcode) | ## 2. Networks & VLANs | Network | Range | Notes | |---------|-------|-------| | Production (VLAN 50) | `192.168.50.0/24` | gateway `192.168.50.1` Β· 7 clients (truenas, traefik-CT102, termix-CT126, grizzley, hermes-pve-CT104, VectorPro, CT200) | | Family / WiFi (VLAN 10) | `192.168.10.0/24` | grizzley wlan0 `.145` lives here | | Home Assistant (VLAN 30) | `192.168.30.0/24` | panda `.196` | | DMZ / Staging (VLAN 40) | `192.168.40.0/24` | | | Mgmt / UGC Ultra (VLAN 1) | `192.168.1.0/24` | UniFi controller at `.1` | | docker bridge (proxy-net) | `172.19.0.0/16` | grizzley containers & postgres-shared | ## 3. Three-Tier Traefik β Static + Dynamic Config Map ### Tier 1 β CT 102 (public Traefik) ``` /etc/traefik/traefik.yml (STATIC) entryPoints: web:80 β redirectβwebsecure websecure:443 β websecure routers sshclone:2222 β TCP forwarder β gitea metrics:8080 /etc/traefik/dynamic/ (file-provider, hot-reload) βββ conf.yml β wildcard cert + dashboards βββ ubuntu.yml β Host(ubuntu.tophermayor.com) β 192.168.50.61 (legacy) βββ gitea-ssh-forwarder.yml β TCP :2222 β 192.168.50.144:2222 βββ grizzley-backup-routers.yml βββ splash-fallbacks.yml β priority-1 fallbacks βββ media-lxc.yml, pve.yml, truenas.yml, termix.yml, ... β 20+ more βββ 95 DNS policies via UniFi integration v1 ``` ### Tier 2 β ubuntu Traefik (FORWARDER ONLY post-migration) ``` /etc/traefik/dynamic/ βββ grizzley-auth-forwarder.yml β Host(auth.tophermayor.com) + PathPrefix(/outpost) β grizzley:9000 βββ grizzley-migrated-forwarder.yml β gitea/vaultwarden/navidrome/slskd/homepage β grizzley βββ upstream-ingress.yml β homepage public routes (repointed to .144) βββ 12+ other files for ubuntu-local services ``` ### Tier 3 β grizzley bare Traefik (systemd, NOT docker) ``` /etc/traefik/traefik.yml (STATIC) entryPoints: websecure:8443 β app routers metrics:8080 (off by default) /etc/traefik/dynamic/ βββ authentik.yml β Host(auth.tophermayor.com) β :9000 + PathPrefix(/outpost) β :9000 βββ (each app's compose has its own service exposure via ports:, NOT via traefik labels) ``` Auth: `CF_DNS_API_TOKEN` via `/etc/traefik/dns-token.env` (chmod 600). Cert: Let's Encrypt DNS-01 via Cloudflare (one cert for `auth.tophermayor.com`). ## 4. Request Flow β Browser β Service ### 4a. Generic Public Request (e.g. `https://gitea.tophermayor.com`) ``` [Step 1 β DNS resolution (client side)] Browser/curl β Cloudflare DNS β gitea.tophermayor.com β tophermayor.com apex β A 47.156.104.83 (public IP) [Step 2 β TCP/TLS handshake + HTTP request (Tier 1)] Browser β UCG Ultra β CT 102 traefik-lxc :443 (websecure entrypoint) β TLS SNI=gitea.tophermayor.com β wildcard cert from acme.json β dynamic/ubuntu.yml: Host(gitea.tophermayor.com) β ubuntu-traefik svc (priority 100) [Step 3 β Forwarder (Tier 2)] ubuntu Traefik :443 β dynamic/grizzley-migrated-forwarder.yml: grizzley-gitea (priority 250) β svc gitea-grizzley @ http://192.168.50.144:3000 [Step 4 β Backend (Tier 3)] grizzley .144:3000 β gitea container (port 3000) ``` > **Note**: Each service may take additional hops. For `auth.tophermayor.com`, the backend is `:9000` (Authentik). For OIDC forwardAuth on OIDC-protected services, the forwardAuth call hops: CT 102 β ubuntu β grizzley :9000 β outpost.goauthentik.io path. ### 4b. SSH-clone Request (e.g. `git clone gitea.tophermayor.com:2222`) ``` client β Cloudflare β 47.156.104.83:2222 β CT 102 traefik :2222 (sshclone entrypoint, TCP) β dynamic/gitea-ssh-forwarder.yml: tcp.routers.gitea-ssh-public β svc gitea-ssh @ 192.168.50.144:2222 β gitea sshd (port 22 in container) ``` ### 4c. OIDC ForwardAuth on gitea ``` browser β CT 102 :443 β router: Host(gitea.tophermayor.com) middlewares=[forwardAuth,local-only] β forwardAuth β http://192.168.50.144:9000/outpost.goauthentik.io/auth/traefik (hops ubuntu .61 forwarder) β Authentik :9000 checks session, returns 302 to /application/o/authorize/ β If unauthed: 302 β auth.tophermayor.com/application/o/authorize/?... β User logs in via Authentik β cookie set β gitea request succeeds ``` ### 4d. LAN-only request (e.g. `https://gitea.local.tophermayor.com`) ``` LAN client β UCG Ultra LAN DNS (192.168.50.1) β A 47.156.104.83 (or direct to 192.168.50.115 if UniFi has split-horizon) β CT 102 :443 β router: Host(gitea.local.tophermayor.com) middlewares=[local-only,forwardAuth] β Same as 4a from Tier 2 onward ``` ## 5. Per-Service Routing Table | Hostname | Tier 1 (CT 102) | Tier 2 (ubuntu forwarder) | Tier 3 (grizzley) | Backend | Auth | |----------|------------------|---------------------------|-------------------|---------|------| | `gitea.tophermayor.com` | ubuntu.yml: gitea-public (100) | grizzley-migrated-forwarder: grizzley-gitea (250) | β (direct port) | `192.168.50.144:3000` (gitea) | forwardAuth β auth.tophermayor.com | | `gitea.tophermayor.com:2222` | TCP: gitea-ssh-public (200) | β (passthrough) | β (direct port) | `192.168.50.144:2222` (gitea sshd) | SSH key (gitea user account) | | `vaultwarden.tophermayor.com` | ubuntu.yml: vaultwarden-public (200) | grizzley-migrated-forwarder: grizzley-vaultwarden (250) | β (direct port) | `192.168.50.144:80` (vaultwarden) | forwardAuth (cookie session) | | `navidrome.tophermayor.com` | ubuntu.yml: navidrome-public (200) | grizzley-migrated-forwarder: grizzley-navidrome (250) | β (direct port) | `192.168.50.144:4533` (navidrome) | navidrome native session | | `slskd.local.tophermayor.com` | ubuntu.yml: sldk-local (200) | grizzley-migrated-forwarder: grizzley-slskd (250) | β (direct port) | `192.168.50.144:5030` (slskd) | slskd native session | | `homepage.tophermayor.com` | upstream-ingress.yml: homepage (100) | β (bypassed, Tier 2βTier 3 direct) | β (direct port) | `192.168.50.144:3003` (homepage) | forwardAuth | | `homepage.local.tophermayor.com` | upstream-ingress.yml: homepage-local (100) | β (direct) | β (direct port) | `192.168.50.144:3003` | local-only + forwardAuth | | `homepage-grizzley.local.tophermayor.com` | upstream-ingress.yml: homepage-grizzley (250) | grizzley-migrated-forwarder: grizzley-homepage-grizzley (250) | β (direct port) | `192.168.50.144:3003` | forwardAuth | | `auth.tophermayor.com` | β (CT 102 passes through) | grizzley-auth-forwarder: grizzley-authentik (100/2001) | β (direct port) | `192.168.50.144:9000` (authentik) | Authentik native login | | `auth.tophermayor.com/outpost.goauthentik.io/*` | β | grizzley-auth-forwarder: outpost router (2001) | β (direct port) | `192.168.50.144:9000` | β (OIDC forwardAuth endpoint) | | `immich.tophermayor.com` | β | immich route on ubuntu | β (still on ubuntu) | `192.168.50.61:2283` (immich) | forwardAuth (immich OIDC) | | `jellyfin.tophermayor.com` | ubuntu.yml: jellyfin-public (200) | β (still on ubuntu) | β | `192.168.50.200:8096` (jellyfin, media-lxc) | jellyfin native | | `traefik-lxc.lan` | β (own host) | β | β | `192.168.50.115:8080` (metrics) | basic-auth | | `media-lxc.lan` | media-lxc.yml routes | β (still on media-lxc, .200) | β | `192.168.50.200` | varies | ## 6. DNS Layer Details ### Cloudflare (public) Authoritative for `tophermayor.com`. 70 records: - 3 A-records at public IP `47.156.104.83`: `opencode`, `termix`, apex `tophermayor.com` - 10 CNAMEs β apex (auth, cloud, gitea, immich, jellyfin, jellyseerr, jfa, minecraft, n8n, vault) - ~57 TXT records (`_acme-challenge.*` for cert validation, DKIM, etc.) - `navidrome.tophermayor.com` added 2026-07-06 (was missing β caused the public 502) ### UniFi DNS Policies (LAN) Authoritative for `{host}.lan` zones. 95 policies total. | Record | Old β New | Notes | |--------|-----------|-------| | `grizzley.lan` | `.84` β `.144` | Stale fixed 2026-07-06 | | `ct102.lan` | (missing) β `.115` | Added 2026-07-06 | | `ubuntu.lan`, `ice.lan`, `pve.lan`, `truenas.lan`, `media-lxc.lan` | already correct | Verified 2026-07-06 | | `*.local.tophermayor.com` (14 service hostnames) | `.84` β `.144` | aiomanager, aiometadata, aiostreams, komodo, metrics-grizzley, minecraft*, oc-grizz, reccollection, starfield, status, traefik-grizzley, traefik-wildcard | ## 7. Migration State Phase A (Authentik) and Phase B (postgres-shared + 5 apps) complete on 2026-07-06. New grizzley (`.144`) is the new primary. Public Traefik ingress unchanged: CT 102 β ubuntu (file-provider forwarders) β grizzley (`:8443` LAN-side). 30-day rollback window: ubuntu containers stopped, data preserved on disk, postgres-shared still running until 2026-08-06. > **2 stale records intentionally NOT changed**: `*.pi.tophermayor.com β .84` (wildcard, separate host) and `oc-ice.local.tophermayor.com β .84` (OpenCode on ice, not grizzley).
Save
cancel
live preview on the right β