Security intermediate ⏱ 45 minutes

Authelia: Lightweight SSO for Homelabs

Single sign-on and 2FA with minimal resources. Perfect for resource-constrained homelabs.

By homelabbing.io • 2025-12-16
#authelia#sso#2fa#authentication#lightweight

Introduction

Managing authentication across multiple homelab services becomes cumbersome as your infrastructure grows. Each application with its own login credentials creates security risks and user friction. Authelia solves this problem by providing a lightweight, open-source authentication and authorization server that adds single sign-on (SSO) and multi-factor authentication (MFA) to your existing applications through your reverse proxy.

Unlike heavyweight identity providers like Keycloak or Authentik, Authelia is purpose-built for homelabs and small deployments. It runs with minimal resources (50-100MB RAM), integrates seamlessly with popular reverse proxies (Traefik, Nginx Proxy Manager, Caddy), and provides enterprise-grade security features without the complexity.

In this comprehensive guide, you’ll learn how to deploy Authelia with Docker, configure two-factor authentication, integrate with Traefik and Nginx reverse proxies, implement granular access control rules, and set up bypass rules for specific services.

What You’ll Build:

  • Production-ready Authelia instance with PostgreSQL backend
  • TOTP-based two-factor authentication
  • WebAuthn/security key support
  • Integration with Traefik reverse proxy
  • Alternative Nginx Proxy Manager integration
  • Fine-grained access control policies
  • Bypass rules for API endpoints and specific services
  • Session management and remember-me functionality

Why Choose Authelia?

  • Lightweight: 50-100MB RAM (vs Keycloak’s 4-8GB or Authentik’s 2-4GB)
  • Fast Deployment: Running in under 10 minutes with Docker Compose
  • Reverse Proxy Native: Designed specifically for forward auth patterns
  • Privacy-First: All authentication data stays on your infrastructure
  • Active Development: Regular updates and security patches
  • Flexible Storage: Supports PostgreSQL, MySQL, SQLite, and file-based backends

Prerequisites

Before starting, ensure you have:

Technical Requirements:

  • Server with 1 CPU core, 1GB RAM, 5GB storage
  • Docker 20.10.0+ and Docker Compose 1.27.0+
  • Reverse proxy: Traefik 2.0+ or Nginx/Nginx Proxy Manager
  • Domain name (e.g., auth.example.com, example.local)
  • DNS configured to point to your server
  • (Optional) SMTP credentials for password reset emails

Knowledge Requirements:

  • Basic Docker and command line familiarity
  • Understanding of DNS and reverse proxies
  • YAML configuration experience helpful

Preparation:

# Verify Docker installation
docker --version  # Should be 20.10.0+
docker-compose --version  # Should be 1.27.0+

# Create working directory
mkdir -p ~/authelia
cd ~/authelia

Section 1: Understanding Authelia Architecture

What is Forward Authentication?

Authelia implements the “forward authentication” pattern, where your reverse proxy delegates authentication decisions to Authelia:

User Request → Reverse Proxy → Authelia (check auth)
                    ↓
             Protected Service (if authenticated)
                    or
             Login Page (if not authenticated)

Flow breakdown:

  1. User requests https://app.example.com
  2. Reverse proxy sends auth verification request to Authelia
  3. Authelia checks for valid session cookie
  4. If valid: reverse proxy forwards request to application
  5. If invalid: redirect to https://auth.example.com login portal

Benefits:

  • Applications don’t need to know about Authelia
  • Centralized authentication for all services
  • Add SSO to apps without native support
  • Consistent login experience

Authelia Components

Authentication Portal: Web interface where users log in, enroll 2FA devices, and manage sessions. Served by Authelia at your authentication domain (e.g., auth.example.com).

Session Provider: Manages authenticated sessions using encrypted cookies. Supports Redis for distributed deployments or in-memory for single instances.

User Database: Stores user credentials and metadata. Supports file-based YAML (simple), LDAP (enterprise), or custom backends.

Storage Backend: Persists TOTP secrets, WebAuthn devices, consent records. PostgreSQL, MySQL, or SQLite.

Notifier: Sends email notifications for password resets and identity verification. Requires SMTP configuration.

Access Control Engine: Evaluates rules to determine if users can access resources based on domain, path, groups, IP addresses, and more.

Authelia vs Alternatives

