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.
- Create a dedicated directory for the stack, e.g.,
authelia-stack. - Inside that directory, create a
docker-compose.ymlfile with the services you need. - 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.
- Deploy Gitea as a Docker container on the same
internalnetwork. - Configure Nginx to route
/requests to Gitea and/autheliarequests to Authelia. - Set up Authelia’s
access_controlrule 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_secretandsession.secretin 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_urlto funnel users to a dashboard that aggregates all your services. It provides a seamless “portal” experience after login.Tip 3: Enable
log_level: debugonly 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_cookieflag is set tofalseonly 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.expirationwith your proxy’s timeout settings to avoid premature logouts. - Overly Broad Access Rules: The default policy of
denyis 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.