Baseline Setup, Part 4 – Centralized Authentication with Authentik
How I set up centralized authentication using Authentik for my homelab. With SSO, role-based access, and Traefik middleware, I finally have a login system that just works.
Baseline Setup, Part 4 – Centralized Authentication with Authentik
Routing was the easy part—now it’s time to lock things down.
I’ve used basic auth, IP allowlists, and even some homegrown token-based hacks in the past. But nothing has made managing access across a dozen services as smooth as Authentik.
This post walks through how I deployed Authentik outside the Kubernetes cluster (on purpose), how I wired it into services like Traefik and Homepage, and why this kind of central login system is absolutely worth it for a homelab at scale.
🧠 Why Authentik?
Because SSO shouldn’t require Google Workspace.
Authentik gives me:
- Centralized authentication with user/group management
- Built-in OAuth2, SAML, and reverse proxy support
- Direct integration with Traefik middleware
- Per-service policy control (think: roles, labels, conditions)
- A clean UI that doesn’t feel like an afterthought
Plus, it’s open-source and actively developed. And it just plain works.
🧱 Where I Run It
Unlike most of my services, Authentik doesn’t live in Kubernetes.
I run it directly on Overseer, my external Ansible/admin box, using Docker Compose. That keeps it isolated from cluster failures and lets me patch or reboot nodes without locking myself out of access controls.
🧰 Docker Compose Setup
Here’s the simplified stack:
version: '3.4'
services:
postgresql:
image: postgres:12-alpine
restart: unless-stopped
environment:
POSTGRES_DB: authentik
POSTGRES_USER: authentik
POSTGRES_PASSWORD: changeme
volumes:
- db_data:/var/lib/postgresql/data
redis:
image: redis:alpine
restart: unless-stopped
server:
image: authentik/server:latest
restart: unless-stopped
ports:
- "9000:9000" # UI
- "9443:9443" # proxy
environment:
AUTHENTIK_REDIS__HOST: redis
AUTHENTIK_POSTGRESQL__HOST: postgresql
AUTHENTIK_SECRET_KEY: super-secret-key
depends_on:
- postgresql
- redis
volumes:
db_data:
I have secrets and extra config in an .env
file, and it’s all managed via Overseer playbooks now.
🔄 Reverse Proxy + Traefik Integration
Authentik has a built-in reverse proxy provider that plugs right into Traefik using middleware. You define an application in Authentik, generate the middleware snippet, and reference it in your TOML file like this:
[http.middlewares.authentik.forwardAuth]
address = "https://auth.petieclark.com/outpost.goauthentik.io/auth/traefik"
trustForwardHeader = true
authResponseHeaders = ["X-authentik-username", "X-authentik-email"]
Then just attach that middleware to your router:
[http.routers.dashboard]
rule = "Host(`dashboard.petieclark.com`)"
entryPoints = ["websecure"]
service = "homepage"
middlewares = ["authentik"]
tls = true
Boom. Now the service is behind your Authentik login.
🔐 Groups, Policies, and SSO Flow
I have two core groups:
admin
– full access to everythingfamily
– limited dashboard-only access
Services are linked to policies, which check group membership or IP range. I can also limit access to certain apps by time, browser type, or even location if I want to get fancy.
Login flows are standard OAuth2 or reverse proxy headers. You can also customize the UI, which is a nice touch.
🧠 Lessons Learned
- Run Authentik outside the cluster—it’s your lifeline
- Always persist your Postgres volume
- Set up email notifications early (password resets, alerts)
- Traefik + Authentik is a dream combo once configured
🔜 Coming Up Next
Now that routing and access are dialed in, I’ll walk through Homepage, my central dashboard. It's what I use to keep tabs on everything running—from uptime to service health to quick links.