Authelia is an open-source authentication and authorization server. In conjunction with an NGINX proxy, all pf your proxied apps and services can use the the same login credentials and login session - that is sign in once and have access to all you services without signing in again. It also offers 2FA via email, Google Authenticator, Duo, and Yubikey.

Scenario

This guide outlines setting up Authelia in the following scenario:

  • On a webserver running Ubuntu 18.04s.
  • NGINX is used to proxy a number of apps and services.
  • Authelia will be run in a docker container.
  • Authelia will be deployed in the "light" deployment.

Prerequisites

This guide assumes you have done or know how to do the following:

  • You have created a DNS entry for the subdomain auth.example.com pointing to your server.
  • Your apps and services are proxied to either your root domain or some subdomains.
  • You are familiar with adding SSL certificates to NGINX (If not, check out Let's Encrypt).

Authelia Configuration & Installation

  1. The first step is to install the docker, docker-compose and git packages to prepare for the installation of Authelia.

    We want to install Docker from the official Docker repository to ensure we get the latest version. The following set of commands prepares the repository.

    sudo apt update
    sudo apt install apt-transport-https ca-certificates \
        curl software-properties-common
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
        | sudo apt-key add -
    sudo add-apt-repository "deb [arch=amd64] \
        https://download.docker.com/linux/ubuntu \
        $(lsb_release -cs) stable"
    sudo apt-get update
    

    Now to actually install the packages:

    sudo apt-get install docker-ce docker-ce-cli docker-compose git
    

    All that's left to do is add your user to the docker group so you can manage docker without having to use sudo all the time:

    sudo usermod -aG docker ${USER}
    su - ${USER}
    
  2. Now we'll begin installing Authelia. First we'll create a directory to contain all of Authelia's configuration files and any dependencies. In my case it will be in my users home directory.

    mkdir ~/authelia
    cd ~/authelia
    
  3. To get started were going to make a docker-compose.yml to define the docker containers we're creating. Create a file named docker-compose.yml in your editor of choice and paste the following:

    version: '3.3'
     
    networks:
      net:
        driver: bridge
    
    services:
      authelia:
        image: authelia/authelia
        container_name: authelia
        volumes:
          - ./authelia:/config
        networks:
          - net
        ports:
          - 9091:9091
        restart: unless-stopped
        environment:
          - PUID=1000
          - PGID=1000
          - TZ=America/Vancouver
    
      redis:
        image: redis:alpine
        container_name: redis_authelia
        volumes:
          - ./redis:/data
        networks:
          - net
        expose:
          - 6379
        restart: unless-stopped
        environment:
          - TZ=America/Vancouver
          - PUID=1000
          - PGID=1000
    

    Now we'll work through the contents of this file and I'll point out the changes you'll need to make depending on your setup.

    The first several lines just specify the oldest version of docker engine this file will work with, and the type of network driver docker should use. You probably won't need to change anything here.

    Under services you will find Authelia itself. As well as redis, a database system Authelia uses. As-is in the file each service will have
    their respective files in subdirectories of the directory docker-compose.yml is is. If you prefer some other setup, those can be changed.

    Change PUID and GUID on lines 19, 20, 35, and 36 to your users id's (find your own id's with id $user).

    Change America\Vancouver on lines 21 and 34 to your local timezone (find a list of timezones known to you system with timedatectl list-timezones).

  4. Now we'll make the first of Authelia's configuration files.

    mkdir ~/authelia/authelia
    cd ~/authelia/authelia
    

    Create and open configuration.yml in your editor of choice and paste the following:

    server:
      host: 0.0.0.0
      port: 9091
    log:
      level: info
    jwt_secret: <your-secret-key>
    default_redirection_url: https://apps.example.com
     
    authentication_backend:
      file:
        path: /config/users_database.yml
     
    access_control:
      default_policy: deny
      rules:
        - domain:
            - "auth.example.com"
          policy: bypass
        - domain:
            - "example.com"
            - "*.example.com"
            - "app.example.com"
          policy: one_factor
     
    session:
      name: authelia_session
      secret: <your-secret-key>
      expiration: 12h           # 12 hours
      inactivity: 45m           # 45 minutes
      remember_me_duration: 1M  # 1 month
      domain: example.com
     
      redis:
        host: redis_authelia
        port: 6379
     
    regulation:
      max_retries: 3
      find_time: 5m
      ban_time: 15m
     
    storage:
      encryption_key: <your-encryption-key>
      local:
        path: /config/db.sqlite3
     
    notifier:
      #filesystem:
        #filename: /config/notification.txt
      smtp:
        username: [email protected]
        password: <gmail_password>
        host: smtp.gmail.com
        port: 587
        sender: [email protected]
    

    The first thing to replace in configuration.yml is <your-secret-key> after jwt_secret on line 6, secret on line 27, and <your-encryption-key> on line 43. You should replace these with unique strings. If you want, the command below can be used to generate random seeds. Just make usre to use unique strings for each of the three screts.

    head /dev/urandom | tr -dc A-Za-z0-9 | head -c64
    

    The rest of the options you'll likely want to change are:

    • default_redirection_url: The URL users who navigate directly to the login page will be redirected to after login.
    • access_control: This is the area of the configuration where you set what kind of authentication is required for different subdomains. Rules are defined as a list of domains and the policy they follow.
      • In the configuration template the default_policy is deny and there are two domain rules:
        • The first is a bypass rule allowing anyone to the auth page and the root of the domain. Change these to match your domain.
      • policy: There are four policy options:
        • deny - No access is permitted.
        • one_factor - Login with username and password.
        • two_factor - Login with username, password, and 2FA.
        • bypass - No login required.
      • For more details on the access control list, see the docs.
    • session: This is where cookie setting are set.
      • expiration: How long before the cookie expires.
      • inactivity: Mow much inactivity will cause the cookie to expire.
      • remember_me_duration: How long you will stay signed in for after ticking "remember me".
    • regulation: If there are max_retries failed login attempts in find_time, you will be banned for ban_time.
    • notifier: This is how 2FA codes will be delivered. The template config is setup for emails to be sent from a Gmail address. You can fill this out with your Gmail information, or some other email services smtp settings. Alternatively, comment out all the email settings and uncomment the filesystem ones. This way 2FA codes will just be saved to the listed file.

    For more information or additional configuration options, you can refer to the docs or the sample config.

  5. The last bit of configuration is creating the user data base. In the same directory as the configuration.yml file, create a new file called users_database.yml and put the following into it.

    users:
      <username>:
        displayname: "Your Name"
        # Generate with docker run authelia/authelia:latest authelia hash-password <your-password>
        password: "<hashed-password>"
        email: <your-email>
        groups:
          - admins
    

    Replace <username> with your desired username, Your Name with your full name and <your-email> with your email. To get the hashed-password to replace <hashed-password> with, use the following command.

    docker run authelia/authelia:latest authelia hash-password <your-password>
    

    You can add as many users as you like under the users: key. You can also add yourself or any other users to more groups if you want to do access control based on groups.

  6. We are now ready to spin up Authelia. cd back to the directory containing docker-compose.yml and run the following command to create and run the containers.

    docker-compose up -d
    

    If everything went smoothly, you should be able to navigate to <webserver-ip>:9091 and be presented with Authelia's login prompt. Try the username and password you setup in step 5!

Adding Authelia to NGINX

Now that Authelia is setup and running, it's time to tie it into NGINX.

  1. The first thing we need to do is create a new site configuration for auth.example.com. For example:

    sudo vim /etc/sudo vim /etc/nginx/sites-available/auth.example.com
    

    Of course, replace example.com with your domain name. Paste the following into the new configuration file:

    server {
        server_name auth.example.com;
        listen 80;
        return 301 https://$server_name$request_uri;
    }
    
    server {
        server_name auth.example.com;
        listen 443 ssl http2;
    
        location / {
            set $upstream_authelia http://127.0.0.1:9091;
            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 reverse proxy, forwards the correct IP
            set_real_ip_from 10.0.0.0/8;
            set_real_ip_from 172.0.0.0/8;
            set_real_ip_from 192.168.0.0/16;
            set_real_ip_from fc00::/7;
            real_ip_header X-Forwarded-For;
            real_ip_recursive on;
        }
    }
    

    Replace all occurrences of example.com with your domain name. Then to enable this new site, run:

    sudo ln -s /etc/nginx/sites-available/auth.example.com /etc/nginx/sites-enabled/auth.example.com
    sudo systemctl reload nginx
    

    Now is a good time to get an SSL certificate for auth.example.com. An example of how to do this with letsencrypt's certbot:

    sudo certbot run -d auth.example.com --nginx
    

    Now try navigating to auth.example.com. If all went well, you should again see the Authelia login prompt.

  2. Now we'll make a couple configuration snippets to make adding Authelia to our sites easier. Create and open a file /etc/nginx/snippets/authelia.conf and the past the following into it.

    # Virtual endpoint created by nginx to forward auth requests.
    location /authelia {
        internal;
        set $upstream_authelia http://127.0.0.1:9091/api/verify;
        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;
    
        # [REQUIRED] Needed by Authelia to check authorizations of the resource.
        # Provide either X-Original-URL and X-Forwarded-Proto or
        # X-Forwarded-Proto, X-Forwarded-Host and X-Forwarded-Uri or both.
        # Those headers will be used by Authelia to deduce the target url of the     user.
        # Basic Proxy Config
        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;
    
        # Advanced Proxy Config
        send_timeout 5m;
        proxy_read_timeout 240;
        proxy_send_timeout 240;
        proxy_connect_timeout 240;
    }
    

    This snippet will be added to the server block of any site we secure with Authelia. We need one more snippet. Create and open /etc/nginx/snippets/auth.conf, then paste the following in.

    # Basic Authelia Config
    # Send a subsequent request to Authelia to verify if the user is authenticated
    # and has the right permissions to access the resource.
    auth_request /authelia;
    # Set the `target_url` variable based on the request. It will be used to build the portal
    # URL with the correct redirection parameter.
    auth_request_set $target_url $scheme://$http_host$request_uri;
    # Set the X-Forwarded-User and X-Forwarded-Groups with the headers
    # returned by Authelia for the backends which can consume them.
    # This is not safe, as the backend must make sure that they come from the
    # proxy. In the future, it's gonna be safe to just use OAuth.
    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;
    # If Authelia returns 401, then nginx redirects the user to the login portal.
    # If it returns 200, then the request pass through to the backend.
    # For other type of errors, nginx will handle them as usual.
    error_page 401 =302 https://auth.example.com/?rd=$target_url;
    

    All you need to do here is replace example.com on the last line with your domain.

  3. Now we can edit our existing example.com NGINX site config to add Authelia.

    • You will include the snippet authelia.conf into the main server block.
    • You will include the snippet auth.conf into any location block you want to protect.

    For example:

    server {
        server_name app.example.com;
        listen 80;
        return 301 https://$server_name$request_uri;
    }
    
    server {
        server_name app.example.com;
        listen 443 ssl http2;
        include snippet/ssl.conf;
    
        include snippets/authelia.conf; # Authelia auth endpoint
    
        location / {
            proxy_pass http://proxied:service;
    	    proxy_set_header Host $host;
    	    proxy_set_header X-Real-IP $remote_addr;
    	    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    
    	    include snippets/auth.conf; # Protect this endpoint
        }
    }
    

    You should just be able to add the snippets in the correct locations to your existing configuration.

    Test the configuration and then reload NGINX:

    sudo nginx -t
    sudo systemctl reload nginx
    

    Congratulations! If everything your done!

Test It Out

Try navigating to any protected endpoint you configured, you should be presented with the login prompt. After entering your credentials, you should be redirected to your destination. If you setup multiple endpoints, going to a second one should not ask for a password because you are still logged in.

If you want to logout, you can navigate to auth.example.com and you will be presented with a logout button. auth.example.com/logout will also accomplish the same.

Down the line: Updating

Because we used docker-compose to bring up this system updating any part of it is very simple. Just run the following commands to pull the latest images and then rebuild and start the containers.

cd ~/authelia
docker-compose pull
docker-compose up --force-recreate --build -d
docker image prune -f

Resources

  • You can download all the configuration templates here.
  • See the official Authelia docs here.
  • Have a look at the official, complete sample config here.

Email me with any suggestions or feedback!