Skip to content

Authelia setup

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

Guides and initial folder setup

There is a good guide on Nginx Proxy Manager integration available at IBRACORP and simple setup (without Redis and MariaDB) is covered by Techno Tim. The below guide combines both of these for a simple setup running with Nginx Proxy Manager but still using Redis to enable session persistence even with Authelia configuration reloads (if not required then just comment out the redis section of the Authelia configuration file).

Create folder structure

mkdir -p ~/containers/authelia/config

There are two key files that then need to be created: configuration.yml & users_database.yml. Both of these are placed in this new config folder - example versions are in the following two sections.

User database

This setup is using the simple (flat file) method. Remember to change the username from default and replace the password in users_database.yml with a hashed version. The following command makes use of the Authelia container to generate a hashed password:

docker run --rm authelia/authelia:latest authelia crypto hash generate argon2 --password 'test'

tabs vs spaces

Do not use tabs to layout the user database - instead use spaces otherwise you will receive an error message Failure running the user provider startup check: error reading the authentication database: could not parse the YAML database: yaml: line xx: found character that cannot start any token

authelia/config/users_database.yml
---
###############################################################
#                         Users Database                      #
###############################################################

# This file can be used if you do not have an LDAP set up.

# List of users - change username to desired user
users:
  username:
    displayname: "Your Name"
    # See documentation for docker command to create hashed password
    password: "$argon2id$v=19$m=65536,t=1,p=8$cUI4a0E3L1laYnRDUXl3Lw$ZsdsrdadaoVIaVj8NltA8x4qVOzT+/r5GF62/bT8OuAs" 
    email: you@example.com
    groups:
      - admins
      - dev
...

Authelia configuration file

