--- type: reference description: "One Caddy fronts both hosts." tags: - architecture - network timestamp: 2026-09-02 --- # Network Architecture One Caddy fronts both hosts. It runs as a container on Dankclaw (192.168.0.143) and terminates TLS for every service on the LAN. Pi-hole on Dankclaw answers the service names for LAN clients; Porkbun answers them for the WAN. The G36 router firewall governs external access. SearXNG outbound traffic exits through the Gluetun VPN container. ## Topology As of 2026-08-28 the front door is a two-tier chain: Caddy terminates TLS, Anubis verifies the client (DENY known AI scrapers, CHALLENGE everyone else), and accepted traffic returns to Caddy's internal listener on `:8016`, which proxies every request whole to the Authentik server with the Host header preserved; Authentik's embedded outpost routes on that Host against each proxy provider's `external_host`, serves the login flow in place for sessionless clients, and forwards authenticated traffic back to Caddy's post-auth listener `:8017`, where per-vhost routing reaches the app. See [[Anubis]] and [[Authentik]]. ```mermaid graph TB EXT[Internet] -->|port forwards 80/443| CADDY[Caddy TLS :80 :443 — Dankclaw] LAN[LAN clients] -->|Pi-hole DNS :53| CADDY subgraph Dankclaw[Dankclaw 192.168.0.143] CADDY -->|unwrapped vhosts route direct| DIRECT{direct routes} CADDY -->|guarded vhosts| ANUBIS[Anubis verify :8923] ANUBIS -->|deny AI bots| EXT ANUBIS -->|challenge solved or transport-exempt| INT[Caddy internal listener :8016] INT -->|whole request, Host preserved| AUTH[Authentik embedded outpost :9000] AUTH -->|session valid, provider internal_host| POST[Caddy post-auth listener :8017] POST --> HOME[Homepage file_server] POST --> SEARCH[SearXNG via Gluetun netns :8081] POST --> PROM[Prometheus :9090] DIRECT -->|3000 + ssh 2222| GITEA[Gitea] DIRECT -->|3005| OWEBUI[OpenWebUI] DIRECT -->|3002| GRAFANA[Grafana :3000] DIRECT -->|8083 web UI| PIHOLE[Pi-hole] AUTH -->|login UI + sessions| AUTHDB[(Authentik Postgres :5432)] SEARCH -.->|tunnel exit| GLU[Gluetun VPN] GLU -.-> EXT end subgraph Dankserver[Dankserver 192.168.0.235] ROMM[RomM :8085] COPY[Copyparty :3923] CAL[Calibre-Web :8083] PLEX[Plex :32400] JEL[Jellyfin :8096] ARR[*arr stack + qBittorrent] end POST -->|romm| ROMM POST -->|files| COPY DIRECT -->|plex plain-HTTP passthrough| PLEX DIRECT --> CAL DIRECT --> JEL DIRECT --> ARR ``` Guarded (through Anubis): homepage, search, prometheus, romm, files. Exempt by construction: `auth.` (the IdP login itself), plex (plain HTTP), gitea (git smart-HTTP clients cannot solve JS challenges — `/info/refs` and `git-*-pack` pass unchallenged), grafana (own auth). Dankserver runs no proxy of its own. Its services expose published LAN ports, and the Dankclaw Caddy routes the names to those ports. ## Hostnames | Scope | Convention | Resolved by | |-------|------------|-------------| | LAN | `romm.franksdank.cloud` → 192.168.0.143 | Pi-hole (`addn-hosts`) | | WAN | `romm.franksdank.cloud` → 71.227.227.172 | Porkbun A record | Users type a name and nothing else. Caddy maps the name to the upstream. The split between the two resolvers removes the need for router NAT loopback. See [[LAN-DNS]] for the flow and the router hand-off. ## TLS Caddy holds one Let's Encrypt certificate per vhost, issued and renewed through the DNS-01 challenge via the Porkbun module. No inbound port 80/443 is required. Details in [[Caddy]]. ## Gluetun Path (SearXNG only) `gluetun.container`, `searxng.container` and `searxng-valkey.container` all set `Network=searxng.network` in their Quadlet sources (runtime network `systemd-searxng`); only those three share the tunnel. The old compose idiom (`network_mode: service:gluetun`) is gone — a shared named network is what carries SearXNG's outbound traffic through the VPN exit. Everything else on Dankclaw uses the normal LAN route. This matches KB Pattern 2 in [[Gluetun]]. See [[Container Network Namespaces]] for which addresses are reachable from that namespace (none of the unpublished host-netns listeners). ## Access Policy - The **G36 router firewall** governs what the WAN can reach. Port forwards are manual router steps; the repo tracks no router state. - Access is layered: Anubis challenges/denies bots at the front door, then Authentik's embedded outpost (whole-request proxy, routed by `Host` → provider `external_host`) gates the wrapped apps — one proxy provider per guarded host is mandatory, and Anubis exempts the `/outpost.goauthentik.io/*` transport paths so login can happen before a challenge cookie exists. Apps with their own login (Grafana, Gitea, Plex) run unwrapped. See [[Anubis]] and [[Authentik]]. - LAN subnet: `192.168.0.0/24`. ## See Also - [[LAN-DNS]] — name resolution, Pi-hole, router hand-off - [[Caddy]] — vhost map, TLS, basic auth - [[Dankserver Stack]], [[Dankclaw Stack]] - [[Gluetun]] - Knowledge base: [[Gluetun]], [[SearXNG]] - [[Container Network Namespaces]] — who can dial what on Dankclaw (host netns vs bridge nets)