Safely expose your services to the world using nginx and 2FA

Creating and securing your reverse proxies with SWAG and Authelia

Containers Sep 25, 2021

Reverse proxies are a great way to access services and apps on your NAS when you're not on your local network. It's also a more secure way to allow others to access your website or service than giving them your public IP address and forwarding your ports through your router. In fact, that last option exposes your whole network to the world and it won't be long before you start seeing intrusion attempts.

Instead, we will use a method which means we only need to keep one, secure, port open.

With the uptake of https, and using a CDN like Cloudflare, you can now protect your public IP from prying eyes, and ensure connections are secure and authorized. We're not going to go into setting up Cloudflare in this article (I'm going to assume you've got your own fully qualified domain name (FQDN) and CDN already set up, and know how to create your A or CNAME records for your reverse proxies) but I will show you how to set up two services:

  1. SWAG: a 3-in-1 service which acts as your nginx reverse proxy server, your SSL certificate requester via LetsEncrypt, and fail2ban jail server (fail2ban is a great tool which monitors attempted auths to your services, and bans IPs which fail to provide correct auth within a certain amount of attempts/time)
  2. Authelia: an authorization service which will act as a single authorizer for your services

The way this works is relatively simple (though it may not look it at first). When your CDN receives a DNS query for your and forwards it to your public IP, your nginx server sees that query, checks the app.subdomain.conf files and routes it to your app or container. So far so easy.

The app.subdomain.conf file also has an option to route the request through Authelia first. So when nginx receives the query, instead of just saying 'ok here's radarr' it goes 'hold up, this is meant to be sent to authelia first', sends it there, and only once the correct auth has been given by authelia will it then say 'ok, now I can send you to radarr'.

Enough of that, let's get these set up. You can jump to a specific part of the page by opening this drop down box:


Prepping for SWAG

