SWAG - Secure Web Application Gateway (formerly known as letsencrypt) is a full fledged web server and reverse proxy with Nginx, Php7, Certbot (Let's Encryptâ„¢ client) and Fail2ban built in. Authelia is an open-source authentication and authorization server providing 2-factor authentication and single sign-on (SSO) for your applications via a web portal. This article will detail how SSO via Authelia can be easily set up using SWAG's preset Authelia confs.
This article assumes that you already have a functional SWAG setup. Following is the compose yaml used to create the SWAG and Authelia containers referenced in this article. Keep in mind your local mount paths will be different so adjust accordingly.
Note that the following assumes you are using Authelia 4.34.6. If you wish to use a newer version, please refer to their configuration migration guide and release info; and adjust your config as appropriate.
---
version: "2.1"
services:
swag:
image: lscr.io/linuxserver/swag
container_name: swag
cap_add:
- NET_ADMIN
environment:
- PUID=1000
- PGID=1000
- TZ=America/New_York
- URL=linuxserver-test.com
- SUBDOMAINS=wildcard
- VALIDATION=dns
- DNSPLUGIN=cloudflare #optional
- PROPAGATION= #optional
- DUCKDNSTOKEN= #optional
- EMAIL= #optional
- ONLY_SUBDOMAINS=false #optional
- EXTRA_DOMAINS= #optional
- STAGING=false #optional
volumes:
- /home/user/swag:/config
ports:
- 443:443
- 80:80 #optional
restart: unless-stopped
authelia:
image: ghcr.io/authelia/authelia:4.34.6
container_name: authelia
user: "1000:1000"
environment:
- TZ=America/New_York
volumes:
- /home/user/authelia:/config
restart: unless-stopped
This yaml will create two containers, one for SWAG and one for Authelia. Since docker-compose automatically creates a user defined bridge network and puts all containers into that network by default, our containers will be able to reach each other using their container names as DNS hostnames. See our previous blog article for more info on this. If you're using docker cli or a gui application to create the containers, you will have to manually create a user defined bridge network and attach both containers to that network.
Setting up Authelia with a users file and 2 factor auth via Duo Mobile
We will go ahead and set up 2 factor authentication utilizing Duo Mobile as the push provider and for brevity, we will use a yaml file to contain the first factor user/pass info. However, Authelia allows various other methods like LDAP, TOTP, etc.
As of Authelia v4.20.0, the default location for all Authelia config is /config
inside the container, so we will refer to that location in the config files. On the host, that folder is mapped to /home/user/authelia
. Let's first create the Authelia folders with our user because Authelia does not do chown on its config folder like linuxserver containers do, and we are running it with user: "1000:1000"
. A simple mkdir -p /home/user/authelia/logs
with our linux user (in this case uid 1000) should suffice, and both the config folder and the logs folder will be created.
Inside the host folder /home/user/authelia
, we will place the following Authelia config files, configuration.yml
and users_database.yml
:
configuration.yml
server:
host: 0.0.0.0
port: 9091
read_buffer_size: 4096
write_buffer_size: 4096
path: "authelia"
log:
level: info
file_path: /config/logs/authelia.log
jwt_secret: somethingsomethingrandomsecret
default_redirection_url: https://domain.url
duo_api:
hostname: api-somenumber.duosecurity.com
integration_key: SOMESECRETKEY
secret_key: somelongersecretkey
authentication_backend:
disable_reset_password: false
file:
path: /config/users_database.yml
password:
algorithm: argon2id
iterations: 1
key_length: 32
salt_length: 16
memory: 512
parallelism: 8
access_control:
default_policy: deny
rules:
- domain:
- domain.url
- "*.domain.url"
policy: two_factor
session:
name: authelia_session
secret: somerandomsecret
expiration: 1h
inactivity: 5m
remember_me_duration: 1M
domain: domain.url
regulation:
max_retries: 3
find_time: 2m
ban_time: 5m
storage:
encryption_key: somethingsomethingreallylongandsecret
local:
path: /config/db.sqlite3
notifier:
disable_startup_check: false
smtp:
username: myemail@gmail.com
password: longpassword
host: smtp.gmail.com
port: 587
sender: myemail@gmail.com
subject: "[Authelia] {title}"
startup_check_address: test@authelia.com
disable_require_tls: false
tls:
skip_verify: false
minimum_version: TLS1.2
Let's break it down and look at some of the important lines and their meaning:
path: "authelia"
Tells Authelia to listen at subfolder /authelia
for requests (required by the default SWAG config).
duo_api:
hostname: api-somenumber.duosecurity.com
integration_key: SOMESECRETKEY
secret_key: somelongersecretkey
Duo api settings retrieved from Duo's website.
authentication_backend:
disable_reset_password: false
file:
path: /config/users_database.yml
password:
algorithm: argon2id
iterations: 1
key_length: 32
salt_length: 16
memory: 512
parallelism: 8
Tells Authelia to use the file /config/users_database.yml
for user/password listings. It also defines the password format that Authelia should use and these numbers should be customized based on the hardware specs. Refer to Authelia docs for more info: https://docs.authelia.com/configuration/authentication/file.html#password-hashing-configuration-settings
access_control:
default_policy: deny
rules:
- domain:
- domain.url
- "*.domain.url"
policy: two_factor
Sets the access control policy as Two Factor
auth for the main domain and all subdomains and sets a default deny
for unauthorized users.
One main gotcha in this section is the line - "*.domain.url"
. In yaml format, all lines starting with a *
have to be wrapped in quotes, otherwise it will be invalid and Authelia will fail to start due to not being able to parse the yaml.
storage:
encryption_key: somethingsomethingreallylongandsecret
local:
path: /config/db.sqlite3
Tells Authelia to use a local sqlite database to store all data (as opposed to an external database like mysql/mariadb).
notifier:
disable_startup_check: false
smtp:
username: myemail@gmail.com
password: longpassword
host: smtp.gmail.com
port: 587
sender: myemail@gmail.com
subject: "[Authelia] {title}"
startup_check_address: test@authelia.com
disable_require_tls: false
tls:
skip_verify: false
minimum_version: TLS1.2
External SMTP server details for Authelia to send e-mails through (like forgot password
e-mails).
Notice how the three files defined, configuration.yml
, users_database.yml
and db.sqlite3
are all defined as residing at /config
, which is the folder we are mounting inside the container.
users_database.yml
users:
aptalca:
displayname: "aptalca"
password: "$argon2id$v=19$m=524288,t=1,p=longrandompasswordhashgenerated"
email: myemail@gmail.com
groups: []
This file contains all of the authorized users, their passwords, e-mail addresses (used for password resets via e-mail), and the groups they belong to. In this example, we only have one user set up, but you can create multiple users with multiple group memberships and create a hierarchy.
The password can be generated in command line via docker run --rm authelia/authelia:latest authelia hash-password yourpassword
. Replace yourpassword
with your choice of password. See the Authelia docs for more info and optional arguments: https://docs.authelia.com/configuration/authentication/file.html#passwords
Enabling Authelia in SWAG
SWAG comes with two preset Authelia conf files located at /config/nginx/authelia-server.conf
and /config/nginx/authelia-location.conf
. To enable Authelia integration, these confs would have to be included (activated) in the server
and location
blocks respectively for each domain/subdomain/subfolder served or reverse proxied. Assuming Authelia is set up with path: "authelia"
in its configuration.yml, these preset Authelia confs do not need any modifications and will work out of the box when enabled.
Enabling for Heimdall reverse proxied via subdomain:
To enable Authelia for Heimdall on a subdomain, we simply edit the file /home/user/swag/nginx/proxy-confs/heimdall.subdomain.conf
. In there, we'll see two commented lines for authelia-server.conf
and authelia-location.conf
, which reside in the server
and location
blocks respectively. We will simply remove the #
characters from the beginning of those two lines to enable both, and then restart the SWAG container.
The edited conf should look like this:
# make sure that your dns has a cname set for heimdall
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name heimdall.*;
include /config/nginx/ssl.conf;
client_max_body_size 0;
# enable for ldap auth, fill in ldap details in ldap.conf
#include /config/nginx/ldap.conf;
# enable for Authelia
include /config/nginx/authelia-server.conf;
location / {
# enable the next two lines for http auth
#auth_basic "Restricted";
#auth_basic_user_file /config/nginx/.htpasswd;
# enable the next two lines for ldap auth
#auth_request /auth;
#error_page 401 =200 /ldaplogin;
# enable for Authelia
include /config/nginx/authelia-location.conf;
include /config/nginx/proxy.conf;
resolver 127.0.0.11 valid=30s;
set $upstream_app heimdall;
set $upstream_port 443;
set $upstream_proto https;
proxy_pass $upstream_proto://$upstream_app:$upstream_port;
}
}
Now when we try to access https://heimdall.linuxserver-test.com
, we should be auto-redirected to https://heimdall.linuxserver-test.com/authelia
and asked for login info.
Enabling for Bazarr reverse proxied via subfolder:
To enable Authelia for Bazarr on a subfolder, we simply edit the file /home/user/swag/nginx/proxy-confs/bazarr.subfolder.conf
. Different from the subdomain confs, there is no server
block in subfolder proxy confs because they all get imported into the main server
block inside the default
site conf. Therefore, we'll only see one commented line for authelia-location.conf
in there. We will simply remove the #
character from the beginning of that line to enable. Then we need to edit the default site conf at home/user/swag/nginx/site-confs/default
, find the line for authelia-server.conf
and enable it by removing the #
preceding it. Then we restart the SWAG container.
Here's the edited subfolder proxy conf for Bazarr (notice how the location
block for /bazarr/api
doesn't contain the authelia conf line, that's because api calls would otherwise fail due to inability to authenticate with Authelia, so we let those calls bypass Authelia):
# first go into bazarr settings, under "General" set the URL Base to /bazarr/ and restart the bazarr container
location /bazarr {
return 301 $scheme://$host/bazarr/;
}
location ^~ /bazarr/ {
# enable the next two lines for http auth
#auth_basic "Restricted";
#auth_basic_user_file /config/nginx/.htpasswd;
# enable the next two lines for ldap auth, also customize and enable ldap.conf in the default conf
#auth_request /auth;
#error_page 401 =200 /ldaplogin;
# enable for Authelia, also enable authelia-server.conf in the default site config
include /config/nginx/authelia-location.conf;
include /config/nginx/proxy.conf;
resolver 127.0.0.11 valid=30s;
set $upstream_app bazarr;
set $upstream_port 6767;
set $upstream_proto http;
proxy_pass $upstream_proto://$upstream_app:$upstream_port;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
location ^~ /bazarr/api {
include /config/nginx/proxy.conf;
resolver 127.0.0.11 valid=30s;
set $upstream_app bazarr;
set $upstream_port 6767;
set $upstream_proto http;
proxy_pass $upstream_proto://$upstream_app:$upstream_port;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
When we try to access https://linuxserver-test.com/bazarr
, we will get auto-redirected to https://linuxserver-test.com/authelia
and asked for login info.
Summary
In a nutshell, in order to enable Authelia for any domain, subdomain or subfolder that is either served or proxied, one has to include (activate) the authelia-server.conf
in its server
block, and the authelia-location.conf
in its location
block. Everything else works like magic.
If you stumble on any of the steps above, or having issues with other customizations, feel free to drop by our (Linuxserver) discord or Authelia's Matrix.
If you like our work, you can support both Linuxserver and Authelia teams on OpenCollective: