kroskinski.com (~$)
jerry@homelab:~/docs

jerry@homelab:~/docs$ cat architecture.md

Homelab Architecture & The Mesh

Security in a homelab shouldn't mean relying on a tangle of firewall port forwards. Here is a breakdown of how I designed my infrastructure so that no internal service is ever bound to 0.0.0.0 -- everything routes through a tightly controlled reverse proxy layer combined with Authelia for single sign-on (SSO) and multi-factor authentication.

        kroskinski.com root/www              *.kroskinski.com apps
     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
     β”‚  Oracle Cloud VM        β”‚      β”‚  TransIP A records point at   β”‚
     β”‚  its OWN public Caddy   β”‚      β”‚  Wasteland's TAILSCALE IP --  β”‚
     β”‚  (static file_server)   β”‚      β”‚  not actually reachable off   β”‚
     β”‚  unrelated to Wasteland β”‚      β”‚  the tailnet despite being     β”‚
     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β”‚  "public" DNS                  β”‚
                                       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                        β”‚
      [ LAN device ] ──▢ Pi-hole local DNS ──▢          β”‚
      [ Tailscale device ] ─────────────────────────────▢
                                                        β–Ό
                                       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                                       β”‚  Caddy   (runs ON Wasteland)  β”‚
                                       β”‚  binds ONLY LAN IP + Tailscaleβ”‚
                                       β”‚  IP -- never 0.0.0.0          β”‚
                                       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                        β”‚ forward_auth
                                                        β–Ό
                                       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                                       β”‚  Authelia (also on Wasteland) β”‚
                                       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

      Minecraft game ports: router-port-forwarded straight to
      Wasteland, bypassing Caddy entirely -- the one deliberate
      raw public exposure in this whole project.

The Edge & Tailscale

Caddy and Authelia run together, directly on Wasteland -- there's no separate reverse-proxy VM in front of it. Caddy binds only to Wasteland's LAN IP and its own Tailscale IP, never 0.0.0.0. Most *.kroskinski.com subdomains do have public TransIP A records, but they resolve to Wasteland's Tailscale IP -- an overlay-only address that's meaningless to reach from the open internet. On the LAN or over Tailscale, Pi-hole's local DNS records resolve the same hostnames straight to Caddy instead. Apps that actually run on Badlands, or on the external Oracle Uptime VM, are reverse-proxied to *by* Wasteland's Caddy over their Tailscale IPs -- Caddy on Wasteland remains the single entry point regardless of which host serves the request.

The kroskinski.com root site is a genuinely separate thing: it lives on its own Oracle Cloud VM with its own independently, publicly-bound Caddy instance, and has no relationship to Wasteland's traffic at all -- see Website. The only other deliberate public exception anywhere in this project is Minecraft's game ports, router-port-forwarded straight to Wasteland, bypassing Caddy entirely.

Zero-Trust via Authelia

Before Caddy allows traffic to reach private services like Immich or Paperless, it issues a forward-auth request to Authelia. If the device isn't authenticated with SSO and a 2FA hardware key, the packet never makes it to the target container.

  • One-Factor / Two-Factor Policies: Administrative dashboards demand hardware-backed 2FA, while lighter endpoints utilize basic session validation.
  • Internal Mesh: Tailscale overlays everything, allowing secure node-to-node communication between wasteland and badlands without exposing ports to the open internet.

For the full breakdown -- forward-auth vs. real OIDC, session behaviour, and the gotchas that came with rolling it out -- see Single Sign-On. For how this extends across every host in the mesh, not just requests through Caddy, see Multi-Host Management.

Security Rule: If a container doesn't explicitly need external exposure via Caddy, it lives entirely behind the Tailscale tailnet or local Docker bridge networks.

jerry@homelab:~/docs$ β–ˆ

cd ..