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
This commit is contained in:
363
homelab/concepts/homelab-network-architecture.md
Normal file
363
homelab/concepts/homelab-network-architecture.md
Normal file
@@ -0,0 +1,363 @@
|
||||
---
|
||||
title: Homelab Network Architecture
|
||||
created: 2026-04-29
|
||||
updated: 2026-04-29
|
||||
type: concept
|
||||
tags: [concept, networking, homelab, traefik, ha]
|
||||
sources: []
|
||||
---
|
||||
|
||||
# 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:
|
||||
```yaml
|
||||
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:
|
||||
```yaml
|
||||
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
|
||||
```yaml
|
||||
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
|
||||
```yaml
|
||||
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.
|
||||
|
||||
## Related
|
||||
|
||||
- [[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
|
||||
Reference in New Issue
Block a user