There are a few things you will need for SWAG to work effectively:

  1. Knowledge of how to use docker-compose. If you don't, please read up on it here
  2. Knowledge of using .env files to pass information to docker-compose. If you don't know how or don't want to use .env files, then remove anything in the below compose template that begins with a $ (dollar sign) and type in your own information for that variable
  3. A pre-created folder already set up on your system which we will point our SWAG config at (make sure permissions are set up to allow docker to read/write to it)
  4. A docker network created and ready (which I've called proxy)
  5. The details for your certificate validation method (my example below uses DNS validation with Cloudflare as it's my CDN, which is doubly secure as DNS validation doesn't require port 80 to be open on my router for LetsEncrypt, which other methods do)
  6. Port 443 forwarded from your router to your SWAG host machine - note that if you change the host port in the container setup below (say you use 444 instead) you will need to make sure that port 443 from your router is forwarded to port 444 on your host machine
  7. The email address you registered or will use for your let's encrypt certificates
  8. A Maxmind License Key if you want to use geoIP restrictions, such as allowing connections from Mongolia but not from Argentina (go to the maxmind website to create your free account and create your license, be sure to take note of it)
  9. A general read of the SWAG documentation is always a good shout, you can find that here
Since writing this article, linuxserver have modified the method used to do geoIP blocking (although it still requires the maxmind key mentioned above and included in the compose file below). You can visit this page in their documentation to read up on the steps needed to enable it

Creating the SWAG container

First up we're going to create our docker proxy network. SSH into your machine and type in:

sudo docker network create proxy

This creates the proxy network we will connect our SWAG container to.

Once that's done, copy and paste this template to create your docker-compose.yml file:

    container_name: swag
      - NET_ADMIN
      - TZ=$TZ #change to your timezone
      - URL=$DOMAINNAME #change to the domain you want to protect with a certificate
      - SUBDOMAINS=wildcard
      - VALIDATION=dns
      - DNSPLUGIN=cloudflare
      - EMAIL=$EMAIL ADDRESS #change, can be any email address
      - ONLY_SUBDOMAINS=false
      - MAXMINDDB_LICENSE_KEY=$MAXMINDDB #remove if not necessary
      - DOCKER_MODS=linuxserver/mods:swag-cloudflare-real-ip|linuxserver/mods:swag-auto-reload|linuxserver/mods:universal-docker|linuxserver/mods:swag-auto-proxy #delete if not wanted or necessary
      - DOCKER_HOST=socket-proxy #delete if not wanted or necessary
      - $DOCKERDIR/swag:/config #change before the `:` to your swag path
      #uncomment the next line if you haven't set up a socket-proxy container
      #- /var/run/docker.sock:/var/run/docker.sock:ro 
      - 443:443 #change before the ':' if necessary, take note of port-forwarding comment at point 6 above if you do change it
      - 80:80 #change before the ':' if necessary
    restart: unless-stopped
      - proxy
      - socket_proxy

    external: true
    external: true
port 80 isn't 100% necessary if you are using DNS validation. all 
For parts of the above to work as intended, you should set up a socket.proxy container. Follow the link here to set it up. If you don't, remove all mention of the socket_proxy network, the universal-docker and auto-proxy mods in the environment block below, and uncomment the volume mapping of - /var/run/docker.sock:/var/run/docker.sock:ro.

Let's break this down a little:

  • URL is where you put your domain name, without any http, https or www
  • SUBDOMAINS can either be a list of your subdomains for which SWAG will request SSL certificates (i.e. SUDBOMAINS=radarr,sonarr,prowlarr,nextcloud etc.) OR as in the above, it can be a wildcard, which will request a * certificate, good for each and every you could want to create
  • VALIDATION and DNSPLUGIN are specific to your preferences, and it can be found in their documentation here
  • EMAIL is pretty self explanatory
  • ONLY_SUBDOMAINS can either be true or false. If true, it means that SWAG will only request the specified subdomain or wildcard certificate. If false, it will also request a certificate as well
  • DOCKER_MODS adds 3 very helpful tools, separated by the | character. The first allows your SWAG container to read actual incoming IPs rather than just see everything as originating from your container IP (this only works if you're using Cloudflare as your domain host). The second removes the need to completely restart the container when you make a change to a proxy.conf or other nginx-related files. The third (which requires the universal-docker and auto-proxy mods) allows SWAG to automatically create reverse proxies using labels
  • volumes, ports and networks should be self explanatory

Preparation required for creating your first reverse proxy

before doing this, I highly recommend you create your A or CNAME for one or more of your services on your CDN. A good first option would be something like radarr or sonarr

Once you've created your compose file, create the container with docker-compose up -d and confirm that it's running.

If you're using Cloudflare

(If you're not, jump to here)

First we're going to change the cloudflare.ini file, which can be found inside the dns-conf directory. Here we need to do 2 things:

  1. input the email address you use to log in to your Cloudflare account
  2. input your Global API Key (by clicking the link and then viewing your global api key)
  3. restart your SWAG container (may be unnecessary but just in case)

Cloudflare and proxying your connection (orange cloud)

Once of Cloudflare's best features is that it will protect your public IP by proxying connections through one of its IPs. To make use of this, you need to do a few things.

  • On your Cloudflare DNS page, make sure you've toggled on the orange cloud which says 'Proxied' next to it
  • Navigate to your SWAG config files, and locate nginx.conf
  • Locate the http block, and inside the { } brackets, add the following lines:
    # docker mod cloudflare_real-ip
    real_ip_header X-Forwarded-For;
    real_ip_recursive on;
    include /config/nginx/cf_real-ip.conf;

I put it at the bottom, which means it looks like the screenshot below, but you can put it anywhere you want within the brackets:

  • Save the file, and restart SWAG (if necessary)

For all users

  • Navigate to the nginx folder and select the ssl.conf folder, ensuring that at least the following lines are uncommented, meaning the whole file should look like this:
# Certificates
ssl_certificate /config/keys/letsencrypt/fullchain.pem;
ssl_certificate_key /config/keys/letsencrypt/privkey.pem;
# verify chain of trust of OCSP response using Root CA and Intermediate certs
ssl_trusted_certificate /config/keys/letsencrypt/fullchain.pem;

# Diffie-Hellman Parameters
ssl_dhparam /config/nginx/dhparams.pem;

# Enable TLS 1.3 early data
ssl_early_data on;

# HSTS, remove # from the line below to enable HSTS
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

# Optional additional headers
#add_header Cache-Control "no-transform" always;
add_header Content-Security-Policy "upgrade-insecure-requests; frame-ancestors 'self'";
#add_header Referrer-Policy "same-origin" always;
add_header X-Content-Type-Options "nosniff" always;
#add_header X-Frame-Options "SAMEORIGIN" always;
#add_header X-UA-Compatible "IE=Edge" always;
add_header X-XSS-Protection "1; mode=block" always;
you can uncomment other optional headers if you know what you're doing
  • Save and close this file
I always prefer having HSTS enabled, however some people may have use-cases where that's not necessary. Comment it again by putting a '#' in front of the line if you want
  • We shouldn't need to touch any other .conf files in this directory just yet. Instead, inside nginx, navigate to the proxy-confs directory, and take a look at all of the 'sample' .confs. These are what we and SWAG use to set up a reverse proxy

Creating a reverse proxy using the auto-proxy docker mod

Provided SWAG has a template service.subdomain.conf.sample file for the service you want to reverse proxy, you can use this method. If it doesn't, you'll need to jump to here.

I'm going to assume you followed the steps on my socket proxy article already. If you haven't, then you're going to need to add a volume mapping to your SWAG container:

      - /var/run/docker.sock:/var/run/docker.sock:ro

Either way, we're going to jump straight in and create our radarr container which will tell SWAG to configure the correct proxy.conf.

Check out the compose file below:

    name: proxy
    external: true

  radarr: #movie search agent
    container_name: radarr
      - PUID=$PUID
      - PGID=$PGID
      - TZ=$TZ
      - UMASK=022
      - $DOCKERDIR/Radarr:/config
      - $MEDIADIR:/media
      - 7878:7878
      - swag=enable
    restart: unless-stopped

It's a standard radarr compose file, but we've done a few things:

  • We've set the default network to be the same that SWAG uses, called proxy
  • We've added a label which, when SWAG scans the docker socket, enables it to see that radarr wants a proxy.conf

We can see this taking place in our SWAG logs:

**** Remote docker service socket-proxy will be used ****
s6-rc: info: service init-mod-universal-docker-setup successfully started
s6-rc: info: service init-mod-swag-auto-proxy-setup: starting
**** libmaxminddb already installed, skipping ****
**** Installing all mod packages ****
s6-rc: info: service init-mod-swag-cloudflare-real-ip-setup successfully started
**** Using preset proxy conf for radarr ****
s6-rc: info: service init-mod-swag-auto-proxy-setup successfully started
(1/1) Installing inotify-tools (
Executing busybox-1.34.1-r7.trigger
OK: 252 MiB in 231 packages

Note line 9, Using preset proxy conf for radarr.

And that's it. It may need a few seconds to configure, and if you have many containers with the label it may take even longer, but you now have a working auto-proxy service.

Creating your reverse proxy using the template .conf file

This is what you'll need to do when it's not possible to use the auto-proxy mod.

Head over to whatever you set as your $DOCKERDIR/swag folder on your host machine. Via SMB in Windows, it should look something like this:

Make sure your mapped directory has the relevant permissions for Docker to write to it, otherwise the above won't populate and your container won't start properly

We're going to stick with radarr as a reverse proxy, and I'm going to assume you've already set up your A or CNAME for it.

  • Locate the radarr.subdomain.conf.sample file, and open it. You should see something like this:
## Version 2021/05/18
# make sure that your dns has a cname set for radarr and that your radarr container is not using a base url

server {
    listen 443 ssl;
    listen [::]:443 ssl;

    server_name radarr.*;

    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;
        include /config/nginx/resolver.conf;
        set $upstream_app radarr;
        set $upstream_port 7878;
        set $upstream_proto http;
        proxy_pass $upstream_proto://$upstream_app:$upstream_port;


    location ~ (/radarr)?/api {
        include /config/nginx/proxy.conf;
        include /config/nginx/resolver.conf;
        set $upstream_app radarr;
        set $upstream_port 7878;
        set $upstream_proto http;
        proxy_pass $upstream_proto://$upstream_app:$upstream_port;

your version number may be different depending on how long ago I first started using SWAG

Again let's break this down a little bit into the various blocks:

  • server: tells the SWAG container various things such as which port to listen in on and which subdomain will be forwarded by the CDN. It has options to uncomment for LDAP or Authelia integration (we'll come back to the Authelia stuff later on)
if you didn't set your A or CNAME record as radarr, but something like movies for instance, change this in server_name radarr.*; to server_name movies.*;
  • location block 1 and 2: we're interested only in the following (in both blocks):
    include /config/nginx/proxy.conf;
    include /config/nginx/resolver.conf;
    set $upstream_app radarr;
    set $upstream_port 7878;
    set $upstream_proto http;
    proxy_pass $upstream_proto://$upstream_app:$upstream_port;
you'll notice it's the same in both blocks

In fact, we're only interested in the following two lines:

    set $upstream_app radarr;
    set $upstream_port 7878;
these tell SWAG where to look for the service
  • If you've used the default container name and port when creating your radarr container, those being radarr and 7878, and you've got your radarr and SWAG containers on the same docker network then you don't need to change a thing
  • If however you did change your port or container name, then you need to reflect those changes here
  • If you have your SWAG and radarr containers on different docker networks, then where it says set $upstream_app radarr;, you must change radarr to the IP of your host machine, without any http or https such as
you need to make any required changes in both blocks
  • When you think you've got this ready to go, rename the file as radarr.subdomain.conf. Do not only save it, as the .sample on the end means that SWAG will not read it
  • You must now restart your SWAG container - any change to a .conf file will not be read other than at container start-up
  • You should now be able to go to and access your radarr gui (or or which matches the A or CNAME you set on your CDN)

And with that you've set up your first reverse proxy. Rinse and repeat for any and all other services. Note that some of the .sample files will have differences, either more or less dependent on the service's requirements.

You may also find that a .sample file doesn't exist for your specific service. In that case, choose one which you think will likely fit, make sure you change the name in the server_name part of the server block to your A or CNAME record, change the relevant parts of the location block(s) and it should work.

A few notes on Fail2ban

Some configuration is required for fail2ban to work in the way you want it to. The SWAG github repo has info here which I recommend reading, but essentially you will want to go through your jail.local in the fail2ban directory. It's worth noting that while 5 jails are included by default in the installation, but other jails can be added by creating their files with .local rather than .conf (the .conf files are recreated every time the container is restarted).  

It's possible that your fail2ban instance may read every IP as the docker bridge network gateway it's on (i.e. 172.xx.xx.1). Specific to Synology, this link has a work around for iptables, but may be applicable to other systems. If you think you may get blocked by default, it's worth disabling your banaction in jail.local by commenting it out (putting a # in front of the line) until you're confident fail2ban is reading IPs correctly.

If you're proxying your domain behind Cloudflare, then everything will come through as one of Cloudflare's proxy IP addresses. While it's not going to block you, it also doesn't help you understand your real traffic, and again could just end up blocking Cloudflare's proxy and no external IP would be able to access your service. I've already included the dockermod in the docker-compose file for Cloudflare to pass the real IP to the container, however  you also need to make a change to the nginx.conf file. Click here to get the instructions.

It's also worth noting that IP obfuscation, either due to docker networking or proxying, will affect the accuracy of your GeoIP tracking via maxmind


Now that you've set up your reverse proxy, you've decided you want to add some security to access it. Enter Authelia.

Buckle up, this will take a bit of time.

Prepping for Authelia

To create and run this container, you'll need the following prepped:

  1. The ability to create a reverse proxy to your Authelia container (handy that you've just learnt how to do that from SWAG hey? Go search for the authelia.subdomain.conf.sample file)
  2. The following folders set up in your $DOCKERDIR: authelia, and subdirectories inside called app, redis and sql
  3. A docker network set up called auth

Creating the necessary containers

The below is a template compose which will create the Authelia service, as well as a database container, a database management container, and a redis container. If you already have a database container you want to use, you do not need to create them again in this stack, and the auth-mysql, auth-phpmyadmin and auth-redis services can be removed. I however like to have a completely separate database container for Authelia.

    external: true
    external: true

    image: authelia/authelia
    container_name: authelia
      - 9091:9091 #change before the ':' as necessary
      - PUID=$PUID #change to your user ID
      - PGID=$PGID #change to your group ID
      - auth-redis
      - auth-mysql
      - $DOCKERDIR/authelia/app:/config/ #change `$DOCKERDIR` to your docker directory
    restart: unless-stopped
      - auth
      - proxy

    image: mysql:latest
    container_name: authelia_mysql
      - $DOCKERDIR/authelia/sql:/var/lib/mysql #change the local path to your NAS location where you want the DB data to live
      - MYSQL_ROOT_PASSWORD=$MYSQLROOTPWD #enter a password for your main sql root user account 
      - 3306:3306 #change before the ':' as necessary
    restart: unless-stopped
      - auth
    image: phpmyadmin/phpmyadmin:latest
    container_name: authelia_php
      - 81:80 #changed because we already used port 80 for SWAG
      - PMA_PORT=3306 #enter the same port that you have your auth-mysql running on
      - PMA_HOST=auth-mysql
    restart: unless-stopped
      - auth
    image: redis:latest
    container_name: authelia_redis
      - $DOCKERDIR/authelia/redis:/data #change the local path to your NAS location where you want the DB data to live
      - 6379:6379 #change before the ':' as necessary
    restart: unless-stopped
      - auth
make changes where indicated or necessary

Once more, let's break this down:

  • authelia - depends_on both the mysql and redis containers, meaning it won't start up unless they also have started up; networks to both auth and proxy, as it needs to communicate with SWAG as well
  • auth-mysql - the database container authelia will use, and sets up a root password to access the database server
  • auth-phpmyadmin - a container to create and manage individual databases and users in the mysql container
  • auth-redis - not 100% necessary, but will speed up request returns when authelia is invoked by SWAG
Note that we currently do not have any database configuration set up, or a way to pass user/password details to authelia. This will be set up in the next step

When you're ready, run your docker-compose up -d command, and watch your 4 containers being created. Once spun up, I would stop the authelia container, either through Portainer if you use it, or via the CLI.

Creating the mysql database and user for authelia

I've written an article about MySQL and phpMyAdmin here. Go through it and set up a database with a user, password and database name of your choice. For the sake of this walkthrough, I'm going to say that both the user and database name is 'authelia'. The password is your own.

when you are offered a choice of collation during the creation of the database, it's recommended to use utf8_bin

Setting the Authelia configuration

We now have all the information we need to modify the configuration.yml file which Authelia uses.

UPDATE 2023/01: A change in the way Authelia reads the configuration.yml meant users trying to set things up the way I'd originally shown weren't having success. I've modified the configuration file below so new installations should work, however if for any reason you're having difficulties please drop a comment at the bottom of the page.

Existing working installations will continue to work, no changes are required.
  • Navigate to your $DOCKERDIR/authelia/app directory and open configuration.yaml. It's a rather long file, so below I'm going to include only the information which needs to be changed, and some of the information you shouldn't change, but overall it should now look like this:
#                           Authelia Configuration                            #

theme: dark
jwt_secret: "YOUR_JWT_SECRET" #change this to at least a 32-character string
default_redirection_url: https://YOUR_DOMAIN.COM/ #such as

  host: #do not change
  port: 9091 #do not change, this is the INTERNAL port so will always be 9091
  path: "authelia" #if your setup doesn't work off the bat, try changing this to ""
  read_buffer_size: 8192
  write_buffer_size: 8192
  enable_pprof: false
  enable_expvars: false
  disable_healthcheck: false
    key: ""
    certificate: ""

  level: info

  issuer: YOUR_DOMAIN.COM #such as
  period: 30
  skew: 1

    disable: false #change to true if you want to stop users from resetting their passwords
  refresh_interval: 30m #I found that the default of 5 is too short
    path: /config/users_database.yml #don't change this
      algorithm: argon2id
      iterations: 1
      key_length: 32
      salt_length: 16
      memory: 1024
      parallelism: 8

access_control: #Recommend reading up on all the options for access control 
  default_policy: deny
  #rule order matters
    - name: internal
      networks: #uncomment (remove the #) the line(s) below which matches your internal network, or add your own (without the #)
  rules: # for more rule examples
    ## bypass rule
    - domain: "" #change to your issuer domain above
      policy: bypass

    ## catch-all
	#bypass authelia while on LAN
    - domain: "*"
        - internal
      policy: bypass

	#rules for everyone
    - domain: "*"
      policy: one_factor

  name: authelia_session #do not change
  domain: YOUR_DOMAIN.COM #this should be your root domain, such as ""
  same_site: lax
  secret: "YOUR_SESSION_SECRET" #make this a long strong, 26 characters or so
  expiration: 1h
  inactivity: 5m
  remember_me_duration: 2M
    host: authelia_redis #change to your host machine's IP if this doesn't work
    port: 6379 #if you use IP above, make sure this matches the mapped port
    password: "" #do not change. if this doesn't work, remove the "" and try again
    database_index: 0
    maximum_active_connections: 10
    minimum_idle_connections: 0

  max_retries: 3
  find_time: 10m
  ban_time: 12h

  encryption_key: "YOUR_STORAGE_ENCRYPTION_KEY" #use a 20-character random string
    host: authelia_mysql #change this to your host machine's IP if this doesn't work
    port: 3306 #if you use IP above, make sure this matches the mapped port
    database: authelia
    username: authelia
    password: "YOUR_MYSQL_AUTHELIA_DB_PASSWORD" #the password you set for the database via phpMyAdmin
notifier: #you can only use one of smtp or filesystem. uncomment/comment below as necessary to choose which
    #filename: /config/notification.txt
  disable_startup_check: false 
    #username: [email protected]
    #password: "YOUR_EMAIL_PASSWORD"
    #host: YOUR_SMTP_HOST
    #port: 587
    #sender: [email protected]
    #subject: "[Authelia] {title}"
    #startup_check_address: [email protected]
    #disable_require_tls: false
    #disable_html_emails: false
      #skip_verify: false
      #minimum_version: TLS1.2
these items are important for the functionality of Authelia. Make sure hostnames for redis and mysql match the container names in the compose file, or use an IP

A quick note on SMTP as a notifier. If you use gmail, the notifier block is a lot simpler. Check out the authelia smtp page at the bottom to get that info, or to read up on what the rest of the block does.

Some users have reported issues with the Notification Provider notifier, both when using filesystem and SMTP. If you experience this, comment out the filesystem and filename lines, and change disable_startup_check: to true

Creating your authelia users and passwords

The final thing we need to do is create your user(s) and password(s). In the configuration above, we specified that this will be done via a file, called users_database.yml. This is perfectly fine for a handful of users, say up to 10. If you have more than that, you may want to investigate LDAP, but for now...

  • In the same directory as your configuration.yml, create a users_database.yml file. The contents will take the following form:
    displayname: "username"
    password: "a long hashed password"
    email: #optional
    groups: #optional
      - a group name
    displayname: "anotheruser"
    password: "another long hashed password"
  • To create the hashed password, we need to SSH into our machine and use the command line, where we copy and paste the following command for each user who needs a password:
docker run authelia/authelia:latest authelia hash-password 'yourpassword'
replace 'yourpassword` with a password
  • This will do a one-time run of the container, which will hash your password
  • You'll get an output on the next line of the password hash. For instance, if you kept the defaults as above, and used a password of 'authelia', you would type in:
docker run authelia/authelia:latest authelia hash-password authelia

and your resulting hash would be

you can read up more on hashed password algorithm tuning here and here if you're so inclined
  • Copy your whole password hash string and paste it in between the " marks for your user's password. So a user called authelia, who uses a password authelia, would have the following entry in the users_database.yml
    displayname: "authelia"
    password: "$argon2id$v=19$m=65536,t=1,p=8$dnBiQ2NLdTB6d2hMakMvOA$Uk9qK8U9EFjYmfKMoAYhTvzM/oTbh+Ht5mev96TqvOo"
our full user setup

Authelia should now be fully configured and ready to use - you can now restart the container. When the container is running, you should be able to access your authelia front page by typing http://yourNASip:9091 into your browser, and see this:

When you type in your username authelia and password authelia, if it's all working, it will simply reload this screen. Congratulations!

There's one final step to protecting your radarr (and/or other) container with it.

Modifying the proxy-conf in SWAG to use Authelia

If you're using auto proxy, this is easy. Where you've got your swag=enable label, you simply add another, swag_auth=authelia so the labels part of your compose will look like:

      - swag=enable
      - swag_auth=authelia

You can even bypass certain subfolders in your URI such as /api and /anotherSubfolderby adding a third label:

      - swag=enable
      - swag_auth=authelia
      - swag_auth_bypass=/api,/anotherSubfolder

If however you don't use the auto-proxy or the container in question doesn't have a proxy.conf template, you'll need to do the below.

Let's head back to our SWAG directory, and the nginx folder. You'll notice that there are two files, called authelia-location.conf and authelia-server.conf. If you have kept things as above, you shouldn't need to change anything in these files, however I bring them up so you understand what is referenced in the next steps.

  • Locate your radarr.subdomain.conf file inside the nginx>proxy-confs directory
  • Inside the first server block, locate the lines # enable for Authelia and #include /config/nginx/authelia-server.conf;
  • Uncomment (remove the #) the line include /config/nginx/authelia-server.conf;
  • Inside the first location block, locate the similar lines # enable for Authelia and #include /config/nginx/authelia-location.conf;
  • Uncomment the line #include /config/nginx/authelia-location.conf;
  • Save the file and restart the SWAG container
  • Now when you access you should see a the same authelia login screen as above
  • Type in your username and password, and you will be sent through to your radarr gui

Happy authenticating!

Related Article

Setting up your docker socket proxy
Protect your docker information from intrusion by using a proxy socket to ensure your docker.sock isn’t exposed to the internet
Portainer - Easy Container Management for Docker
A step-by-step docker walkthrough to installing and configuring Portainer, your one-stop container-management resource
Local DNS to serve your apps via URL instead of IP
Tired of remembering a raft of port numbers to access your service GUIs? Here’s a way to access them all using easier-to-remember URLs


With very limited knowledge, PTS fell down the selfhosted rabbit hole after buying his first NAS in October 2020. You can find him on the Synology discord server (click the icon below)

Have some feedback or something to add? Comments are welcome!

Please note comments should be respectful, and may be moderated