FeatureAutheliaAuthentikKeycloak
Primary Use CaseForward auth for reverse proxiesFull IdPEnterprise IdP
RAM Usage50-100MB2-4GB4-8GB
Setup Time10 minutes30 minutes60+ minutes
OAuth2/OIDCLimited (v4.38+)✅ Full Support✅ Full Support
LDAP Provider❌ Client only✅ Yes✅ Yes
Forward Auth✅ Native⚠️ Via proxy⚠️ Manual setup
Best ForHomelab reverse proxiesSMB with diverse SSO needsEnterprise deployments

Choose Authelia if:

  • Using Traefik, Nginx, or Caddy reverse proxy
  • Want minimal resource usage
  • Need quick setup with file-based user management
  • Primarily protecting web applications behind reverse proxy
  • Don’t need SAML or complex OAuth2 provider functionality

Section 2: Installing Authelia with Docker

Step 1: Create Project Structure

Set up the directory structure for Authelia configuration:

# Create directories
mkdir -p ~/authelia/{config,secrets}
cd ~/authelia

# Set restrictive permissions on secrets
chmod 700 secrets

Step 2: Generate Secrets

Authelia requires several cryptographic secrets for security:

# Generate JWT secret (used for session tokens)
openssl rand -hex 32 > secrets/jwt_secret

# Generate session secret (encrypts session cookies)
openssl rand -hex 32 > secrets/session_secret

# Generate storage encryption key (encrypts TOTP secrets)
openssl rand -hex 32 > secrets/storage_encryption_key

# Display generated secrets (save these securely!)
echo "JWT Secret: $(cat secrets/jwt_secret)"
echo "Session Secret: $(cat secrets/session_secret)"
echo "Storage Encryption Key: $(cat secrets/storage_encryption_key)"

