Every self-hosted application comes with its own login page, its own user database, and its own password to remember. Ten services means ten separate credentials, ten sessions to manage, and ten places where a compromised password could grant unauthorized access. Authentik solves this by providing a centralized identity provider — one login for everything, with single sign-on, multi-factor authentication, and a complete audit trail of who accessed what and when.
Running your own identity provider on an Ubuntu VPS gives you the security and convenience of enterprise SSO without depending on Okta, Auth0, or Google for authentication. Your credentials never leave your infrastructure, and you control the authentication policies, MFA requirements, and access rules that govern every application in your self-hosted stack.
MassiveGRID Ubuntu VPS includes: Ubuntu 24.04 LTS pre-installed · Proxmox HA cluster with automatic failover · Ceph 3x replicated NVMe storage · Independent CPU/RAM/storage scaling · 12 Tbps DDoS protection · 4 global datacenter locations · 100% uptime SLA · 24/7 human support rated 9.5/10
Deploy a self-managed VPS — from $1.99/mo
Need dedicated resources? — from $19.80/mo
Want fully managed hosting? — we handle everything
Why Centralized Authentication Matters
Without a centralized identity provider, your self-hosted infrastructure accumulates security debt with every new application:
- Password reuse — users (including you) inevitably reuse passwords across services when managing dozens of separate accounts. One compromised service exposes all the others.
- Inconsistent MFA — some services support TOTP, some support WebAuthn, some support neither. Without centralization, enforcing MFA across all applications is impossible.
- No audit trail — when logins are scattered across ten databases, answering "who accessed what and when" requires checking ten separate log files.
- Orphaned accounts — when someone leaves your household or team, you need to remember every service they had access to and disable each account individually.
- Session sprawl — logging into each service separately means managing multiple browser sessions, multiple cookies, and multiple token lifetimes.
A centralized identity provider eliminates all of this. One account, one password, one MFA enrollment, one place to revoke access, and one audit log for everything.
Authentik vs Authelia vs Keycloak
Three identity providers dominate the self-hosting space. Here is how they compare:
Authelia — lightweight forward-auth proxy. Excellent for adding authentication to applications that lack their own login systems. Limited in that it cannot act as a full OIDC/OAuth2 provider or LDAP server. Best for simple setups with few applications that lack native SSO support.
Keycloak — enterprise Java-based identity platform by Red Hat. Extremely powerful but resource-heavy (1–2GB RAM just for Keycloak itself) and complex to configure. The admin interface has hundreds of options that can overwhelm self-hosters. Best for organizations with dedicated IT staff.
Authentik — modern, Python-based identity provider that hits the sweet spot. Full OIDC/OAuth2 provider, SAML support, LDAP outpost, forward-auth proxy, customizable login flows, and an intuitive admin interface. Resource requirements are moderate, and the documentation is written for self-hosters rather than enterprise admins. This is the right choice for most self-hosted environments.
Prerequisites
Authentik runs alongside your other self-hosted services on Docker. Install Docker first using our Docker installation guide for Ubuntu VPS, and set up Nginx by following our Nginx reverse proxy guide.
Authentik runs alongside your other self-hosted services. It requires about 1GB RAM for the main application plus PostgreSQL and Redis — a Cloud VPS with 2 vCPU / 4GB RAM provides comfortable headroom for Authentik alongside several other Docker services.
Docker Compose Setup
Create the Authentik directory and generate the required secret key:
mkdir -p /opt/authentik && cd /opt/authentik
# Generate a secret key (do not change this after initial setup)
echo "AUTHENTIK_SECRET_KEY=$(openssl rand -base64 36)" >> .env
echo "PG_PASS=$(openssl rand -base64 24)" >> .env
Review and extend the environment file:
cat >> /opt/authentik/.env << 'EOF'
# Authentik configuration
AUTHENTIK_ERROR_REPORTING__ENABLED=false
COMPOSE_PORT_HTTP=9000
COMPOSE_PORT_HTTPS=9443
# Email (optional, for password reset and notifications)
# AUTHENTIK_EMAIL__HOST=smtp.yourdomain.com
# AUTHENTIK_EMAIL__PORT=587
# AUTHENTIK_EMAIL__USERNAME=authentik@yourdomain.com
# AUTHENTIK_EMAIL__PASSWORD=smtp_password
# AUTHENTIK_EMAIL__USE_TLS=true
# AUTHENTIK_EMAIL__FROM=authentik@yourdomain.com
EOF
Create the Docker Compose file:
cat > /opt/authentik/docker-compose.yml << 'EOF'
version: "3.8"
services:
server:
container_name: authentik_server
image: ghcr.io/goauthentik/server:latest
restart: always
command: server
environment:
AUTHENTIK_REDIS__HOST: redis
AUTHENTIK_POSTGRESQL__HOST: postgresql
AUTHENTIK_POSTGRESQL__USER: authentik
AUTHENTIK_POSTGRESQL__NAME: authentik
AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
env_file:
- .env
volumes:
- ./media:/media
- ./custom-templates:/templates
ports:
- "127.0.0.1:9000:9000"
- "127.0.0.1:9443:9443"
depends_on:
- postgresql
- redis
worker:
container_name: authentik_worker
image: ghcr.io/goauthentik/server:latest
restart: always
command: worker
environment:
AUTHENTIK_REDIS__HOST: redis
AUTHENTIK_POSTGRESQL__HOST: postgresql
AUTHENTIK_POSTGRESQL__USER: authentik
AUTHENTIK_POSTGRESQL__NAME: authentik
AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
env_file:
- .env
volumes:
- ./media:/media
- ./certs:/certs
- ./custom-templates:/templates
depends_on:
- postgresql
- redis
postgresql:
container_name: authentik_postgres
image: docker.io/library/postgres:16-alpine
restart: always
volumes:
- database:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: ${PG_PASS}
POSTGRES_USER: authentik
POSTGRES_DB: authentik
healthcheck:
test: ["CMD-SHELL", "pg_isready -d authentik -U authentik"]
interval: 10s
timeout: 5s
retries: 5
redis:
container_name: authentik_redis
image: docker.io/library/redis:7-alpine
command: --save 60 1 --loglevel warning
restart: always
volumes:
- redis:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
volumes:
database:
redis:
EOF
Start the stack:
cd /opt/authentik && docker compose up -d
Wait 30–60 seconds for initial database migrations, then verify all containers are running:
docker compose ps
Nginx Reverse Proxy with SSL
Configure Nginx to proxy requests to Authentik. Follow our Nginx reverse proxy guide and SSL certificate guide for the foundation:
cat > /etc/nginx/sites-available/authentik << 'EOF'
server {
listen 80;
server_name auth.yourdomain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name auth.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/auth.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/auth.yourdomain.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:9000;
proxy_set_header Host $host;
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;
# WebSocket support
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
EOF
ln -sf /etc/nginx/sites-available/authentik /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx
Initial Setup — Admin Account and First Tenant
Navigate to https://auth.yourdomain.com/if/flow/initial-setup/ to create the initial admin account. This is only available on first access — once an admin account exists, this URL is disabled.
After logging in, you will see the Authentik admin interface. The key concepts to understand:
- Applications — each service you want to protect (Gitea, Grafana, Immich, etc.) is registered as an application in Authentik.
- Providers — the authentication mechanism for each application (OAuth2/OIDC, SAML, Proxy/Forward Auth, LDAP).
- Flows — customizable authentication sequences (login, enrollment, password recovery). The defaults work well for most setups.
- Outposts — Authentik components that run alongside your applications to handle proxy authentication and LDAP queries. A default embedded outpost handles most needs.
Integration Pattern 1: OIDC/OAuth2 for Native SSO Apps
Many self-hosted applications support OIDC (OpenID Connect) or OAuth2 natively. This is the cleanest integration — users click "Login with Authentik" and are redirected to a centralized login page.
Here is how to connect Gitea as an example:
In Authentik admin:
- Go to Applications, then Providers, then Create
- Select "OAuth2/OpenID Provider"
- Name: "Gitea"
- Authorization flow: default-provider-authorization-implicit-consent
- Client ID: (auto-generated, copy this)
- Client Secret: (auto-generated, copy this)
- Redirect URI:
https://git.yourdomain.com/user/oauth2/authentik/callback - Save, then create an Application pointing to this provider
In Gitea admin (Site Administration, Authentication Sources, Add):
Authentication Type: OAuth2
Provider: OpenID Connect
Client ID: (from Authentik)
Client Secret: (from Authentik)
OpenID Connect Auto Discovery URL: https://auth.yourdomain.com/application/o/gitea/.well-known/openid-configuration
The same pattern works for Grafana, Portainer, Outline, BookStack, and dozens of other self-hosted applications. Each application needs its own provider in Authentik with the correct redirect URI.
For Grafana specifically, add these environment variables to its Docker Compose configuration:
environment:
GF_AUTH_GENERIC_OAUTH_ENABLED: "true"
GF_AUTH_GENERIC_OAUTH_NAME: "Authentik"
GF_AUTH_GENERIC_OAUTH_CLIENT_ID: "your-client-id"
GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET: "your-client-secret"
GF_AUTH_GENERIC_OAUTH_SCOPES: "openid profile email"
GF_AUTH_GENERIC_OAUTH_AUTH_URL: "https://auth.yourdomain.com/application/o/authorize/"
GF_AUTH_GENERIC_OAUTH_TOKEN_URL: "https://auth.yourdomain.com/application/o/token/"
GF_AUTH_GENERIC_OAUTH_API_URL: "https://auth.yourdomain.com/application/o/userinfo/"
GF_AUTH_SIGNOUT_REDIRECT_URL: "https://auth.yourdomain.com/application/o/grafana/end-session/"
Integration Pattern 2: Forward Auth for Apps Without SSO
Many self-hosted applications do not support OAuth2 or any external authentication. For these, Authentik's forward auth integration places an authentication layer in front of the application at the Nginx level — users must authenticate through Authentik before Nginx allows the request through to the backend.
In Authentik admin:
- Go to Applications, then Providers, then Create
- Select "Proxy Provider"
- Name: "App Forward Auth"
- Authorization flow: default-provider-authorization-implicit-consent
- Mode: Forward auth (single application)
- External host:
https://app.yourdomain.com - Save, then create an Application pointing to this provider
In your Nginx site configuration:
server {
listen 443 ssl http2;
server_name app.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/app.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/app.yourdomain.com/privkey.pem;
# Authentik forward auth
location /outpost.goauthentik.io {
internal;
proxy_pass http://127.0.0.1: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;
}
location / {
auth_request /outpost.goauthentik.io;
# Forward authentication headers to the backend
auth_request_set $authentik_username $upstream_http_x_authentik_username;
auth_request_set $authentik_groups $upstream_http_x_authentik_groups;
auth_request_set $authentik_email $upstream_http_x_authentik_email;
proxy_set_header X-authentik-username $authentik_username;
proxy_set_header X-authentik-groups $authentik_groups;
proxy_set_header X-authentik-email $authentik_email;
# Redirect to Authentik login on 401
error_page 401 = @authentik_proxy_signin;
proxy_pass http://127.0.0.1:YOUR_APP_PORT;
proxy_set_header Host $host;
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;
}
location @authentik_proxy_signin {
internal;
add_header Set-Cookie "rd=$scheme://$http_host$request_uri; Path=/; HttpOnly; Secure";
return 302 https://auth.yourdomain.com/outpost.goauthentik.io/start?rd=$scheme://$http_host$request_uri;
}
}
With forward auth, any unauthenticated request to the protected application gets redirected to Authentik's login page. After successful authentication, the user is redirected back to the original URL with access granted.
Integration Pattern 3: LDAP Provider for Legacy Applications
Some applications only support LDAP authentication (older software, some network equipment, certain enterprise tools). Authentik can present itself as an LDAP server:
- In Authentik admin, create an LDAP Provider under Applications, then Providers
- Configure the Base DN (e.g.,
dc=yourdomain,dc=com) - Create an LDAP Outpost under Applications, then Outposts that uses this provider
- The outpost exposes LDAP on port 389 (or 636 for LDAPS) inside Docker
Applications that support LDAP can then authenticate against Authentik using standard LDAP bind operations. Users and groups defined in Authentik appear as LDAP entries.
Adding Users and Groups
Manage users and groups through the Authentik admin interface under Directory:
# Users can also be created via the Authentik API
curl -X POST https://auth.yourdomain.com/api/v3/core/users/ \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"username": "partner",
"name": "Partner Name",
"email": "partner@yourdomain.com",
"is_active": true
}'
Groups provide role-based access control. Common groups for a self-hosted environment:
- admins — full access to all applications and admin interfaces
- family — access to Immich, Paperless-ngx, media services
- developers — access to Gitea, CI/CD, monitoring tools
- guests — limited access to specific shared applications
In each Application's configuration, you can restrict access to specific groups. For example, allow only the "admins" group to access Portainer, while the "family" group can access Immich and Jellyfin.
Multi-Factor Authentication
Authentik supports multiple MFA methods, and because authentication is centralized, enabling MFA in Authentik protects every connected application simultaneously:
TOTP (Time-based One-Time Passwords) — compatible with Google Authenticator, Authy, Bitwarden, and any other TOTP app. Users enroll by scanning a QR code.
WebAuthn / FIDO2 — hardware security keys (YubiKey, SoloKey) and platform authenticators (Touch ID, Windows Hello, Android fingerprint). The strongest MFA option available.
To enforce MFA for all users, modify the default authentication flow:
- Go to Flows and Stages, then Flows, then default-authentication-flow
- Add an "Authenticator Validation Stage" after the password stage
- Configure it to require at least one of: TOTP, WebAuthn, or static recovery tokens
- Add an "Authenticator Setup Stage" for users who have not enrolled in MFA yet
Once configured, users who have not set up MFA will be prompted to enroll during their next login. Users who have MFA configured will be prompted for their second factor after entering their password.
Connecting Your Self-Hosted Apps
Here is a practical checklist for connecting common self-hosted applications to Authentik:
- Immich — supports OAuth2 natively. Create an OAuth2 provider in Authentik, configure Immich's
OAUTH_ENABLED,OAUTH_ISSUER_URL,OAUTH_CLIENT_ID, andOAUTH_CLIENT_SECRETenvironment variables. - Paperless-ngx — use forward auth via Nginx. Paperless-ngx can read the
X-authentik-usernameheader for automatic user creation withPAPERLESS_ENABLE_HTTP_REMOTE_USER=true. - Grafana — native OIDC support, configure via environment variables as shown above.
- Gitea — native OAuth2 support, configure via admin panel Authentication Sources.
- Portainer — supports OAuth2 in Business Edition. For Community Edition, use forward auth.
- Uptime Kuma — use forward auth. The monitoring dashboard itself gets protected by Authentik.
When handling authentication for 10+ services, every login triggers OIDC token generation, session management, and group membership checks. A Dedicated VPS ensures dedicated resources handle auth requests instantly — because a slow identity provider means slow logins across every application in your stack. When authentication is the gateway to everything, latency is unacceptable.
Your Identity Provider Needs 100% Uptime
Your identity provider is the single most critical service in your self-hosted stack. If Authentik goes down, nobody can log into anything — every application behind SSO becomes inaccessible. This is not like a media server going down where the impact is inconvenience. An identity provider outage is a total infrastructure lockout.
MassiveGRID's Proxmox HA clustering provides automatic failover at the hypervisor level. If the physical node running your VPS experiences a hardware failure, your VM is automatically restarted on a healthy node — typically within seconds. Combined with Ceph's triple-replicated storage that ensures your database is intact after failover, your Authentik instance achieves genuine high availability without manual intervention.
The 100% uptime SLA means your authentication infrastructure stays available even during maintenance windows, hardware replacements, and unexpected failures.
Backup Strategy for the Identity Database
The Authentik database contains user accounts, credentials, MFA enrollments, OAuth2 client secrets, group memberships, and flow configurations. Losing this data means reconfiguring every application integration from scratch and requiring every user to re-enroll. Back it up rigorously:
#!/bin/bash
# /opt/authentik/backup.sh — run nightly via cron
BACKUP_DATE=$(date +%Y-%m-%d)
BACKUP_DIR="/backup/authentik"
mkdir -p ${BACKUP_DIR}
# Backup PostgreSQL database
docker exec authentik_postgres pg_dump -U authentik authentik | gzip > ${BACKUP_DIR}/authentik-db-${BACKUP_DATE}.sql.gz
# Backup media directory (custom branding, icons)
tar czf ${BACKUP_DIR}/authentik-media-${BACKUP_DATE}.tar.gz -C /opt/authentik media/
# Backup environment file (contains secret key — encrypt this!)
gpg --symmetric --cipher-algo AES256 -o ${BACKUP_DIR}/authentik-env-${BACKUP_DATE}.gpg /opt/authentik/.env
# Retain 30 days of backups (identity data is critical)
find ${BACKUP_DIR} -name "authentik-*" -mtime +30 -delete
echo "Authentik backup completed: ${BACKUP_DATE}"
Test your restore procedure periodically. Spin up a test instance, restore the database backup, and verify that user accounts, MFA enrollments, and application integrations are intact. A backup that has never been tested is not a backup.
Prefer Managed Identity Infrastructure?
Your identity provider is the master key to your entire self-hosted infrastructure. A vulnerability in the authentication layer compromises everything behind it. Security patches must be applied within hours of release, not days. Backups must be verified automatically, not manually. SSL certificates must renew without fail.
With MassiveGRID's fully managed hosting, our team handles the security-critical maintenance that an identity provider demands — patching, backup verification, SSL management, intrusion monitoring, and 24/7 incident response. Your authentication infrastructure gets the same operational rigor as a commercial identity service, with the privacy and control of self-hosting. When the security of every application depends on one service, managed infrastructure is not a luxury — it is risk management.