Files
hermes-ice/homelab/concepts/homelab-network-architecture.md
Hermes Agent e4d91aadf9 Initial commit: homelab infrastructure wiki
- Full Obsidian vault content
- Host configs (ice, grizzley, ubuntu, proxmox, truenas, panda, hyte)
- Media stack documentation
- Traefik HA setup
- Automation scripts
- Bachelor party planning
2026-05-24 16:08:40 -07:00

17 KiB

title, created, updated, type, tags, sources
title created updated type tags sources
Homelab Network Architecture 2026-04-29 2026-04-29 concept
concept
networking
homelab
traefik
ha

Homelab Network Architecture

Complete traffic flow and routing topology for the homelab cluster. Covers Traefik dual-instance HA, VRRP failover, certificate distribution, Docker network segmentation, and all routing rules.

Traffic Flow Overview

Internet (Cloudflare DNS)
        │
        ▼  *.tophermayor.com A → home public IP
══════════════════════════════════════════════════════════════════════
  VRRP VIP 192.168.50.80/27 (eth0.50) — keepalived
  ┌─────────────────────────────────────────────────────────────┐
  │  PRIMARY: ubuntu traefik (when up)                         │
  │  BACKUP:  grizzley traefik-pi (when ubuntu fails)         │
  └─────────────────────────────────────────────────────────────┘
        │
        ▼ port 80/443
┌──────────────────────────────────────────────────────────────────┐
│                    grizzley traefik-pi                          │
│  Edge ingress controller (ACME master, Cloudflare DNS challenge) │
│  IP: 192.168.50.84 | Ports: 80,443,2222,8080,19132udp,19134udp  │
│  Network: traefik-proxy                                         │
│  Certs: /mnt/truenas/traefik-certs/grizzley (NFS)             │
└──────────────────────────────────────────────────────────────────┘
        │
        ├──[grizzley-local services]──────────────────────────► served directly
        │    vaultwarden, uptime-kuma, komodo, homepage,
        │    aiostreams, aiomanager, aiometadata,
        │    opencode-ice, homeassistant, proxmox, truenas
        │
        └──[everything else]────────────────────────────────────► forwarded to ubuntu
             (upstream-ingress.yml load-balances to ubuntu:443)

DNS Zones

Zone Example Resolution
Public (*.tophermayor.com) gitea.tophermayor.com, jellyfin.tophermayor.com Cloudflare → home public IP
Local (*.local.tophermayor.com) sonarr.local.tophermayor.com, proxmox.local.tophermayor.com UniFi Controller DHCP/DNS

Cloudflare proxies all *.tophermayor.com — origin IP is hidden, DDoS protection active.

Network Segmentation

Physical / VLAN

Network Subnet Gateway Hosts
Production (VLAN 50) 192.168.50.0/24 192.168.50.1 ice, grizzley, ubuntu, proxmox, truenas
Default (VLAN 1) 192.168.1.0/24 192.168.1.1 Management workstations
Trusted (VLAN 3) 192.168.3.0/24 Trusted devices
WireGuard VPN 192.168.4.0/24 VPN clients
Docker bridge 172.16.0.0/12 Container internal networking

Docker Networks (ubuntu)

Network Driver Subnet Connected Services
proxy-net bridge 172.18.0.0/16 traefik (primary ingress), homepage-ubuntu
app-net bridge 172.20.0.0/16 general application containers
uefi-proxynet bridge 172.26.0.0/16
authentik_authentik-internal bridge authentik server/worker/redis
monitoring_monitoring-internal bridge prometheus, grafana, loki, alertmanager
immich_immich-internal bridge immich stack
reccollection-internal bridge reccollection stack
ai-subscriptions_default bridge ai-subscriptions
infisical_infisical bridge infisical stack

Docker Networks (grizzley)

Network Driver Connected Services
traefik-proxy bridge traefik-pi, homepage-grizzley, komodo, aiostreams, aiomanager, aiometadata, vaultwarden, uptime-kuma
aiomanager_default bridge aiomanager stack
aiometadata_aiometadata-internal bridge aiometadata stack
komodo_komodo-internal bridge komodo stack
homepage_default bridge homepage-grizzley
desktop-test_default bridge test containers

