Build notes for a three-site, GitOps-managed homelab: Docker Compose, Traefik, Authentik SSO, self-hosted mail, media automation, and the pitfalls hit along the way. Written so you (or future me) can rebuild it from scratch, in order. Start with the series.
Self-hosted mail: Stalwart behind a smarthost chain
The boss fight, documented: inbound through the VPS, a mailstore the internet can’t reach, and outbound through a retry-ladder of relay providers, DMARC-aligned on the root domain no matter which rung delivers.
Split-horizon DNS: same names, shorter path
Public hostnames that resolve to the local proxy when you’re at site A: same URLs everywhere, no hairpin through the VPS for local traffic, and the OAuth quirk the shortcut drags into the light.
Backups: restic to local + B2, restore-tested
Nightly restic snapshots of appdata to a local disk AND cloud object storage, databases dumped properly, keys that live on paper, and the quarterly restore drill that finds what the green checkmarks hide.
Observability without the Prometheus tax
Four small tools instead of a monitoring distro: live metrics, every host’s logs in one tab, uptime checks that page the phone, and a dashboard tying it together. What you give up, and why it doesn’t hurt at this scale.
The *arrs, properly: naming templates, quality profiles, and recyclarr
The deep dive on library automation: exact naming templates that feed Plex cleanly, quality profiles that stop the upgrade churn, custom formats without the madness, and recyclarr so none of it lives only in a web UI.
Plex, properly: a full setup, and why not Jellyfin (yet)
The whole Plex page: the honest Plex-vs-Jellyfin call, hardware transcoding that actually engages, the /data mount convention that makes hardlinks work, naming the scanner loves, and wiring the *arrs in cleanly.
The download pipeline: gluetun and the VPN-namespace trick
The plumbing half of bender’s media stack: download clients that live inside a VPN network namespace, the label trick namespace-sharing requires, and the restart gotcha that otherwise pages you at 3 a.m.
Komodo: git push to deploy
Komodo Core watches the repo and redeploys app stacks on push. Secrets decrypt in a pre-deploy hook, the agent runs as systemd on purpose, and the webhook gets treated like the weather: usually fine, never trusted.
Authentik: one login for everything
A single Authentik core with a lightweight outpost on every host: forward-auth for apps that can’t do auth, OIDC for apps that can, config as code where the product allows, and four pitfalls ranked by how down production went.
Traefik part 2: the public edge
A cheap VPS fronts everything: TLS, auth at the door, Crowdsec bouncing the scanners, then proxying over the overlay to services whose disks it can’t even see. Plus the TLS error whose message will not help you.
Traefik part 1: proxies inside the walls
One Traefik per host, wildcard certs via DNS-01 with zero open ports, and routing declared as labels on the containers themselves. Plus three footguns, ranked by how many hours each took from me.
ZeroTier: a private /24 across three sites
One flat 10.99.0.0/24 spanning site A, site B, and the VPS. No port forwards, no router surgery, and the two-nodes-one-NAT collision that silently makes everything slow.