Authelia: Add Single Sign-On to Any Self-Hosted App
HOW TO GUIDES March 24, 2026, 5:30 p.m.

Authelia: Add Single Sign-On to Any Self-Hosted App

Imagine a world where every self‑hosted tool you run—whether it’s a Git server, a password manager, or a media library—shares a single, secure login. No more juggling dozens of credentials, no more forgotten passwords, and no more patchwork solutions that break with the next update. Authelia makes that vision a reality by providing a powerful, open‑source Single Sign‑On (SSO) gateway that sits in front of any web application you can think of.

What Is Authelia?

Authelia is a modern authentication and authorization server written in Go. It acts as a reverse proxy that intercepts HTTP requests, validates the user’s identity, and then forwards the request to the protected backend if the user is authorized. Because it supports a wide range of authentication methods—LDAP, OAuth2, TOTP, WebAuthn, and more—it can serve as a universal gatekeeper for heterogeneous environments.

At its core, Authelia follows the “defense‑in‑depth” principle. It doesn’t replace your existing identity provider; instead, it augments it with multi‑factor authentication (MFA) and fine‑grained access control policies. This makes it especially attractive for developers who want to secure their self‑hosted stacks without sacrificing flexibility.

Key Concepts

  • Authentication Backend: Where user credentials live (e.g., LDAP, file‑based, or external OAuth2).
  • Authorization Policies: YAML rules that decide which users or groups can access which resources.
  • Two‑Factor Authentication: Built‑in support for TOTP, Duo, and WebAuthn devices.
  • Reverse Proxy Integration: Works seamlessly with Nginx, Traefik, Caddy, or any HTTP proxy that can forward authentication headers.

Prerequisites & Installation

Before you dive into Autoloader configuration, make sure you have a Docker‑enabled host, a domain name that resolves to that host, and at least one self‑hosted app you want to protect. Authelia runs best in a Docker Compose stack, but you can also run it as a standalone binary if you prefer.

The following steps assume a Docker Compose setup. Adjust paths and versions as needed for your environment.

  1. Create a dedicated directory for the stack, e.g., authelia-stack.
  2. Inside that directory, create a docker-compose.yml file with the services you need.
  3. Prepare a persistent volume for Authelia’s configuration and secrets.
version: "3.8"

services:
  authelia:
    image: authelia/authelia:latest
    container_name: authelia
    restart: unless-stopped
    environment:
      - TZ=UTC
    volumes:
      - ./authelia/config:/config
      - ./authelia/db:/var/lib/authelia
    ports:
      - "9091:9091"
    networks:
      - internal

  nginx:
    image: nginx:stable-alpine
    container_name: nginx
    restart: unless-stopped
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d
    ports:
      - "80:80"
      - "443:443"
    depends_on:
      - authelia
    networks:
      - internal
      - external

networks:
  internal:
    internal: true
  external:
    external: true

In this minimal stack, Nginx will act as the front‑line reverse proxy, forwarding authentication requests to Authelia on port 9091. The internal network isolates the two services, while the external network exposes Nginx to the outside world.

Configuring Authelia

Authelia’s behavior is driven by a single YAML file, typically located at /config/configuration.yml. This file defines the authentication backend, the MFA providers, and the access control rules. Below is a working example that uses a file‑based user database and TOTP for second‑factor authentication.

# /config/configuration.yml
host: 0.0.0.0
port: 9091

jwt_secret: "replace_this_with_a_strong_random_string"

default_redirection_url: https://dashboard.example.com

authentication_backend:
  file:
    path: /config/users_database.yml

access_control:
  default_policy: deny
  rules:
    - domain: "git.example.com"
      policy: two_factor
    - domain: "vault.example.com"
      policy: one_factor

session:
  name: authelia_session
  secret: "another_strong_random_string"
  expiration: 3600
  inactivity: 300
  domain: example.com

totp:
  issuer: "example.com"
  period: 30
  skew: 1

The users_database.yml file holds user entries and hashed passwords. Authelia ships with a handy authelia hash-password CLI to generate BCrypt hashes.

# Example users_database.yml
users:
  alice:
    password: "$2y$12$KIXQ9YwXGzDk9hN1Yk8iUe5ZKf/1c3JY2hZ6Q5WbVwK9l/6g8aTGa"
    displayname: "Alice Doe"
    email: "alice@example.com"
    groups:
      - admins
  bob:
    password: "$2y$12$9eB3LzQ5v5FjXhK3pZ6Y3eJ4V6u1hT9YvK0c2W1XcJ4v9x0c7gP5a"
    displayname: "Bob Smith"
    email: "bob@example.com"
    groups:
      - developers

Notice the access_control section: it denies everything by default and then explicitly allows two‑factor authentication for the Git subdomain and one‑factor for a vault service. You can extend these rules to cover any domain or URL pattern you host.

Enabling LDAP and Duo

If your organization already runs an LDAP directory, replace the file backend with an ldap block. Authelia will bind to the LDAP server, search for users, and validate passwords against the directory. Adding Duo as a secondary factor is as simple as providing your Duo integration key, secret key, and API hostname.

authentication_backend:
  ldap:
    url: "ldap://ldap.example.com:389"
    base_dn: "dc=example,dc=com"
    additional_users_dn: "ou=users"
    user:
      username_attribute: "uid"
      mail_attribute: "mail"
    group:
      name_attribute: "cn"
    admin:
      username: "admin"
      password: "admin_password"