A number of items need to be replaced in the configuration file:

  1. Set the jwt_secret with a 128-bit key (e.g. from https://generate-random.org/encryption-key-generator)
  2. Set the default_redirection_url with the one for this domain
  3. Under access_control set the policy for different subdomains (options: bypass/one_factor/two_factor). Useful IBRACORP guide and video to rules
  4. Under session set another random 128-bit key for the secret and change the domain to the main domain name (i.e. no subdomains). Alter expiration/inactivity as required. Add a secret for the redis/password key and also insert this in the docker-compose file.
  5. Under storage set a 512-bit key for the encryption_key
  6. Add relevant SMTP credentials under notifier
authelia/config/configuration.yml
---
###############################################################
#                   Authelia configuration                    #
###############################################################

## Note: the container by default expects to find this file at /config/configuration.yml

##
## Server Configuration
##
server:
  ## The address to listen on.
  host: 0.0.0.0

  ## The port to listen on.
  port: 9091

##
## Log Configuration
##
log:
  ## Level of verbosity for logs: info, debug, trace.
  level: debug

## The theme to display: light, dark, grey, auto.
theme: dark

## The secret used to generate JWT tokens when validating user identity by email confirmation. JWT Secret can also be
## set using a secret: https://www.authelia.com/c/secrets
jwt_secret: a_very_important_secret

## Default redirection URL
##
## If user tries to authenticate without any referer, Authelia does not know where to redirect the user to at the end
## of the authentication process. This parameter allows you to specify the default redirection URL Authelia will use
## in such a case.
##
## Note: this parameter is optional. If not provided, user won't be redirected upon successful authentication.
default_redirection_url: https://auth.local.example.com

## Define 2FA method, options are totp, webauthn, mobile_push - see documentation for alternative options.
## https://www.authelia.com/configuration/second-factor/time-based-one-time-password/
totp:
  ## The issuer name displayed in the Authenticator application of your choice.
  issuer: authelia.com

  ## The number of digits a user has to input. Must either be 6 or 8.
  ## Changing this option only affects newly generated TOTP configurations.
  ## It is CRITICAL you read the documentation before changing this option:
  ## https://www.authelia.com/c/totp#digits
  digits: 6

  ## The period in seconds a one-time password is valid for.
  ## Changing this option only affects newly generated TOTP configurations.
  period: 30

  ## The skew controls number of one-time passwords either side of the current one that are valid.
  ## Warning: before changing skew read the docs link below.
  skew: 1
  ## See: https://www.authelia.com/c/totp#input-validation to read
  ## the documentation.

  ## The size of the generated shared secrets. Default is 32 and is sufficient in most use cases, minimum is 20.
  secret_size: 32

##
## NTP Configuration
##
## This is used to validate the servers time is accurate enough to validate TOTP.
ntp:
  ## NTP server address.
  address: "time.cloudflare.com:123"

  ## NTP version.
  version: 4

  ## Maximum allowed time offset between the host and the NTP server.
  max_desync: 3s

  ## Disables the NTP check on startup entirely. This means Authelia will not contact a remote service at all if you
  ## set this to true, and can operate in a truly offline mode.
  disable_startup_check: false

  ## The default of false will prevent startup only if we can contact the NTP server and the time is out of sync with
  ## the NTP server more than the configured max_desync. If you set this to true, an error will be logged but startup
  ## will continue regardless of results.
  disable_failure: false

##
## Authentication Backend Provider Configuration
##
## Used for verifying user passwords and retrieve information such as email address and groups users belong to.
##
## The available providers are: `file`, `ldap`. You must use only one of these providers.
authentication_backend:
  ##
  ## File (Authentication Provider)
  ##
  ## With this backend, the users database is stored in a file which is updated when users reset their passwords.
  ## Therefore, this backend is meant to be used in a dev environment and not in production since it prevents Authelia
  ## to be scaled to more than one instance. The options under 'password' have sane defaults, and as it has security
  ## implications it is highly recommended you leave the default values. Before considering changing these settings
  ## please read the docs page below:
  ## https://www.authelia.com/r/passwords#tuning
  ##
  file:
    path: /config/users_database.yml
    password:
      algorithm: argon2id
      iterations: 1
      salt_length: 16
      parallelism: 8
      memory: 64

##
## Access Control Configuration
##
## Access control is a list of rules defining the authorizations applied for one resource to users or group of users.
##
## If 'access_control' is not defined, ACL rules are disabled and the 'bypass' rule is applied, i.e., access is allowed
## to anyone. Otherwise restrictions follow the rules defined.
##
## Note: One can use the wildcard * to match any subdomain.
## It must stand at the beginning of the pattern. (example: *.mydomain.com)
##
## Note: You must put patterns containing wildcards between simple quotes for the YAML to be syntactically correct.
##
## Definition: A 'rule' is an object with the following keys: 'domain', 'subject', 'policy' and 'resources'.
##
## - 'domain' defines which domain or set of domains the rule applies to.
##
## - 'subject' defines the subject to apply authorizations to. This parameter is optional and matching any user if not
##    provided. If provided, the parameter represents either a user or a group. It should be of the form
##    'user:<username>' or 'group:<groupname>'.
##
## - 'policy' is the policy to apply to resources. It must be either 'bypass', 'one_factor', 'two_factor' or 'deny'.
##
## - 'resources' is a list of regular expressions that matches a set of resources to apply the policy to. This parameter
##   is optional and matches any resource if not provided.
##
## Note: the order of the rules is important. The first policy matching (domain, resource, subject) applies.
## For fuller information see examples at https://github.com/authelia/authelia/blob/master/config.template.yml 
## and documentation at https://www.authelia.com/configuration/security/access-control/
access_control:
  ## Default policy can either be 'bypass', 'one_factor', 'two_factor' or 'deny'. It is the policy applied to any
  ## resource if there is no policy to be applied to the user.
  default_policy: deny
  rules:
    # Rules applied to everyone and are read top to bottom
    # Set to bypass, one_factor or two_factor
    # Remember main login page needs to be allowed to bypass
    - domain: "auth.example.com"
      policy: bypass
    - domain: "status.example.com" # allow /status, /assets, /api and icon.svg to be available to unauthenticated users
      resources:
        - "^/status([/?].*)?$"
        - "^/assets([/?].*)?$"
        - "^/api([/?].*)?$"
        - "^/icon.svg$"
      policy: bypass
    - domain: "important.example.com"
      policy: two_factor
    - domain: "*.example.com"
      policy: one_factor

##
## Session Provider Configuration
##
## The session cookies identify the user once logged in.
## The available providers are: `memory`, `redis`. Memory is the provider unless redis is defined.
session:
  ## The name of the session cookie.
  name: authelia_session

  # This secret can also be set using the env variables AUTHELIA_SESSION_SECRET_FILE
  secret: unsecure_session_secret

  ## The time before the cookie expires and the session is destroyed if remember me IS NOT selected.
  # Possible values are listed at https://www.authelia.com/c/common#duration-notation-format
  expiration: 1h

  ## The inactivity time before the session is reset. If expiration is set to 1h, and this is set to 5m, if the user
  ## does not select the remember me option their session will get destroyed after 1h, or after 5m since the last time
  ## Authelia detected user activity.
  inactivity: 5m

  ## The time before the cookie expires and the session is destroyed if remember me IS selected.
  ## Value of -1 disables remember me.
  remember_me_duration: 1M

  ## The domain to protect.
  ## Note: the authenticator must also be in that domain.
  ## If empty, the cookie is restricted to the subdomain of the issue
  domain: example.com  # Should match whatever your root protected domain is

  ##
  ## Redis Provider
  ##
  # option to install Redis in-memory database - this allows persistence of sessions even when Authelia container is restarted, e.g. for config changes
  redis:
    host: redis
    port: 6379
    # This secret can also be set using the env variables AUTHELIA_SESSION_REDIS_PASSWORD_FILE
    # Has issues with some special characters so stick to text/numbers - set this in docker-compose file too
    password: authelia

##
## Regulation Configuration
##
## This mechanism prevents attackers from brute forcing the first factor. It bans the user if too many attempts are made
## in a short period of time.
regulation:
  ## The number of failed login attempts before user is banned. Set it to 0 to disable regulation.
  max_retries: 3

  ## The time range during which the user can attempt login before being banned. The user is banned if the
  ## authentication failed 'max_retries' times in a 'find_time' seconds window. Find Time accepts duration notation.
  ## See: https://www.authelia.com/c/common#duration-notation-format
  find_time: 2m

  ## The length of time before a banned user can login again. Ban Time accepts duration notation (as above).
  ban_time: 1h

##
## Storage Provider Configuration
##
## The available providers are: `local`, `mysql`, `postgres`. You must use one and only one of these providers.
storage:
  ## The encryption key that is used to encrypt sensitive information in the database. Must be a string with a minimum
  ## length of 20. Please see the docs if you configure this with an undesirable key and need to change it.
  encryption_key: a_very_important_secret_of_more_than_20_chars

  ##
  ## Local (Storage Provider)
  ##
  ## This stores the data in a SQLite3 Database.
  ## This is only recommended for lightweight non-stateful installations.
  ##
  local:
    path: /config/db.sqlite3

##
## Notification Provider
##
## Notifications are sent to users when they require a password reset, a Webauthn registration or a TOTP registration.
## The available providers are: filesystem, smtp. **You must use only one of these providers.**
notifier:
  ##
  ## SMTP (Notification Provider)
  ##
  ## Use a SMTP server for sending notifications. Authelia uses the PLAIN or LOGIN methods to authenticate.
  ## [Security] By default Authelia will:
  ##   - force all SMTP connections over TLS including unauthenticated connections
  ##      - use the disable_require_tls boolean value to disable this requirement
  ##        (only works for unauthenticated connections)
  ##   - validate the SMTP server x509 certificate during the TLS handshake against the hosts trusted certificates
  ##     (configure in tls section)
  smtp:
    username: test
    # This secret can also be set using the env variables AUTHELIA_NOTIFIER_SMTP_PASSWORD_FILE
    password: password
    host: mail.example.com
    port: 587
    sender: admin@example.com
    subject: "[Authelia] {title}"
  # filesystem:
  #   filename: /config/notification.txt
...

Container setup

Once these two files are in place the container can now be started. Install via docker-compose or as a Portainer stack using the following file (remember to set the Redis password environment variable):

docker-compose/authelia.yml
version: '3'
services:
  authelia:
    container_name: authelia    
    image: authelia/authelia:latest
    expose:
      - 9091
    volumes:
      - /home/alan/containers/authelia/config:/config
    environment:
      - TZ=Europe/London
    networks:
      - nginx-proxy-manager_default
    restart: unless-stopped

  redis:
    container_name: redis
    image: redis:alpine
    expose:
      - 6379
    command: redis-server --save 20 1 --loglevel warning --requirepass YOURPASSWORD
    volumes:
      - /home/alan/containers/redis:/data
    environment:
      - TZ=Europe/London
    networks:
      - nginx-proxy-manager_default
    restart: unless-stopped    

networks:
  nginx-proxy-manager_default:
    external: true
    name: nginx-proxy-manager_default          

Nginx Proxy Manager setup

Create a new proxy host (in the format auth.domain.tld), pointing to the new authelia container on port 9091. Switch on all SSL options and generate a new SSL certificate. The following text then needs to be added under advanced settings for this new auth proxy host:

host proxy advanced settings
location / {
set $upstream_authelia http://authelia:9091; # Replace with Docker container name if not authelia
proxy_pass $upstream_authelia;
client_body_buffer_size 128k;

#Timeout if the real server is dead
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;

# Advanced Proxy Config
send_timeout 5m;
proxy_read_timeout 360;
proxy_send_timeout 360;
proxy_connect_timeout 360;

# Basic Proxy Config
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
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-Ssl on;
proxy_redirect  http://  $scheme://;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_cache_bypass $cookie_session;
proxy_no_cache $cookie_session;
proxy_buffers 64 256k;

# If behind a reverse proxy, forwards the correct IP, assumes you're using Cloudflare. Adjust IP for your Docker network.
set_real_ip_from 172.19.0.0/16;
real_ip_header CF-Connecting-IP;
real_ip_recursive on;
}

Then for each proxy that you wish to be protected add the following text to advanced settings. For ease/consistency it is best to add this to every proxy and then set bypass rules in the Authelia configuration file, although omitting this advanced setup from a host will have the same effect. Be sure to alter the highlighted lines (esp line 45) for the server in question.

endpoint proxy advanced settings
location /authelia {
internal;
set $upstream_authelia http://authelia:9091/api/verify; # change from authelia if different Docker container name
proxy_pass_request_body off;
proxy_pass $upstream_authelia;    
proxy_set_header Content-Length "";

# Timeout if the real server is dead
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
client_body_buffer_size 128k;
proxy_set_header Host $host;
proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr; 
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-Ssl on;
proxy_redirect  http://  $scheme://;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_cache_bypass $cookie_session;
proxy_no_cache $cookie_session;
proxy_buffers 4 32k;

send_timeout 5m;
proxy_read_timeout 240;
proxy_send_timeout 240;
proxy_connect_timeout 240;
}

location / {
set $upstream_app $forward_scheme://$server:$port;
proxy_pass $upstream_app;

auth_request /authelia;
auth_request_set $target_url https://$http_host$request_uri;
auth_request_set $user $upstream_http_remote_user;
auth_request_set $email $upstream_http_remote_email;
auth_request_set $groups $upstream_http_remote_groups;
proxy_set_header Remote-User $user;
proxy_set_header Remote-Email $email;
proxy_set_header Remote-Groups $groups;

error_page 401 =302 https://auth.alanjrobertson.co.uk/?rd=$target_url; # change domain name as required

client_body_buffer_size 128k;

proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;

send_timeout 5m;
proxy_read_timeout 360;
proxy_send_timeout 360;
proxy_connect_timeout 360;

proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection upgrade;
proxy_set_header Accept-Encoding gzip;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
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-Ssl on;
proxy_redirect  http://  $scheme://;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_cache_bypass $cookie_session;
proxy_no_cache $cookie_session;
proxy_buffers 64 256k;

set_real_ip_from 172.18.0.0/16;
set_real_ip_from 172.19.0.0/16;
real_ip_header CF-Connecting-IP;
real_ip_recursive on;

}