Authentik vs Authelia: Self-Hosted SSO Compared

Quick Verdict

Authelia is the better choice for most self-hosters. It does one thing well — adding authentication and MFA in front of your reverse proxy — and it does it with minimal resource usage and a straightforward YAML config. If all you need is to protect your web apps behind a login portal with two-factor auth, Authelia gets you there in minutes with under 30 MB of RAM.

Pick Authentik when you need a real identity provider: SAML support, user provisioning, an admin GUI for managing dozens of users, or SCIM directory sync. It is a full IAM platform, not an auth proxy. That power costs 800+ MB of RAM and a more involved setup.

The Core Difference

This is not an apples-to-apples comparison. These tools solve different problems that happen to overlap:

Authelia is an authentication proxy. It sits between your reverse proxy (Traefik, Nginx, Caddy) and your applications. When a user tries to access a protected app, the reverse proxy asks Authelia whether the request is authenticated. If not, the user sees a login portal. Authelia itself does not manage application access at the protocol level — it gates HTTP requests.

Authentik is a full identity provider (IdP). It speaks OIDC, SAML 2.0, LDAP, SCIM, and RADIUS. Applications connect to Authentik directly using standard identity protocols. It has a web-based admin console, user self-service portal, enrollment flows, and a policy engine. It is closer to Keycloak or Okta than it is to Authelia.

The overlap is that both can protect self-hosted apps with SSO and MFA. The question is how much identity infrastructure you actually need.

Feature Comparison

FeatureAuthentikAuthelia
ArchitectureFull identity providerAuth proxy / portal
OpenID Connect (OIDC)Full providerCertified provider (since v4.38)
SAML 2.0Full providerNot supported
LDAPBuilt-in LDAP outpostConsumer only (can auth against LDAP)
Forward Auth (Traefik/Nginx)Via embedded outpostNative — this is the primary mode
Multi-Factor AuthTOTP, WebAuthn/FIDO2, SMS, email, DuoTOTP, WebAuthn/FIDO2, Duo
Admin UIFull web-based admin consoleNone — YAML configuration only
User Self-ServicePortal with profile, app links, enrollmentPassword reset, MFA registration
User DirectoryBuilt-in with groups, attributes, SCIM syncFile-based (users.yml) or LDAP backend
Policy EngineVisual flow designer with conditions and stagesAccess control rules in YAML
Branding/ThemingPer-tenant branding, custom CSS, logoBasic theming via CSS overrides
Idle RAM Usage~800 MB - 1.2 GB (server + worker + PostgreSQL)~20-30 MB (Authelia only)
LanguagePython (Django) + Go (outposts)Go
LicenseMIT (Enterprise features available)Apache 2.0
GitHub Stars~20k~24k
Docker SupportOfficial Compose with server + worker + PostgreSQLSingle container + optional DB

Docker Compose: Authentik

Authentik requires three services: PostgreSQL, the server, and a background worker. As of 2025.10+, Redis is no longer required — PostgreSQL handles caching and task queuing.

Create a .env file first:

# Generate required secrets
echo "PG_PASS=$(openssl rand -base64 36 | tr -d '\n')" >> .env
echo "AUTHENTIK_SECRET_KEY=$(openssl rand -base64 60 | tr -d '\n')" >> .env

Your .env file should look like this:

# PostgreSQL password -- used by both the database and Authentik
PG_PASS=your-generated-password-here

# Authentik secret key -- used for signing tokens and cookies
AUTHENTIK_SECRET_KEY=your-generated-secret-here

# Optional: customize exposed ports (defaults: 9000/9443)
# COMPOSE_PORT_HTTP=9000
# COMPOSE_PORT_HTTPS=9443

docker-compose.yml:

services:
  postgresql:
    image: postgres:16-alpine
    container_name: authentik-db
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"]
      start_period: 20s
      interval: 30s
      retries: 5
      timeout: 5s
    volumes:
      - database:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: ${PG_PASS}
      POSTGRES_USER: authentik
      POSTGRES_DB: authentik
    networks:
      - authentik

  server:
    image: ghcr.io/goauthentik/server:2025.12.4
    container_name: authentik-server
    restart: unless-stopped
    command: server
    environment:
      AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
      AUTHENTIK_POSTGRESQL__HOST: postgresql
      AUTHENTIK_POSTGRESQL__USER: authentik
      AUTHENTIK_POSTGRESQL__NAME: authentik
      AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
    volumes:
      - ./media:/media
      - ./custom-templates:/templates
    ports:
      - "${COMPOSE_PORT_HTTP:-9000}:9000"
      - "${COMPOSE_PORT_HTTPS:-9443}:9443"
    depends_on:
      postgresql:
        condition: service_healthy
    networks:
      - authentik

  worker:
    image: ghcr.io/goauthentik/server:2025.12.4
    container_name: authentik-worker
    restart: unless-stopped
    command: worker
    environment:
      AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
      AUTHENTIK_POSTGRESQL__HOST: postgresql
      AUTHENTIK_POSTGRESQL__USER: authentik
      AUTHENTIK_POSTGRESQL__NAME: authentik
      AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
    # user: root
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./media:/media
      - ./certs:/certs
      - ./custom-templates:/templates
    depends_on:
      postgresql:
        condition: service_healthy
    networks:
      - authentik

volumes:
  database:

networks:
  authentik:

Start it:

docker compose up -d

Navigate to http://your-server:9000/if/flow/initial-setup/ to create the admin account. Authentik exposes a full admin dashboard at /if/admin/.

Docker Compose: Authelia

Authelia is a single Go binary. For a basic setup with a local SQLite database and file-based users, you need one container and two config files.

Create the directory structure:

mkdir -p ./authelia/config ./authelia/secrets

Generate secrets:

openssl rand -base64 32 > ./authelia/secrets/JWT_SECRET
openssl rand -base64 32 > ./authelia/secrets/SESSION_SECRET
openssl rand -base64 32 > ./authelia/secrets/STORAGE_ENCRYPTION_KEY

docker-compose.yml:

services:
  authelia:
    image: authelia/authelia:4.39.15
    container_name: authelia
    restart: unless-stopped
    volumes:
      - ./authelia/config:/config
      - ./authelia/secrets:/secrets
    environment:
      TZ: "UTC"
      AUTHELIA_IDENTITY_VALIDATION_RESET_PASSWORD_JWT_SECRET_FILE: "/secrets/JWT_SECRET"
      AUTHELIA_SESSION_SECRET_FILE: "/secrets/SESSION_SECRET"
      AUTHELIA_STORAGE_ENCRYPTION_KEY_FILE: "/secrets/STORAGE_ENCRYPTION_KEY"
    ports:
      - "9091:9091"
    networks:
      - authelia

networks:
  authelia:

Create ./authelia/config/configuration.yml:

# Authelia configuration
# Docs: https://www.authelia.com/configuration/

server:
  address: "tcp://0.0.0.0:9091"

log:
  level: info

totp:
  issuer: selfhosting.sh

authentication_backend:
  file:
    path: /config/users.yml
    password:
      algorithm: argon2id
      iterations: 3
      memory: 65536
      parallelism: 4
      salt_length: 16

access_control:
  default_policy: deny
  rules:
    # Allow public access to specific subdomains
    - domain: "public.example.com"
      policy: bypass
    # Require two-factor for sensitive apps
    - domain: "*.example.com"
      policy: two_factor

session:
  cookies:
    - name: authelia_session
      domain: "example.com"     # CHANGE THIS to your root domain
      authelia_url: "https://auth.example.com"  # CHANGE THIS
      expiration: 1h
      inactivity: 5m

storage:
  local:
    path: /config/db.sqlite3

notifier:
  filesystem:
    filename: /config/notification.txt
  # For production, use SMTP instead:
  # smtp:
  #   address: "smtp://mail.example.com:587"
  #   sender: "[email protected]"
  #   username: "[email protected]"
  #   password: "your-smtp-password"

Create ./authelia/config/users.yml:

# User accounts
# Generate password hashes: docker run --rm authelia/authelia:4.39.15 crypto hash generate argon2
users:
  admin:
    displayname: "Admin"
    # Password: changeme (CHANGE THIS - generate a proper hash)
    password: "$argon2id$v=19$m=65536,t=3,p=4$your-generated-hash-here"
    email: [email protected]
    groups:
      - admins
      - users

Start it:

docker compose up -d