duo_api:
  hostname: "api-12345678.duosecurity.com"
  integration_key: "DIXXXXXXXXXXXXXXXXXX"
  secret_key: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"

With these additions, Authelia can serve both internal employees (via LDAP) and external collaborators (via file‑based accounts) while enforcing Duo push notifications for the highest security tier.

Adding SSO to a Self‑Hosted App: Gitea Example

Let’s walk through a concrete scenario: protecting a Gitea instance (a lightweight Git server) with Authelia. The goal is to have users log in once at git.example.com, be prompted for TOTP, and then seamlessly access Gitea without re‑entering credentials.

  1. Deploy Gitea as a Docker container on the same internal network.
  2. Configure Nginx to route / requests to Gitea and /authelia requests to Authelia.
  3. Set up Authelia’s access_control rule for the Gitea domain.

Below is an Nginx configuration snippet that demonstrates the required proxying and header forwarding.

# /nginx/conf.d/git.example.com.conf
server {
    listen 80;
    server_name git.example.com;

    # Enforce HTTPS (let's assume you have certbot handling TLS)
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name git.example.com;

    ssl_certificate /etc/letsencrypt/live/git.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/git.example.com/privkey.pem;

    # Protect the whole site with Authelia
    location / {
        # Forward the request to Gitea
        proxy_pass http://gitea:3000;
        # Forward authentication headers set by Authelia
        proxy_set_header Remote-User $remote_user;
        proxy_set_header Remote-Groups $remote_groups;
        # Preserve the original host
        proxy_set_header Host $host;
    }

    # Authelia endpoint
    location /authelia {
        internal;
        proxy_pass http://authelia:9091;
        proxy_set_header Content-Length "";
        proxy_pass_request_body off;
    }

    # Authelia authentication check
    auth_request /authelia;
    auth_request_set $remote_user $upstream_http_remote_user;
    auth_request_set $remote_groups $upstream_http_remote_groups;
}

Notice the auth_request directive. Nginx forwards the request to Authelia, which either returns 200 OK (user authenticated) or 302 Redirect (user needs to log in). Once authenticated, Authelia injects Remote-User and Remote-Groups headers that Gitea can consume.

Gitea itself needs a tiny tweak to trust these headers. Add the following to app.ini:

[security]
INSTALL_LOCK = true
REVERSE_PROXY_AUTHENTICATION_HEADER = Remote-User
REVERSE_PROXY_AUTHORIZATION_HEADER = Remote-Groups

After reloading both Nginx and Gitea, visiting https://git.example.com will redirect you to Authelia’s login page. Once you enter your credentials and TOTP code, you’ll be sent back to Gitea as the authenticated user.

Protecting Multiple Apps with a Single Authelia Instance

Because Authelia sits at the network edge, you can protect dozens of services—Portainer, Nextcloud, Home Assistant, and more—by simply adding new server_name blocks in Nginx and corresponding rules in the access_control section. This eliminates the need to configure each app individually for SSO, dramatically reducing operational overhead.

Real‑World Use Cases

  • Development Teams: Centralize login for Git, CI/CD dashboards, and internal wikis, ensuring every commit is traceable to a two‑factor‑authenticated user.
  • Home Labs: Secure access to Plex, Home Assistant, and a private Docker registry without exposing each service to the internet.
  • Small Enterprises: Replace legacy VPN + password combos with a zero‑trust model that requires MFA before any internal web app is reachable.

In each scenario, Authelia acts as a single point of truth for authentication, allowing you to audit login attempts, enforce password policies, and rotate secrets centrally.

Pro Tips

Tip 1: Store jwt_secret and session.secret in Docker secrets or an external vault. Hard‑coding them in the YAML file is convenient for demos but a security risk in production.

Tip 2: Use the default_redirection_url to funnel users to a dashboard that aggregates all your services. It provides a seamless “portal” experience after login.

Tip 3: Enable log_level: debug only while troubleshooting. Authelia’s logs are verbose and can quickly fill up storage if left on.

Common Pitfalls & How to Avoid Them

  • Missing HTTPS on Authelia: Authelia requires TLS for secure cookie transmission. If you terminate TLS at Nginx, ensure the secure_cookie flag is set to false only in local testing.
  • Incorrect Header Names: Nginx must forward the exact header names defined in REVERSE_PROXY_AUTHENTICATION_HEADER. A typo will cause the backend to treat every request as unauthenticated.
  • Session Expiration Mismatch: Align session.expiration with your proxy’s timeout settings to avoid premature logouts.
  • Overly Broad Access Rules: The default policy of deny is a safety net. Always double‑check that each domain you intend to expose has an explicit rule.

Conclusion

Authelia turns the cumbersome task of managing separate logins for each self‑hosted service into a streamlined, secure SSO experience. By leveraging a reverse‑proxy architecture, flexible backends, and robust MFA options, you can protect everything from personal hobby projects to enterprise‑grade infrastructure with a single, auditable gateway.

Start small—protect a single app like Gitea—then expand the policy set to cover your entire stack. With the configuration patterns and tips outlined above, you’ll be well on your way to a zero‑trust, user‑friendly environment that scales alongside your ambitions.

Share this article