Self-Host Authentik: Your Own Identity Provider in 20 Minutes
Tired of managing separate logins for every self-hosted service? Authentik is an open-source identity provider that brings enterprise-grade SSO, MFA, and user management to your homelab — without the enterprise-grade complexity (or price tag).
In this guide, you'll deploy Authentik with Docker Compose, connect it to reverse proxies like Traefik or Nginx, and secure your entire stack behind a single login.
Why Self-Host Your Identity Provider?
Every app you self-host needs authentication. Without a central identity provider, you're juggling:
- Duplicate user accounts across services
- Inconsistent password policies
- No unified MFA enforcement
- Manual user provisioning for family/team members
Authentik solves this with OIDC, SAML, LDAP, and proxy provider support — meaning virtually any self-hosted app can delegate authentication to it. Think of it as your own private Okta or Auth0.
What Makes Authentik Different?
Unlike simpler SSO solutions, Authentik offers:
- Visual flow editor — customize login/signup flows without code
- Policy engine — attribute-based access control
- Multi-tenancy — separate branding and policies per domain
- Event monitoring — audit log of every authentication attempt
Prerequisites
- VPS or server with 2+ CPU cores, 4GB RAM (8GB recommended for production)
- Docker and Docker Compose installed
- A domain with DNS A record pointing to your server (e.g.,
auth.yourdomain.com) - Reverse proxy (Traefik, Nginx, or Caddy) with SSL certificates
Step 1: Create the Docker Compose File
Create a directory for Authentik and its configuration:
mkdir -p ~/authentik && cd ~/authentik
mkdir -p media custom-templates certs
Create docker-compose.yml:
version: "3.8"
services:
postgresql:
image: docker.io/library/postgres:16-alpine
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"]
start_period: 20s
interval: 30s
timeout: 10s
retries: 5
volumes:
- database:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: ${PG_PASS:?database password required}
POSTGRES_USER: ${PG_USER:-authentik}
POSTGRES_DB: ${PG_DB:-authentik}
env_file:
- .env
redis:
image: docker.io/library/redis:alpine
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
start_period: 20s
interval: 30s
timeout: 10s
retries: 5
volumes:
- redis:/data
server:
image: ghcr.io/goauthentik/server:2024.10
restart: unless-stopped
command: server
environment:
AUTHENTIK_REDIS__HOST: redis
AUTHENTIK_POSTGRESQL__HOST: postgresql
AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
volumes:
- ./media:/media
- ./custom-templates:/templates
- ./certs:/certs
- /var/run/docker.sock:/var/run/docker.sock
ports:
- "9000:9000"
- "9443:9443"
depends_on:
- postgresql
- redis
worker:
image: ghcr.io/goauthentik/server:2024.10
restart: unless-stopped
command: worker
environment:
AUTHENTIK_REDIS__HOST: redis
AUTHENTIK_POSTGRESQL__HOST: postgresql
AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
user: root
volumes:
- ./media:/media
- ./custom-templates:/templates
- ./certs:/certs
- /var/run/docker.sock:/var/run/docker.sock
depends_on:
- postgresql
- redis
volumes:
database:
redis:
Step 2: Configure Environment Variables
Create .env with secure values:
# Database Configuration
PG_USER=authentik
PG_DB=authentik
PG_PASS=$(openssl rand -base64 36 | tr -dc 'a-zA-Z0-9' | head -c 32)
# Authentik Security
AUTHENTIK_SECRET_KEY=$(openssl rand -base64 60 | tr -dc 'a-zA-Z0-9' | head -c 50)
# Email Configuration (optional, for password resets)
# AUTHENTIK_EMAIL__HOST=smtp.yourdomain.com
# AUTHENTIK_EMAIL__PORT=587
# [email protected]
# AUTHENTIK_EMAIL__PASSWORD=your_smtp_password
# AUTHENTIK_EMAIL__USE_TLS=true
# [email protected]
Generate the secrets and write them to .env:
cat > .env << 'EOF'
PG_USER=authentik
PG_DB=authentik
PG_PASS=$(openssl rand -base64 36 | tr -dc 'a-zA-Z0-9' | head -c 32)
AUTHENTIK_SECRET_KEY=$(openssl rand -base64 60 | tr -dc 'a-zA-Z0-9' | head -c 50)
EOF
Step 3: Launch Authentik
docker compose pull
docker compose up -d
Wait for the database migrations to complete (check logs):
docker compose logs -f server
Look for: Server started
Step 4: Initial Setup
Open https://your-server-ip:9443 (or http://localhost:9000 if testing locally).
You'll see a setup screen asking for:
- Email — your admin account email
- Password — strong admin password
- Token — leave blank for new installations
After setup, log in at the default URL. You'll land in the Admin Interface.
Step 5: Configure Your First Application
Let's secure a simple app — say, whoami.yourdomain.com — using Authentik's proxy provider.
Create an Application
- Go to Applications → Applications
- Click Create
- Name:
Whoami - Slug:
whoami - Provider: Create new Proxy Provider
Configure the Proxy Provider
For the proxy provider:
- Type: Forward auth (single application)
- External host:
https://whoami.yourdomain.com - Internal host:
http://whoami:80(your app's internal address)
Update Your Reverse Proxy
For Traefik, add this middleware to your whoami service:
labels:
- "traefik.http.middlewares.authentik.forwardauth.address=http://authentik-server:9000/outpost.goauthentik.io/auth/traefik"
- "traefik.http.middlewares.authentik.forwardauth.trustForwardHeader=true"
- "traefik.http.middlewares.authentik.forwardauth.authResponseHeaders=X-authentik-username,X-authentik-groups,X-authentik-entitlements,X-authentik-email,X-authentik-name,X-authentik-uid,X-authentik-jwt,X-authentik-meta-jwks,X-authentik-meta-outpost,X-authentik-meta-provider,X-authentik-meta-app,X-authentik-meta-version"
- "traefik.http.routers.whoami.middlewares=authentik"
For Nginx, add to your server block:
location / {
proxy_pass http://whoami:80;
# Authentik forward auth
auth_request /outpost.goauthentik.io/auth/nginx;
error_page 401 = @goauthentik_proxy_signin;
auth_request_set $x_authentik_username $upstream_http_x_authentik_username;
auth_request_set $x_authentik_groups $upstream_http_x_authentik_groups;
auth_request_set $x_authentik_email $upstream_http_x_authentik_email;
auth_request_set $x_authentik_name $upstream_http_x_authentik_name;
auth_request_set $x_authentik_uid $upstream_http_x_authentik_uid;
proxy_set_header X-authentik-username $x_authentik_username;
proxy_set_header X-authentik-groups $x_authentik_groups;
proxy_set_header X-authentik-email $x_authentik_email;
proxy_set_header X-authentik-name $x_authentik_name;
proxy_set_header X-authentik-uid $x_authentik_uid;
}
location /outpost.goauthentik.io {
proxy_pass http://authentik-server:9000/outpost.goauthentik.io;
proxy_set_header Host $host;
proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
Step 6: Test the Flow
- Navigate to
https://whoami.yourdomain.com - You should be redirected to Authentik's login page
- Log in with your admin credentials
- You're redirected back to the app — now authenticated
Check the headers to confirm Authentik is passing identity data:
curl -H "X-authentik-username: test" https://whoami.yourdomain.com
Step 7: Add MFA (Recommended)
Enforce two-factor authentication for all users:
- Go to Policies → Policy Bindings
- Create a policy: Group → Users → All users
- Bind to default-authentication-flow
- Set Must pass: True
Users will now be prompted to set up TOTP or WebAuthn on next login.
Verification Checklist
- [ ] Authentik admin interface loads at
https://auth.yourdomain.com - [ ] Can create users and groups in Admin Interface
- [ ] Proxy provider redirects unauthenticated requests to login
- [ ] After login, user is redirected back to original app
- [ ] App receives
X-authentik-usernameheader - [ ] MFA prompt appears if policy is enforced
Next Steps
Now that Authentik is running:
- Connect more apps — Grafana, Portainer, and Nextcloud all support OIDC
- Set up LDAP — for apps that don't support modern protocols
- Create user groups — map to different access levels per app
- Enable email — for password resets and notifications
- Monitor events — check Events for failed login attempts
Related Guides
- Self-Host Portainer: Manage All Your Docker Containers from One Dashboard in 15 Minutes
- Self-Host WireGuard: Your Own Secure VPN in 10 Minutes
- Self-Host Traefik: The Ultimate Reverse Proxy for Your Homelab
Questions or hit a snag? Drop a comment below or reach out on our community channels.