# Secure permissions
chmod 600 secrets/*

Important: Store these secrets in a password manager. Loss of the storage encryption key means loss of all TOTP enrollments.

Step 3: Create Docker Compose Configuration

Create the Docker Compose file for Authelia and PostgreSQL:

# docker-compose.yml
version: '3.8'

services:
  authelia:
    image: authelia/authelia:latest
    container_name: authelia
    volumes:
      - ./config:/config
      - ./secrets:/secrets:ro
    networks:
      - proxy
      - authelia
    environment:
      - TZ=America/New_York
    ports:
      - "9091:9091"
    restart: unless-stopped
    depends_on:
      - postgres

  postgres:
    image: postgres:16-alpine
    container_name: authelia-postgres
    environment:
      POSTGRES_DB: authelia
      POSTGRES_USER: authelia
      POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password
    volumes:
      - postgres-data:/var/lib/postgresql/data
    networks:
      - authelia
    secrets:
      - postgres_password
    restart: unless-stopped

networks:
  proxy:
    external: true  # Shared with Traefik/Nginx
  authelia:
    driver: bridge

volumes:
  postgres-data:

secrets:
  postgres_password:
    file: ./secrets/postgres_password

Generate PostgreSQL password:

# Generate and save PostgreSQL password
openssl rand -base64 24 > secrets/postgres_password
chmod 600 secrets/postgres_password

Network configuration notes:

  • proxy network: External network shared with your reverse proxy (Traefik/Nginx)
  • authelia network: Internal network for Authelia and PostgreSQL only
  • Ensures PostgreSQL is not accessible from reverse proxy network

Step 4: Create Authelia Configuration

Create the main Authelia configuration file:

# config/configuration.yml
---
theme: auto  # Options: light, dark, auto

server:
  address: 'tcp://0.0.0.0:9091'
  buffers:
    read: 4096
    write: 4096
  timeouts:
    read: 6s
    write: 6s
    idle: 30s

log:
  level: info  # Options: trace, debug, info, warn, error
  format: text  # Options: text, json

jwt_secret: '/secrets/jwt_secret'

default_redirection_url: https://example.com  # Change to your domain

totp:
  disable: false
  issuer: authelia.com
  algorithm: sha1
  digits: 6
  period: 30
  skew: 1

webauthn:
  disable: false
  display_name: Authelia
  attestation_conveyance_preference: indirect
  user_verification: preferred
  timeout: 60s

authentication_backend:
  password_reset:
    disable: false
  refresh_interval: 5m
  file:
    path: /config/users_database.yml
    password:
      algorithm: argon2id
      iterations: 3
      key_length: 32
      salt_length: 16
      memory: 65536
      parallelism: 4

access_control:
  default_policy: deny
  rules:
    # Allow access to Authelia portal itself
    - domain: auth.example.com
      policy: bypass

    # Protect all other services (require authentication)
    - domain: "*.example.com"
      policy: two_factor

session:
  secret: '/secrets/session_secret'
  name: authelia_session
  domain: example.com  # Root domain for cookies
  same_site: lax
  expiration: 1h
  inactivity: 5m
  remember_me: 1M

  cookies:
    - domain: example.com
      authelia_url: https://auth.example.com

  redis:
    host: authelia-redis
    port: 6379

regulation:
  max_retries: 5
  find_time: 2m
  ban_time: 5m

storage:
  encryption_key: '/secrets/storage_encryption_key'
  postgres:
    address: 'tcp://postgres:5432'
    database: authelia
    username: authelia
    password: '/secrets/postgres_password'

notifier:
  disable_startup_check: false
  smtp:
    address: smtp.resend.com:587
    username: resend
    password: 'your-resend-api-key'  # Or use file: /secrets/smtp_password
    sender: "Authelia <[email protected]>"
    startup_check_address: [email protected]

Important configuration notes:

  • Replace example.com with your actual domain throughout
  • Update SMTP settings if you want password reset functionality
  • For testing, you can set notifier.filesystem.filename: /config/notifications.txt instead of SMTP

Step 5: Create Users Database

Create a file-based user database:

# config/users_database.yml
---
users:
  admin:
    disabled: false
    displayname: "Admin User"
    password: "$argon2id$v=19$m=65536,t=3,p=4$placeholder"  # Will be replaced
    email: [email protected]
    groups:
      - admins
      - users

  john:
    disabled: false
    displayname: "John Doe"
    password: "$argon2id$v=19$m=65536,t=3,p=4$placeholder"
    email: [email protected]
    groups:
      - users

Generate password hashes:

# Generate password hash for admin user
docker run --rm authelia/authelia:latest authelia crypto hash generate argon2 --password 'YourSecurePassword123!'

# Copy the generated hash and replace the placeholder in users_database.yml

For production deployments, use Redis for session storage:

# Add to docker-compose.yml services section
  redis:
    image: redis:7-alpine
    container_name: authelia-redis
    volumes:
      - redis-data:/data
    networks:
      - authelia
    command: redis-server --save 60 1 --loglevel warning
    restart: unless-stopped

# Add to volumes section
volumes:
  redis-data:

If using in-memory sessions (not recommended for production), modify configuration.yml:

session:
  # ... other session settings ...
  # Remove or comment out redis section
  provider: memory  # Add this line

Step 7: Start Authelia

Launch all services:

# Pull latest images
docker-compose pull

# Start services
docker-compose up -d

# Monitor startup logs
docker-compose logs -f authelia

# Wait for "Authelia is listening on 0.0.0.0:9091" message

Verify services are running:

# Check container status
docker-compose ps

# Expected output:
# NAME                 STATUS
# authelia             Up
# authelia-postgres    Up
# authelia-redis       Up

# Test Authelia API
curl -I http://localhost:9091/api/health

# Expected: HTTP/1.1 200 OK

Section 3: Two-Factor Authentication Setup

TOTP (Time-based One-Time Passwords)

TOTP is the most common 2FA method, compatible with authenticator apps.

Configuration (already in configuration.yml):

totp:
  disable: false
  issuer: authelia.com  # Name shown in authenticator app
  algorithm: sha1       # sha1 (most compatible), sha256, sha512
  digits: 6             # 6 or 8 digits
  period: 30            # Seconds between code rotations
  skew: 1               # Allow 1 period before/after for clock drift

User enrollment process:

  1. User logs in with username and password
  2. Authelia prompts: “Two-factor authentication is required”
  3. User scans QR code with authenticator app:
    • Google Authenticator (iOS/Android)
    • Authy (iOS/Android/Desktop)
    • Microsoft Authenticator (iOS/Android)
    • 1Password (if available)
  4. User enters 6-digit code to verify enrollment
  5. Authelia displays one-time backup codes (print and store securely)
  6. Subsequent logins require both password and TOTP code

Testing TOTP enrollment:

# Access Authelia portal (adjust URL to your domain)
# https://auth.example.com

# Login with credentials from users_database.yml
# Follow TOTP enrollment wizard

WebAuthn (Security Keys and Biometrics)

WebAuthn provides phishing-resistant authentication using hardware security keys or platform authenticators.

Configuration (already in configuration.yml):

webauthn:
  disable: false
  display_name: Authelia
  attestation_conveyance_preference: indirect  # indirect, direct, none
  user_verification: preferred  # required, preferred, discouraged
  timeout: 60s

Supported devices:

  • Hardware keys: YubiKey 5 series, Google Titan, Nitrokey
  • Platform authenticators: Windows Hello, TouchID, FaceID, Android biometrics
  • Passkeys: Chrome/Safari passkey storage

User enrollment:

  1. Navigate to Authelia portal → User settings
  2. Click “Register Security Key”
  3. Insert security key or prepare biometric authenticator
  4. Click “Register” and follow browser prompts
  5. Touch key or perform biometric verification
  6. Give device a friendly name (e.g., “YubiKey 5C NFC”)
  7. Device is now enrolled for 2FA

Multiple device enrollment: Users can enroll multiple TOTP apps and multiple WebAuthn devices for redundancy.

Backup Codes

Authelia generates one-time backup codes during 2FA enrollment for account recovery.

Best practices:

  • Print codes and store in secure location
  • Never store backup codes digitally alongside passwords
  • Regenerate codes if compromised
  • Use codes only as last resort

Manual backup code generation:

# Access user settings in Authelia portal
# Navigate to "Two-Factor Authentication"
# Click "Regenerate backup codes"
# Print or write down codes

Section 4: Traefik Integration

Traefik 2.x has native support for forward authentication with Authelia.

Step 1: Ensure Shared Network

Verify Traefik and Authelia share the proxy network:

# Create proxy network if not exists
docker network create proxy

# Verify Authelia is connected
docker network inspect proxy | grep authelia

Step 2: Configure Traefik Middleware

Create Authelia forward auth middleware in Traefik:

Dynamic configuration (YAML file method):

# traefik/dynamic/authelia.yml
http:
  middlewares:
    authelia:
      forwardAuth:
        address: http://authelia:9091/api/verify?rd=https://auth.example.com
        trustForwardHeader: true
        authResponseHeaders:
          - Remote-User
          - Remote-Groups
          - Remote-Name
          - Remote-Email

    authelia-basic:
      forwardAuth:
        address: http://authelia:9091/api/verify?auth=basic
        trustForwardHeader: true
        authResponseHeaders:
          - Remote-User
          - Remote-Groups

Docker labels method:

# In your Traefik docker-compose.yml
services:
  traefik:
    labels:
      - "traefik.http.middlewares.authelia.forwardauth.address=http://authelia:9091/api/verify?rd=https://auth.example.com"
      - "traefik.http.middlewares.authelia.forwardauth.trustForwardHeader=true"
      - "traefik.http.middlewares.authelia.forwardauth.authResponseHeaders=Remote-User,Remote-Groups,Remote-Name,Remote-Email"

Step 3: Expose Authelia Portal via Traefik

Create Traefik router for Authelia authentication portal:

# Add to authelia service in docker-compose.yml
services:
  authelia:
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.authelia.rule=Host(`auth.example.com`)"
      - "traefik.http.routers.authelia.entrypoints=websecure"
      - "traefik.http.routers.authelia.tls=true"
      - "traefik.http.routers.authelia.tls.certresolver=letsencrypt"
      - "traefik.http.services.authelia.loadbalancer.server.port=9091"

Restart Authelia:

docker-compose up -d

Step 4: Protect Applications with Authelia

Add Authelia middleware to any service you want to protect:

Example: Protecting Portainer

services:
  portainer:
    image: portainer/portainer-ce:latest
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.portainer.rule=Host(`portainer.example.com`)"
      - "traefik.http.routers.portainer.entrypoints=websecure"
      - "traefik.http.routers.portainer.tls.certresolver=letsencrypt"

      # Add Authelia protection
      - "traefik.http.routers.portainer.middlewares=authelia@docker"

      - "traefik.http.services.portainer.loadbalancer.server.port=9000"
    networks:
      - proxy

Example: Protecting multiple services

services:
  grafana:
    labels:
      - "traefik.http.routers.grafana.middlewares=authelia@docker"

  jellyfin:
    labels:
      - "traefik.http.routers.jellyfin.middlewares=authelia@docker"

  nextcloud:
    labels:
      - "traefik.http.routers.nextcloud.middlewares=authelia@docker"

Step 5: Test Authentication Flow

  1. Clear browser cookies
  2. Navigate to protected service: https://portainer.example.com
  3. Expect redirect: Browser redirects to https://auth.example.com
  4. Enter credentials: Username and password from users_database.yml
  5. Complete 2FA: Enter TOTP code or touch security key
  6. Redirect back: Automatically redirected to https://portainer.example.com
  7. Access granted: Service loads normally

Troubleshooting:

  • 404 error → Check Authelia container is running
  • Redirect loop → Verify access control rules don’t block auth.example.com
  • 401 unauthorized → Check middleware configuration
  • No redirect → Middleware not applied to router

Section 5: Nginx Proxy Manager Integration

Nginx Proxy Manager (NPM) requires manual Nginx configuration for forward auth.

Step 1: Access Authelia from NPM Network

Update docker-compose.yml to share network with NPM:

networks:
  proxy:
    external: true  # NPM's network
    name: npm_default  # Adjust to your NPM network name

Find NPM network name:

docker network ls | grep npm
# Output example: npm_default

Step 2: Create Proxy Host for Authelia Portal

In Nginx Proxy Manager web UI:

  1. Proxy Hosts → Add Proxy Host
  2. Domain Names: auth.example.com
  3. Scheme: http
  4. Forward Hostname/IP: authelia
  5. Forward Port: 9091
  6. SSL Tab:
    • ✅ Force SSL
    • ✅ Request new SSL certificate (Let’s Encrypt)
  7. Save

Step 3: Create Advanced Configuration Snippet

NPM → Advanced → Custom Nginx Configuration (for each protected service):

# Advanced configuration for protected-app.example.com
location / {
    # Send auth verification to Authelia
    auth_request /authelia;

    # Pass auth headers to backend
    auth_request_set $user $upstream_http_remote_user;
    auth_request_set $groups $upstream_http_remote_groups;
    auth_request_set $name $upstream_http_remote_name;
    auth_request_set $email $upstream_http_remote_email;

    proxy_set_header Remote-User $user;
    proxy_set_header Remote-Groups $groups;
    proxy_set_header Remote-Name $name;
    proxy_set_header Remote-Email $email;

    # Redirect to Authelia if unauthenticated
    error_page 401 =302 https://auth.example.com/?rd=$scheme://$http_host$request_uri;
}

# Internal location for auth verification
location /authelia {
    internal;
    proxy_pass http://authelia:9091/api/verify;
    proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
    proxy_set_header X-Forwarded-Method $request_method;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Host $http_host;
    proxy_set_header X-Forwarded-Uri $request_uri;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_set_header Content-Length "";
    proxy_pass_request_body off;
}

Step 4: Alternative - Authelia Authentication Preset

Create a reusable Nginx snippet:

SSH into NPM container:

docker exec -it npm bash

# Create custom snippet directory
mkdir -p /data/nginx/custom

# Create Authelia snippet
cat > /data/nginx/custom/authelia-auth.conf << 'EOF'
# Authelia Forward Auth Configuration
location /authelia {
    internal;
    proxy_pass http://authelia:9091/api/verify;
    proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
    proxy_set_header X-Forwarded-Method $request_method;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Host $http_host;
    proxy_set_header X-Forwarded-Uri $request_uri;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_set_header Content-Length "";
    proxy_pass_request_body off;
}
EOF

exit

Reference in proxy host custom configuration:

# Include Authelia auth check
include /data/nginx/custom/authelia-auth.conf;

location / {
    auth_request /authelia;
    auth_request_set $user $upstream_http_remote_user;
    proxy_set_header Remote-User $user;
    error_page 401 =302 https://auth.example.com/?rd=$scheme://$http_host$request_uri;
}

Section 6: Access Control Rules

Authelia’s access control engine evaluates rules top-to-bottom and applies the first match.

Rule Structure

access_control:
  default_policy: deny  # deny, bypass, one_factor, two_factor

  rules:
    - domain: "example.com"
      policy: bypass
      subject:
        - "group:admins"
      networks:
        - "192.168.1.0/24"

Rule components:

  • domain: Domain(s) to match (supports wildcards and regex)
  • policy: Action to take (bypass, one_factor, two_factor, deny)
  • subject: User or group requirements (optional)
  • networks: Source IP restrictions (optional)
  • resources: Path-based matching (optional)

Common Access Control Patterns

Pattern 1: Public landing page, protected dashboard

rules:
  # Allow public access to marketing site
  - domain: example.com
    policy: bypass

  # Require authentication for app subdomain
  - domain: app.example.com
    policy: two_factor

Pattern 2: Admin-only services

rules:
  # Admin panel accessible only to admins group
  - domain: admin.example.com
    policy: two_factor
    subject:
      - "group:admins"

  # Deny everyone else
  - domain: admin.example.com
    policy: deny

Pattern 3: Network-based access

rules:
  # Internal network can access without 2FA
  - domain: "*.internal.example.com"
    policy: one_factor
    networks:
      - "192.168.1.0/24"
      - "10.0.0.0/8"

  # External access requires 2FA
  - domain: "*.internal.example.com"
    policy: two_factor

Pattern 4: Path-based rules

rules:
  # Allow webhook endpoints without auth
  - domain: app.example.com
    resources:
      - "^/api/webhooks/.*$"
    policy: bypass

  # Require auth for everything else
  - domain: app.example.com
    policy: two_factor

Pattern 5: User-specific access

rules:
  # Only john can access personal dashboard
  - domain: john.example.com
    policy: two_factor
    subject:
      - "user:john"

  # Deny everyone else
  - domain: john.example.com
    policy: deny

Advanced: Regex Domain Matching

rules:
  # Match multiple TLDs
  - domain_regex: "^app\.(example\.com|example\.local)$"
    policy: two_factor

  # Match numbered subdomains
  - domain_regex: "^service-[0-9]+\.example\.com$"
    policy: one_factor

Complete Real-World Example

access_control:
  default_policy: deny

  rules:
    # Authelia portal itself (must be first)
    - domain: auth.example.com
      policy: bypass

    # Public services
    - domain:
        - example.com
        - www.example.com
      policy: bypass

    # Admin services - require admin group and 2FA
    - domain:
        - portainer.example.com
        - proxmox.example.com
      policy: two_factor
      subject:
        - "group:admins"

    # Media services - all authenticated users
    - domain:
        - jellyfin.example.com
        - plex.example.com
      policy: one_factor
      subject:
        - "group:users"

    # API endpoints - bypass for automation
    - domain: api.example.com
      resources:
        - "^/webhooks/.*$"
        - "^/health$"
      policy: bypass

    # Everything else requires 2FA
    - domain: "*.example.com"
      policy: two_factor

Section 7: Bypass Rules for API and Special Cases

Some services require authentication bypass for specific functionality.

Bypass API Endpoints

rules:
  # Allow API access for automation
  - domain: nextcloud.example.com
    resources:
      - "^/remote\.php/dav/.*$"  # CalDAV/CardDAV
      - "^/ocs/.*$"                # OCS API
    policy: bypass

  # Require auth for web interface
  - domain: nextcloud.example.com
    policy: two_factor

Bypass Health Checks and Monitoring

rules:
  # Allow Uptime Kuma to check services
  - domain: "*.example.com"
    resources:
      - "^/health$"
      - "^/api/health$"
      - "^/ping$"
    networks:
      - "192.168.1.50/32"  # Uptime Kuma IP
    policy: bypass

Bypass Mobile Apps

rules:
  # Allow Jellyfin mobile app access
  - domain: jellyfin.example.com
    resources:
      - "^/emby/.*$"
      - "^/mediabrowser/.*$"
    policy: bypass

Bypass RSS Feeds

rules:
  # Public RSS feeds
  - domain: blog.example.com
    resources:
      - "^/feed$"
      - "^/rss$"
      - "^\/.*\.xml$"
    policy: bypass

Bypass with User-Agent Detection

Authelia doesn’t natively support user-agent matching, but you can implement this in Nginx:

# In NPM custom configuration
location / {
    # Bypass auth for specific user agents
    if ($http_user_agent ~* "JellyfinClient|PlexClient") {
        proxy_pass http://backend;
        break;
    }

    # Normal Authelia auth for browsers
    auth_request /authelia;
    error_page 401 =302 https://auth.example.com/?rd=$scheme://$http_host$request_uri;
}

Testing Bypass Rules

# Test API endpoint bypass
curl -I https://api.example.com/webhooks/github

# Expected: 200 OK (no redirect to auth portal)

# Test protected endpoint
curl -I https://api.example.com/admin

# Expected: 302 Redirect to https://auth.example.com

Section 8: Session Management and Remember Me

Session Configuration Deep Dive

session:
  secret: '/secrets/session_secret'
  name: authelia_session  # Cookie name
  domain: example.com     # Root domain for cookie sharing
  same_site: lax          # lax, strict, none
  expiration: 1h          # Session expires after 1 hour
  inactivity: 5m          # Session expires after 5 min of inactivity
  remember_me: 1M         # Remember me extends session to 1 month

Session behavior:

  • User logs in → Session created with 1 hour expiration
  • User inactive for 5 minutes → Session expires, requires re-login
  • User checks “Remember me” → Session extended to 1 month
  • User closes browser → Session persists (unless browser clears cookies)

Multi-Domain Session Sharing

To share sessions across multiple root domains:

session:
  cookies:
    - domain: example.com
      authelia_url: https://auth.example.com

    - domain: example.net
      authelia_url: https://auth.example.net

Logout Functionality

Manual logout:

  • Navigate to https://auth.example.com
  • Click user icon → Logout
  • Session cookie deleted

Programmatic logout:

# Delete session cookie via JavaScript
document.cookie = "authelia_session=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=.example.com";

Session Security Best Practices

  1. Use HTTPS only: Set session.secure: true in production
  2. Minimize expiration: Shorter sessions reduce attack window
  3. Enable inactivity timeout: Auto-logout idle users
  4. Restrict remember_me: Limit to trusted devices only
  5. Monitor active sessions: Check Redis for suspicious sessions
# View active sessions in Redis
docker exec -it authelia-redis redis-cli

# List all keys (sessions)
KEYS authelia:session:*

# Inspect specific session
GET authelia:session:abc123def456

Section 9: LDAP Integration (Optional)

For environments with existing LDAP/Active Directory:

Replace File Backend with LDAP

authentication_backend:
  password_reset:
    disable: false
  refresh_interval: 5m

  ldap:
    address: ldap://openldap:389
    implementation: custom  # custom, activedirectory, rfc2307bis
    timeout: 5s
    start_tls: false
    tls:
      skip_verify: false

    base_dn: dc=example,dc=com
    username_attribute: uid
    additional_users_dn: ou=users
    users_filter: (&({username_attribute}={input})(objectClass=person))

    additional_groups_dn: ou=groups
    groups_filter: (&(member={dn})(objectClass=groupOfNames))
    group_name_attribute: cn
    mail_attribute: mail
    display_name_attribute: displayName

    user: cn=admin,dc=example,dc=com
    password: 'ldap-admin-password'

Active Directory Example

authentication_backend:
  ldap:
    address: ldap://dc.example.com:389
    implementation: activedirectory
    start_tls: true

    base_dn: DC=example,DC=com
    username_attribute: sAMAccountName
    additional_users_dn: CN=Users
    users_filter: (&({username_attribute}={input})(objectCategory=person)(objectClass=user))

    additional_groups_dn: CN=Users
    groups_filter: (&(member={dn})(objectClass=group))
    group_name_attribute: cn

    user: CN=authelia,CN=Users,DC=example,DC=com
    password: '/secrets/ldap_password'

Section 10: Troubleshooting Common Issues

Issue 1: Redirect Loop

Symptoms: Browser repeatedly redirects between app and auth portal

Causes and solutions:

# 1. Check access control rules
# Ensure auth.example.com has bypass policy

# 2. Verify Traefik middleware isn't applied to Authelia itself
# Remove authelia middleware from auth portal router

# 3. Check cookie domain configuration
# Ensure session.domain matches your setup

# 4. Clear browser cookies
# Browser dev tools → Application → Cookies → Delete all for domain

Issue 2: 401 Unauthorized After Login

Symptoms: Login succeeds but still shows 401 on protected service

Diagnostic steps:

# Check Authelia logs
docker-compose logs authelia | grep -i error

# Verify middleware configuration
docker exec traefik cat /etc/traefik/dynamic/authelia.yml

# Test Authelia verify endpoint directly
curl -H "Cookie: authelia_session=abc123" http://localhost:9091/api/verify

# Check access control rules match the domain
docker exec authelia cat /config/configuration.yml | grep -A 20 access_control

Issue 3: 2FA Not Prompting

Symptoms: Login with password succeeds, but no 2FA prompt appears

Solutions:

# 1. Verify TOTP is enabled in configuration
docker exec authelia cat /config/configuration.yml | grep -A 5 totp

# 2. Check access control policy
# Rules must specify 'two_factor' policy

# 3. Force re-enrollment
# Delete TOTP secret from database
docker exec -it authelia-postgres psql -U authelia -d authelia
DELETE FROM totp_configurations WHERE username = 'admin';
q

Issue 4: SMTP Errors

Symptoms: Cannot send password reset emails

Diagnostic steps:

# Test SMTP connectivity
docker exec authelia telnet smtp.resend.com 587

# Check SMTP credentials
docker exec authelia cat /config/configuration.yml | grep -A 10 smtp

# View detailed SMTP errors
docker-compose logs authelia | grep -i smtp

# Test with filesystem notifier instead
# Modify configuration.yml:
# notifier:
#   filesystem:
#     filename: /config/notifications.txt

Issue 5: High Memory Usage

Symptoms: Authelia consuming excessive RAM

Solutions:

# 1. Set resource limits in docker-compose.yml
services:
  authelia:
    deploy:
      resources:
        limits:
          memory: 256M
        reservations:
          memory: 128M

# 2. Optimize session storage
# Use Redis instead of memory provider

# 3. Clean up old sessions
docker exec -it authelia-redis redis-cli FLUSHDB

# 4. Reduce session duration
# Lower session.expiration and session.inactivity values

Section 11: Monitoring and Metrics

Health Check Endpoint

# Check Authelia health
curl http://localhost:9091/api/health

# Expected response:
# {"status":"UP"}

Prometheus Metrics (Optional)

Enable metrics in configuration:

# Add to configuration.yml
telemetry:
  metrics:
    enabled: true
    address: tcp://0.0.0.0:9959
    buffers:
      read: 4096
      write: 4096
    timeouts:
      read: 6s
      write: 6s
      idle: 30s

Expose metrics port:

# Update docker-compose.yml
services:
  authelia:
    ports:
      - "9091:9091"
      - "9959:9959"  # Metrics endpoint

Scrape with Prometheus:

# prometheus.yml
scrape_configs:
  - job_name: 'authelia'
    static_configs:
      - targets: ['authelia:9959']

Import Grafana dashboard:

  • Dashboard ID: 14837 (Authelia Overview)

Log Monitoring

# View authentication attempts
docker-compose logs authelia | grep "Successful authentication"

# View failed logins
docker-compose logs authelia | grep "failed authentication"

# View 2FA enrollments
docker-compose logs authelia | grep "TOTP registration"

# Monitor in real-time
docker-compose logs -f authelia

Conclusion

Congratulations! You’ve deployed a production-ready Authelia instance with comprehensive SSO and 2FA protection for your homelab. You now have:

  • ✅ Centralized authentication for all services behind reverse proxy
  • ✅ Multi-factor authentication with TOTP and WebAuthn
  • ✅ Integration with Traefik or Nginx Proxy Manager
  • ✅ Granular access control with user, group, and network-based rules
  • ✅ Bypass rules for API endpoints and special cases
  • ✅ Secure session management with remember-me functionality
  • ✅ (Optional) LDAP integration for enterprise environments

Next Steps

  1. Add More Protected Services: Apply Authelia middleware to additional applications
  2. Fine-tune Access Rules: Create user-specific and group-based policies
  3. Enable Monitoring: Set up Prometheus and Grafana dashboards
  4. Implement High Availability: Deploy Redis cluster and multiple Authelia instances
  5. Regular Backups: Automate PostgreSQL and configuration backups

Maintenance Checklist

Weekly:

  • Review authentication logs for suspicious activity
  • Check failed login attempts
  • Verify backup codes are stored securely

Monthly:

  • Update Authelia to latest version
  • Review and update access control rules
  • Test disaster recovery procedures
  • Rotate SMTP credentials

Quarterly:

  • Security audit of all protected services
  • Review user accounts and group memberships
  • Update documentation
  • Test 2FA enrollment and recovery processes

Resources

Final Thoughts

Authelia strikes the perfect balance between security and simplicity for homelabs. Its lightweight footprint, reverse proxy-native design, and comprehensive 2FA support make it ideal for protecting services without the overhead of enterprise IdP solutions.

By implementing Authelia, you’ve transformed your homelab from a collection of individually authenticated services into a unified, secure infrastructure with enterprise-grade authentication—all while maintaining complete control over your data and identity management.

Your homelab is now protected by SSO and 2FA. Happy homelabbing!


Guide Version: 1.0 Last Updated: December 2025 Authelia Version: 4.38+ Tested On: Ubuntu 22.04, Docker 24.0+

Author Note: This guide is maintained as part of the homelabbing.io project. Found an issue or have improvements? Contribute on GitHub!