High Availability (VRRP / Keepalived)

Two Traefik instances provide failover via keepalived VRRP on VLAN 50.

Parameter Value
Interface eth0.50 (VLAN 50)
Virtual Router ID 51
ubuntu priority PRIMARY (higher)
grizzley priority BACKUP (90)
Virtual IP 192.168.50.80/27
Auth PASS (HomelabH)
Health check /etc/keepalived/check_traefik.sh — 2s interval, fall 2, rise 2

When ubuntu Traefik fails health checks, keepalived promotes grizzley to MASTER and the VIP moves to grizzley's interface. Traffic for *.tophermayor.com and *.local.tophermayor.com then routes to grizzley's traefik-pi (192.168.50.84).

Certificate Architecture

Cloudflare DNS Challenge (grizzley traefik-pi)
        │
        ▼
ACME writes certs to /etc/traefik/certs/acme.json
        │
        ▼ (real-time via NFS)
/mnt/truenas/traefik-certs/grizzley (NFS share from TrueNAS)
        │
        ▼ (read by ubuntu traefik at startup/reread)
ubuntu traefik serves same wildcard certs (*.tophermayor.com)

Both instances serve the same Cloudflare-issued wildcard certificate (*.tophermayor.com) for all public-facing services. The ACME challenge only runs on grizzley — ubuntu syncs certs via NFS.

Traefik Instance Comparison

Aspect ubuntu (PRIMARY) grizzley (BACKUP / ACME)
Container traefik traefik-pi
Image traefik:v3.6.7 traefik:v3.6.7
IP 192.168.50.61 192.168.50.84
Port 80/443 Direct Direct
HTTP→HTTPS
Cloudflare ACME ✗ (reads via NFS) ✓ (origin)
Static configs middlewares.yml middlewares.yml
Dynamic configs 29 files 4 files
Networks proxy-net, app-net, uefi-proxynet traefik-proxy
Metrics port 8080
SSH proxy port 2222
UDP Minecraft 19132, 19134
upstream-ingress (receives traffic) forwards to ubuntu

Traefik Dynamic Configs

grizzley (Edge / ACME)

File Contents
pi-routers.yml Wildcard cert triggers (traefik-wildcard.local.tophermayor.com, traefik-wildcard.tophermayor.com)
grizzley-services.yml 11 local routers: vaultwarden, uptime-kuma, komodo, homepage, opencode-ice, aiostreams, aiomanager, aiometadata, homeassistant, proxmox, truenas
upstream-ingress.yml Forwards all unmatched traffic to ubuntu Traefik (HTTPS 192.168.50.61)
metrics.yml Internal metrics endpoints
middlewares.yml IP allowlists (local-only, homepage-localonly), security headers

ubuntu (Primary Router)

File Contents
gitea.yml gitea.tophermayor.com → gitea:3000
immich.yml immich.tophermayor.com → immich_server:2283
jellyfin.yml jellyfin.tophermayor.com → jellyfin:8096 (rate limit + jellyfin headers)
media-stack.yml sonarr, radarr, lidarr, prowlarr, qbittorrent, sabnzbd, readarr, sonarr-anime, radarr-anime, lazylibrarian, nzbdav → via gluetun VPN tunnel
opencode.yml opencode.tophermayor.com → host.docker.internal:4096
proxmox.yml proxmox.local.tophermayor.com → https://192.168.50.11:8006
homepage-widgets.yml Internal routes (sonarr-internal, radarr-internal, etc.) → gluetun VPN tunnel
upstream-ingress.yml Homepage routes to homepage-ubuntu:3003 and homepage-grizzley:3000
whisper.yml whisper.local.tophermayor.com → faster-whisper-server:8394
truenas.yml truenas.local.tophermayor.com → TrueNAS web UI
navidrome.yml navidrome.tophermayor.com
audiobookshelf.yml audiobooks.tophermayor.com
calibre-web.yml calibre-web.local.tophermayor.com
kavita.yml kavita.tophermayor.com
rustfs.yml rustfs S3 routes
stremio.yml stremio routes
jellyseerr.yml jellyseerr.tophermayor.com
comparaison.yml comparison service
inventory.yml inventory service
cabo-voting.yml Cabo voting app
gsd-mcp.yml GSD MCP server
ai-subscriptions.yml AI subscriptions service
hermes-dashboard.yml Hermes dashboard routes
homeassistant.yml Home Assistant route
umm.yml Unified media manager
middlewares.yml Full middleware stack (see below)