Authelia is now listening on port 9091. You still need to configure your reverse proxy (Traefik, Nginx Proxy Manager, or Caddy) to use Authelia as a forward authentication provider. That is where the actual protection happens.

Performance and Resource Usage

This is where the difference is stark.

MetricAuthentikAuthelia
Container count3 (server + worker + PostgreSQL)1 (Authelia only)
Idle RAM800 MB - 1.2 GB total20-30 MB
RAM under load1.5 - 2 GB+50-100 MB
CPU (idle)Moderate — Python + background workerNegligible — compiled Go binary
Minimum specs2 CPU cores, 2 GB RAMRuns on a Raspberry Pi Zero
Disk (application)~500 MB (images + database)~20 MB (binary + SQLite)
Startup time15-30 seconds (migrations, worker init)1-2 seconds

Authentik is a Django application with a background worker process, a PostgreSQL database, and (prior to 2025.10) a Redis cache. That stack adds up. On a 4 GB homelab server running other services, Authentik takes a noticeable chunk.

Authelia is a single statically-compiled Go binary. It starts instantly, barely touches the CPU, and can run alongside dozens of other containers without anyone noticing. If your server has 2 GB of RAM or less, Authelia is the practical choice.

Setup Complexity

Authelia requires editing YAML config files by hand. There is no admin UI. You define users in a file (or point to an LDAP backend), write access control rules in YAML, and configure your reverse proxy to forward auth requests. The configuration surface is small and well-documented. Most setups take 15-30 minutes.

Authentik gives you a web-based admin console with a visual flow designer for authentication flows. You can configure OIDC providers, SAML applications, user enrollment, and access policies through a GUI. The trade-off is that the initial setup is more involved — understanding flows, stages, providers, and outposts takes time. Expect 1-2 hours for a first deployment with application integrations.

The irony: Authelia’s lack of a GUI makes simple setups faster. Authentik’s GUI makes complex setups manageable but adds overhead for simple ones.

Use Cases

Choose Authelia If…

  • You want to add login + MFA in front of apps that do not support SSO natively (dashboards, admin panels, monitoring tools)
  • You run Traefik, Nginx, or Caddy and want forward auth middleware
  • Your server has limited resources (Raspberry Pi, 2 GB VPS)
  • You have fewer than 20 users
  • You prefer declarative YAML configuration over GUIs
  • You do not need SAML, LDAP server, or SCIM
  • You want the fastest path to “all my apps are behind a login page”

Choose Authentik If…

  • You need a proper identity provider that speaks OIDC and SAML to applications
  • You manage users across multiple apps and want centralized provisioning
  • You want a web-based admin console for managing users, groups, and policies
  • You need LDAP server functionality (Authentik can expose an LDAP interface)
  • You run applications that require SAML 2.0 (many enterprise apps do)
  • You want customizable authentication flows (enrollment, password reset, conditional MFA)
  • You have the hardware headroom — at least 2 GB of RAM available for auth infrastructure

What About OIDC?

Both support OpenID Connect, but differently.

Authelia earned OpenID Certified status with v4.38. It can act as an OIDC provider for applications that support it. This is a significant addition — apps like Portainer, Grafana, and Gitea can authenticate directly against Authelia via OIDC without relying on forward auth. The OIDC support is newer and covers the common cases well.

Authentik has had OIDC support since its early days. Its implementation is more mature, with support for more grant types, token customization, and advanced claim mapping. If your applications rely heavily on OIDC features like dynamic client registration or complex scope configurations, Authentik has the edge.

For most self-hosted apps that just need “login with OIDC,” both work fine.

Final Verdict

For a typical self-hoster running 5-20 apps on a single server or small cluster, Authelia is the right tool. It protects everything behind a clean login portal with MFA, it barely uses any resources, and you can have it running in under 30 minutes. The addition of OIDC support means it now covers the vast majority of authentication needs without the overhead of a full IdP.

Authentik is the right tool when Authelia is not enough. If you are building a multi-user environment, need SAML for specific applications, want a GUI for user management, or are running infrastructure that resembles an organization more than a homelab, Authentik delivers enterprise-grade identity management without the enterprise price tag.

Neither is objectively better. They solve different problems at different scales. But for the question most people are actually asking — “how do I put a login page in front of my self-hosted apps?” — the answer is Authelia.