Infrastructure

How to Deploy Authelia Using Docker Compose Behind Caddy

Authelia is an open-source authentication and authorization server providing two-factor authentication and single sign-on (SSO) for applications via a web portal.

Rajasekhar Gundala··6 min read

Authelia is an open-source authentication and authorization server providing two-factor authentication and single sign-on (SSO) for your applications via a web portal. It acts as a companion for reverse proxies by allowing, denying, or redirecting incoming HTTP requests.

Happy New Year 2025 to all readers! Wishing you a year of health, wealth, and endless opportunities.

I have been a bit busy with other work, so I haven’t had much time to write articles. Moving forward, I will publish tutorials more regularly.

Let’s get started. Today, I will walk you through deploying Authelia using Docker Compose behind a Caddy reverse proxy.

Prerequisites

Ensure you fulfill the following requirements before proceeding with the deployment:

  1. Ubuntu Server (any Linux distribution works, but Ubuntu is used throughout this guide).
  2. Docker and Docker Compose installed on your server.

Introduction to Authelia

Authelia is an open-source authentication and authorization server and portal fulfilling the Identity and Access Management (IAM) role. It provides multi-factor authentication and single sign-on (SSO) for your applications via a web portal, serving as an authentication companion for reverse proxies such as Caddy, Traefik, and NGINX.

Here, we integrate Authelia with Caddy. Authelia handles requests directed to its authorization (authz) endpoints using specific headers and returns standardized responses based on your configured policies.

Caddy leverages its forward_auth directive to pass client requests to Authelia based on the proxy authorization endpoint, response headers, and session cookies.

The Single Sign-On Multi-Factor Portal for Web Apps.

Authelia Server Core Features

Lightweight
  • Compressed container image size is under 20 MB.
  • Runtime memory usage typically stays below 30 MB.
Fast
  • Authorization policies and backend validations execute in milliseconds.
  • The web login portal loads in under 100 milliseconds.
Login Regulation
  • Prevents brute-force attempts by enforcing temporary lockouts after consecutive failed logins.
Password Reset
  • Enables self-service password resets for LDAP or file-based accounts using email verification.
Single Sign-On (SSO)
  • Allows users to authenticate once across multiple web applications via session cookies, OpenID Connect, and trusted headers.
Authorization Policies
  • Defines granular access control rules mapping specific users and groups to domain endpoints.
Multi-Factor Authentication
  • Supports one-time passcodes (TOTP), push notifications (Duo), and hardware security keys (WebAuthn / FIDO2).
Intuitive User Interface
  • Clean, responsive portal providing an effortless login experience for end-users.

Prepare the Authelia Server Environment

Create a dedicated directory under /opt on your host to persist Authelia’s configuration and runtime SQLite database:

cd /opt
sudo mkdir -p authelia

Authelia Configuration

Authelia supports two primary methods for managing user credentials:

Save the following configuration inside /opt/authelia/configuration.yml:

theme: auto
default_2fa_method: 'totp'

server:
  address: 'tcp://0.0.0.0:9091/'
  endpoints:
    authz:
      forward-auth:
        implementation: 'ForwardAuth'

log:
  level: debug

totp:
  disable: false
  issuer: 'authelia.example.com'
  algorithm: 'sha1'
  digits: 6
  period: 30
  skew: 1
  secret_size: 32
  allowed_algorithms:
    - 'SHA1'
  allowed_digits:
    - 6
  allowed_periods:
    - 30
  disable_reuse_security_policy: false

webauthn:
  disable: true

authentication_backend:
  password_reset:
    disable: false
  refresh_interval: 15m
  ldap:
    implementation: custom
    address: ldap://lldap:3890
    timeout: 5s
    start_tls: false
    base_dn: dc=example,dc=com
    users_filter: (&(|({username_attribute}={input})({mail_attribute}={input}))(objectClass=person))
    additional_groups_dn: ou=groups
    additional_users_dn: ou=people
    groups_filter: (member={dn})
    user: uid=admin,ou=people,dc=example,dc=com
    attributes:
      display_name: displayName
      distinguished_name: distinguishedName
      username: uid
      mail: mail
      member_of: memberOf
      group_name: cn

password_policy:
  standard:
    enabled: false
    min_length: 8
    max_length: 0
    require_uppercase: true
    require_lowercase: true
    require_number: true
    require_special: false

access_control:
  default_policy: deny
  rules:
    - domain: public.example.com
      policy: bypass
    - domain: secure.example.com
      policy: two_factor