All Traefik Routes

grizzley traefik-pi (Local Services)

Domain Service Backend Middleware Cert
vaultwarden.tophermayor.com vaultwarden vaultwarden:80 cloudflare
status.tophermayor.com uptime-kuma uptime-kuma:3001 cloudflare
komodo.local.tophermayor.com komodo komodo:9120 cloudflare
homepage.local.tophermayor.com homepage homepage-grizzley:3000 homepage-localonly cloudflare
opencode-ice.local.tophermayor.com opencode-ice 192.168.50.197:4096 local-only cloudflare
aiostreams.tophermayor.com aiostreams aiostreams:3002 cloudflare
aiomanager.tophermayor.com aiomanager aiomanager:1610 cloudflare
aiometadata.tophermayor.com aiometadata aiometadata:1337 cloudflare
ha.tophermayor.com homeassistant 192.168.30.196:8123 cloudflare
proxmox.local.tophermayor.com proxmox 192.168.50.11:8006 local-only cloudflare
truenas.local.tophermayor.com truenas 192.168.50.12:8080 local-only cloudflare
traefik-grizzley.local.tophermayor.com dashboard api@internal local-only cloudflare
metrics-grizzley.local.tophermayor.com metrics api@internal local-only cloudflare

grizzley traefik-pi (Upstream → ubuntu)

Traffic NOT matched above is forwarded via upstream-ingress.yml:

Rule Target
HostRegexp(^[a-z0-9-]+\.local\.tophermayor\.com$) && !homepage && !traefik-grizzley && !metrics-grizzley && !traefik-wildcard && !opencode-ice → ubuntu:443
HostRegexp(^[a-z0-9-]+\.tophermayor\.com$) && !traefik-wildcard → ubuntu:443

ubuntu traefik (Public Routes — *.tophermayor.com)

Domain Backend Middleware
gitea.tophermayor.com gitea:3000 homelab-public
immich.tophermayor.com immich_server:2283 homelab-public
jellyfin.tophermayor.com jellyfin:8096 ratelimit, jellyfin-headers
audiobooks.tophermayor.com audiobookshelf homelab-public
navidrome.tophermayor.com navidrome homelab-public
kavita.tophermayor.com kavita:5000 homelab-public
opencode.tophermayor.com host.docker.internal:4096 local-only, opencode-streaming, opencode-cors
ha.tophermayor.com 192.168.30.196:8123 (see homeassistant.yml)
jellyseerr.tophermayor.com jellyseerr homelab-public

ubuntu traefik (Local Routes — *.local.tophermayor.com)

Domain Backend Middleware Notes
sonarr.local.tophermayor.com gluetun:8989 local-only Via VPN tunnel
radarr.local.tophermayor.com gluetun:7878 local-only Via VPN tunnel
lidarr.local.tophermayor.com gluetun:8686 local-only Via VPN tunnel
sabnzbd.local.tophermayor.com gluetun:8080 local-only Via VPN tunnel
qbittorrent.local.tophermayor.com qbittorrent local-only
prowlarr.local.tophermayor.com prowlarr local-only
readarr.local.tophermayor.com readarr local-only
sonarr-anime.local.tophermayor.com sonarr-anime local-only Via VPN tunnel
radarr-anime.local.tophermayor.com radarr-anime local-only Via VPN tunnel
flaresolverr.local.tophermayor.com flaresolverr local-only
bazarr.local.tophermayor.com bazarr:6767 local-only
lazylibrarian.local.tophermayor.com lazylibrarian local-only
nzbdav.local.tophermayor.com nzbdav local-only
calibre-web.local.tophermayor.com calibre-web:8083 local-only
stremio.local.tophermayor.com stremio-server local-only
proxmox.local.tophermayor.com 192.168.50.11:8006 proxmox-headers, local-only
truenas.local.tophermayor.com 192.168.50.12:8080 local-only
opencode-ice.local.tophermayor.com 192.168.50.197:4096 local-only
whisper.local.tophermayor.com faster-whisper-server:8394 local-only
traefik.local.tophermayor.com api@internal local-only Dashboard

