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
-
The first step is to install the
docker
,docker-compose
andgit
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}
-
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
-
To get started were going to make a
docker-compose.yml
to define the docker containers we're creating. Create a file nameddocker-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 directorydocker-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 withtimedatectl list-timezones
). -
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>
afterjwt_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
isdeny
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.
- The first is a
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.
- In the configuration template the
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 aremax_retries
failed login attempts infind_time
, you will be banned forban_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.
-
The last bit of configuration is creating the user data base. In the same directory as the
configuration.yml
file, create a new file calledusers_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. -
We are now ready to spin up Authelia.
cd
back to the directory containingdocker-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.
-
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. -
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. -
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!
- You will include the snippet
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!