session:
  name: authelia_session
  secret: some-secret
  same_site: 'lax'
  inactivity: '5m'
  expiration: '1h'
  remember_me: '1M'
  cookies:
    - domain: example.com
      authelia_url: [https://authelia.example.com](https://authelia.example.com)

regulation:
  max_retries: 3
  find_time: 120
  ban_time: 300

storage:
  encryption_key: secure-encryption-key
  local:
    path: /config/db.sqlite3

notifier:
  disable_startup_check: false
  smtp:
    address: 'smtp://smtp.example.com:587'
    username: 'yourname@example.com'
    password: 'secure-password'
    sender: 'Authelia <authelia@authelia.example.com>'
    identifier: 'authelia.example.com'
    subject: '[Authelia] {title}'
    startup_check_address: 'mailtest@example.com'
    tls:
      server_name: 'smtp.example.com'

Caddy Configuration (Caddyfile)

Create your Caddyfile inside /opt:

cd /opt
sudo touch Caddyfile
sudo nano Caddyfile

Paste the configuration below:

{
    email you@example.com
    cert_issuer acme
    acme_ca [https://acme-v02.api.letsencrypt.org/directory](https://acme-v02.api.letsencrypt.org/directory)
    
    servers {
        metrics
        protocol h1 h2c h3
        strict_sni_host on
        trusted_proxies cloudflare {
            interval 12h
            timeout 15s
        }
    }
    admin 0.0.0.0:2019
}

authelia.example.com {
    log {
        output file /var/log/caddy/authelia.log {
            roll_size 20mb
            roll_keep 2
            roll_keep_for 6h
        }
        format console
        level error
    }

    reverse_proxy authelia:9091 {
        transport http {
            keepalive 300s
        }
    }
}

Docker Compose Configuration

Create a bridge network named caddy so services can communicate across separate compose projects:

docker network create caddy

Create /opt/docker-compose.yml:

cd /opt
sudo touch docker-compose.yml
sudo nano docker-compose.yml

Add the following stack definition:

secrets:
  jwt_secret:
    file: ./jwt_secret.txt
  backend_password:
    file: ./backend_password.txt
  smtp_password:
    file: ./smtp_password.txt

volumes:
  caddydata:
  caddyconfig:
  caddylogs:
  authelia:

networks:
  caddy:
    external: true

services:
  caddy:
    image: rajaseg/caddy
    restart: unless-stopped
    container_name: caddy
    ports:
      - "80:80"
      - "443:443"
      - "2019:2019"
    networks:
      - caddy
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - ./caddydata:/data
      - ./caddyconfig:/config
      - ./caddylogs:/var/log/caddy

  authelia:
    image: authelia/authelia:latest
    container_name: authelia
    restart: unless-stopped
    depends_on:
      caddy:
        condition: service_started
    volumes:
      - ./authelia:/config
    secrets:
      - jwt_secret
      - backend_password
      - smtp_password
    networks:
      - caddy
    environment:
      - AUTHELIA_IDENTITY_VALIDATION_RESET_PASSWORD_JWT_SECRET_FILE=/run/secrets/jwt_secret
      - AUTHELIA_AUTHENTICATION_BACKEND_LDAP_PASSWORD_FILE=/run/secrets/backend_password
      - AUTHELIA_NOTIFIER_SMTP_PASSWORD_FILE=/run/secrets/smtp_password

Key configuration directives used:

  • depends_on: Ensures service startup ordering (Caddy starts before Authelia).
  • secrets: Mounts sensitive credentials into /run/secrets/ inside the container rather than passing them through cleartext environment variables.
  • restart: unless-stopped: Ensures automatic recovery across host reboots and container crashes.

Deploy the Stack

Deploy the containers in detached mode:

docker compose up -d

Authelia utilizes session cookies to identify and authorize incoming user requests. For session persistence, Authelia supports:

  1. Memory (default, local process storage suitable for single-node setups).
  2. Redis (centralized cache recommended for high-availability clusters).

This guide uses in-memory session persistence. Once deployed, open your browser and navigate to the subdomain defined in your Caddyfile (https://authelia.example.com).

Ensure your DNS provider contains an A or CNAME record pointing authelia.example.com to your server’s public IP address before testing.

Interface Preview

Authelia Web Interface

Feel free to leave a comment below if you have any questions or encounter issues setting this up.

Share
Written by
Rajasekhar Gundala

Senior Infrastructure & Web Platform Leader.

Continue reading

Weekly Engineering Notes.

A weekly digest on infrastructure, observability, Rust, and the open web. No spam, just technical signals.

Free. Unsubscribe in one click.