Internal Widget Routes (sonarr-internal, etc.)

These are *-internal.local.tophermayor.com routes for Homepage widgets, accessible only inside the network via the gluetun VPN tunnel. From homepage-widgets.yml:

Internal Domain Backend (via gluetun)
sonarr-internal.local.tophermayor.com gluetun:8989
radarr-internal.local.tophermayor.com gluetun:7878
lidarr-internal.local.tophermayor.com gluetun:8686
sabnzbd-internal.local.tophermayor.com gluetun:8080
seerr-internal.local.tophermayor.com seerr:5055
jellyfin-internal.local.tophermayor.com jellyfin:8096
prometheus-internal.local.tophermayor.com prometheus:9090

Special Protocols

Protocol Port Host Purpose
HTTP→HTTPS 80 grizzley Redirects to 443
HTTPS 443 grizzley All TLS traffic
QUIC/HTTP3 443/udp grizzley HTTP3 support
Traefik metrics 8080 grizzley Prometheus scraping
Gitea SSH proxy 2222 grizzley → ubuntu:2222
Minecraft Bedrock 19132/udp grizzley Bedrock server (standby)
Minecraft Bedrock 19134/udp grizzley Bedrock server (sison)

Middleware Chains (ubuntu)

homelab-public

Applied to: gitea, immich, audiobookshelf, navidrome, kavita, jellyseerr, etc.

chain: [compress, security-headers, buffering, ratelimit]

Security Headers

Applied to most services:

browserXssFilter: true
contentTypeNosniff: true
forceSTSHeader: true
stsIncludeSubdomains: true
stsPreload: true
stsSeconds: 31536000        # 1 year
customFrameOptionsValue: SAMEORIGIN

Jellyfin-specific Headers

Adds CSP allowing jsDelivr CDN for the Ultrachromic theme:

contentSecurityPolicy: "style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://fonts.googleapis.com; ..."

Authentik ForwardAuth (SSO)

Applied to: sonarr, radarr, lidarr, prowlarr, bazarr, sabnzbd, transmission, qbittorrent, flaresolverr, jellyseerr, listsync, dockge, it-tools, bentopdf, code-ai, and more.

Each service has its own middleware with X-authentik-host query param:

http://authentik-server:9000/outpost.goauthentik.io/auth/traefik?X-authentik-host=<domain>

local-only IP Allowlist

sourceRange:
  - 127.0.0.1/32
  - 192.168.50.0/24   # Production
  - 192.168.1.0/24    # Management
  - 192.168.3.0/24    # Trusted
  - 192.168.4.0/24    # WireGuard VPN
  - 172.16.0.0/12     # Docker
  - 10.0.0.0/8        # VPN/Docker

Rate Limiting

average: 100
burst: 50

VPN Tunnel (gluetun)

Media automation services route through gluetun VPN container for privacy when connecting to torrent/indexer services:

  • sonarr → gluetun:8989
  • radarr → gluetun:7878
  • lidarr → gluetun:8686
  • sabnzbd → gluetun:8080

gluetun ports: 8000, 8388, 8888 (TCP), 8388 (UDP) — exposed on ubuntu's Docker network.

SSH Routing

Gitea SSH is proxied through grizzley:

Internet → grizzley:2222 (SNI * → any)
    → forwards to ubuntu:2222
    → gitea container handles git SSH protocol

UniFi Controller

Network services (DHCP, DNS, VLAN tagging) managed by UniFi Controller at 192.168.1.1 (or similar). All internal DNS for *.local.tophermayor.com resolves through the UniFi DNS forwarder.

  • traefik — Traefik entity page
  • grizzley — RPi5 edge node (ACME master, backup ingress)
  • ubuntu — Primary Docker host (primary ingress router)
  • truenas — NFS storage for cert sync
  • traefik-ha — HA concept page
  • homepage — Dashboard services with widget routes
  • authentik — SSO identity provider
  • sso-authentik — SSO configuration details