Need some help with Authelia plz

Hi,

I am using nginx via letsencrypt from linuxserver.
I have it all configured and working well with no issues.SSL certificate is generated every 2/3 months or so and I am reverse proxying some URLs.

Now I want to extend the security and I am looking to use Authelia -
https://github.com/clems4ever/authelia

I have the Authelia docker configured and running.
It works together with nginx - but here is where I get lost. I can not figure which parts of the Authelia nginx config goes into which letencrypt nginx .conf files.

Their nginx config doco is here:

https://github.com/clems4ever/authelia/blob/master/docs/proxies/nginx.md

However, I cant figure it out where the various blocks (server, location /, location /auth_verify) in that configuration example) should go in the various letsencrypt nginx .conf files.

Can someone please have a look at the examples above and reply and let me know in which letsencrypt files should the Authelia nginx blocks be added?

Many thanks.

btw - this is not spam :slight_smile:

There are other examples of their nginx blocks:

https://github.com/clems4ever/authelia/issues/178
https://github.com/clems4ever/authelia/issues/364

Yes the above are issues but it does show examples of the nginx blocks used.

Authelia is something I’ve been trying to get around to playing with myself. Happy to donate some time to it and see if we can get it figured out between us. You using LDAP or file based backend? I might need some help to get as far as you before I can help though!

1 Like

Hi,

Thank you for looking at this :slight_smile:

I have an openldap container (osixia/openldap) and an admin gui for it (osixia/phpldapadmin) using it for all sorts of LDAP authentications.
However, I think we can have a simpler start as Authelia now supports a file backend as well as ldap.
So we can start with the file based authetication option before using ldap:

Sorry wont let me link to the config file direct so I cannot post it properly.
Is config.template.yml in the root of github /clems4ever/authelia

Yeah, that’s about where I am with things already and I run the same LDAP backend, although I confess I’ve never actually implemented LDAP into anything production wise.

I’ve got the container up and running, can hit the login page, am using file backend for now. Just playing with it now.

I’ve got authelia sort of working on a subdomain. Still trying to fix stuff so it will allow you to login with your password, but none of the 2FA methods work yet.

Create a subdomain called authelia

Run your authelia container with

docker run \
-d --name='authelia' \
-p '8080:8080/tcp' \
-v '/path/to/config.yml':'/etc/authelia/config.yml':'rw' \
-v '/path/to/users_database.yml':'/etc/authelia/users_database.yml':'rw' \
'clems4ever/authelia'

Then for your authelia subdomain

server {
    listen         80;
    server_name    authelia.*;
    return         301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name authelia.*;
    
    include /config/nginx/ssl.conf;

    # Authelia's API for requests coming from external Nginx servers

    location = /api/verify {
        include /config/nginx/authelia/default_headers;
        # Set original requested Host from X-Forwared-Host.
        # Of course, the external Nginx server protecting his resources
        # must have properly set this header, as configured in this how-to.
        proxy_set_header Host $http_x_forwarded_host;
        resolver 127.0.0.11 valid=30s;
        set $upstream_authelia authelia;
        proxy_pass http://$upstream_authelia:8080;
    }

    # Authelia's frontend

    location /secondfactor/totp/identity/finish {
        # We don't want the user web browser to cache
        # TOTP secrets / QR codes, for security purposes.
        include /config/nginx/authelia/default_headers;
        include /config/nginx/authelia/proxy_params;
        # Pass to Authelia's backend
        resolver 127.0.0.11 valid=30s;
        set $upstream_authelia authelia;
        proxy_pass http://$upstream_authelia:8080;
        proxy_intercept_errors on;
        if ($request_method !~ ^(POST)$){
            error_page 401 = /error/401;
            error_page 403 = /error/403;
            error_page 404 = /error/404;
            }
     }

    location / {
        include /config/nginx/authelia/default_headers;
        include /config/nginx/authelia/proxy_params;
        # Pass to Authelia's backend
        resolver 127.0.0.11 valid=30s;
        set $upstream_authelia authelia;
        proxy_pass http://$upstream_authelia:8080;
        proxy_intercept_errors on;
        if ($request_method !~ ^(POST)$){
            error_page 401 = /error/401;
            error_page 403 = /error/403;
            error_page 404 = /error/404;
            }
    }
     
}

You also need to create a folder in /config/nginx/ in letsencrypt called authelia then recreate in that folder the following files:

default_headers

# Make sure to understand the purpose of each of these HTTP headers.
# Some may be not relevant for your own setup.
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag "noindex, nofollow, nosnippet, noarchive";
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;

proxy_params

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_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_cache_bypass $http_upgrade;

authelia_check-auth_block_internal_api

location = /.check-auth {
    internal;
    proxy_set_header Host $host;
    proxy_set_header X-Original-URI $request_uri;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Content-Length "";
    proxy_pass_request_body off;
    resolver 127.0.0.11 valid=30s;
    set $upstream_authelia authelia;
    proxy_pass http://$upstream_authelia:8080/api/verify;
}

authelia_sso_params

#auth_request /.check-auth;

# Uncomment if needed: it gives the backend server protected by Authelia
# HTTP headers containing the user name and groups of the authenticated user.
# Useful for SSO, for instance.
#
# auth_request_set $user $upstream_http_remote_user;
# auth_request_set $groups $upstream_http_remote_groups;
# proxy_set_header X-Forwarded-User $user;
# proxy_set_header X-Forwarded-Groups $groups;

auth_request_set $redirect $upstream_http_redirect;
error_page 401 =302 https://authelia.server.com?redirect=$redirect;
error_page 403 = https://authelia.server.com/error/403;

(Changing the last two lines to fit your setup)

Then to protect a subdomain, you need to use a config based on this:

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

    server_name CONTAINER.*;

    include /config/nginx/ssl.conf;

    client_max_body_size 0;

    include /config/nginx/authelia/authelia_check-auth_block_internal_api;

    location / {
        include /config/nginx/authelia/default_headers;
        auth_request /.check-auth;
        include /config/nginx/authelia/authelia_sso_params;

        include /config/nginx/proxy.conf;
        resolver 127.0.0.11 valid=30s;
        set $upstream_CONTAINER CONTAINER;
        proxy_pass http://$upstream_CONTAINER:CONTAINER-PORT;
    }
}

Obviously changing CONTAINER & CONTAINER-PORT

Now it’s not working yet, but that’s as far as I managed to get today. Feel free to work out the next bits. Might be a little while until I get to it again.

:+1:

Hi,

Really appreciate your help with this. Also the speed with which you have tackled it :slight_smile:
You have made great progress!!
I will make the changes and create the files as you have suggested and start testing.
Will report back in this thread.

Little bit more progress. This line needs adding in to proxy_params

proxy_set_header X-Forwarded-Host $http_host;

I had a good sessions last night with this - a good 4 hours or so.
In the end I got it working as it should. But my configuration is all over the place in multiple files (in wrong places) etc

chbmb - thank you for puttying me on the right track on how to structure the config within the Letsencrypt environment!!

Tonight I plan to clean it all up and will post the content of the files - atm is only protecting 1 application, no MongoDB (uses the file system for usernames and passwords), no Redis and no Duo yet (working with Google Authenticator only).

After I clean up the config the next step is to get LDAP working and add Duo to it as well.

Pretty much exactly where I am with it. I managed to get TOTP working last night. I’m not sure for a home server whether I actually need Redis and MongoDB though. I already have the same LDAP containers as you set up, but I’ve never really used them.

Two minds are better than one!

Hi,

Here is my working configuration.

Uses DUO as 2FA, OpenLDAP for usernames, passwords and group membership.
No mongodb or redis.

Assume you have linuxserver.io letsencrypt container installed, configured (using subdomains for this example) and issuing certificates.

Assume you have a DUO account (free for 10 users) and users/mobiles already enrolled.

No IPV6 only IPV4.

Authelia, Letsencrypt, Heimdall all installed on the same docker host.

OpenLDAP - create a group called admin and add the users you want/need.

Below is the docker-compose file normally created/found in

/opt/docker-compose.yml

Please adjust the volume paths to suit your own config.
Change the network to your defined network in docker.
Port must be the same as the one you will define in the Authelia config.yml file.

# ----------------------------------------
# Authelia
# ----------------------------------------
authelia:
    image: clems4ever/authelia:latest
    container_name: authelia
    hostname: authelia
    volumes:
        - /docker/containers/authelia/config/config.yml:/etc/authelia/config.yml
        - /docker/containers/authelia/config/store:/var/lib/authelia/store
    environment:
        - NODE_TLS_REJECT_UNAUTHORIZED=0
    networks:
        - nginx
    ports:
        - 9090:9090
    restart: unless-stopped

The /docker/containers/authelia/config/store:/var/lib/authelia/store will hold the databases of registered users, authenticated methods etc.
If is not defined on a persistent volume all data will be lost if Authelia container image is removed and will require all users to register again.

Login to your DUO account and create a new application - use the Partner Auth API template.
Enter the DUO api details in the file below.

This is the Authelia config file (config.yml) - minimal version. Adjust for your config.

###############################################################
#                   Authelia configuration                                                                    #
###############################################################

port: 9090

logs_level: debug

duo_api:
  hostname: xxxxxxxxxxxxxxxxxxxxxxxxxx
  integration_key: xxxxxxxxxxxxxxxxxxxxxxx
  secret_key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  ldap:
    url: ldap://ldap.example.com
    base_dn: dc=example,dc=com
    additional_users_dn: cn=users
    users_filter: uid={0}
    additional_groups_dn: ou=groups
    groups_filter: (&(memberuid={0})(objectclass=posixGroup))
    group_name_attribute: cn
    mail_attribute: mail
    user: cn=xxxxxxxx,dc=example,dc=com
    password: xxxxxxxxxxxxxxxx

access_control:
  default_policy: deny
  rules:
    - domain: '*.example.com'
      subject: 'group:admin'   #same group as you created in OpenLDAP
      policy: two_factor

session:
  name: XXXXXXXXXXXXXX_authelia_session_idXXXXXXXXXXXXXXXX #this needs to have the same in the cookie in `authelia_sso_params`
  secret: XXXXXXXXXXXX_top_secret_XXXXXXXXXXXX
  expiration: 3600000 # 1 hour
  inactivity: 300000 # 5 minutes
  domain: example.com

regulation:
  max_retries: 3
  find_time: 120
  ban_time: 300

storage:
   local:
    path: /var/lib/authelia/store

  smtp:
    username: test
    password: password
    secure: XXXX   #true or false
    host: your mail server ip here
    port: your mail server port here
    sender: authelia@example.com

In /config/nginx/ in letsencrypt create a new folder called authelia
Inside this folder create the following files and content in each file (modify per your requirements)

proxy_params

proxy_set_header X-Forwarded-Host $host;
proxy_set_header Host $http_x_forwarded_host;
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_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_cache_bypass $http_upgrade;

default_headers

add_header Cache-Control "no-store";
add_header Pragma "no-cache";
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag "noindex, nofollow, nosnippet, noarchive";
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;

authelia_sso_params - remeber to specify same cookie name as in the session section in Authelia’s config.yml (authelia.session.id is the default)

auth_request /.check-auth;
auth_request_set $target_url $scheme://$http_host$request_uri;
error_page 401 =302 https://authelia.example.com/#/?rd=$target_url;
set $new_cookie $http_cookie;
if ($http_cookie ~ "(.*)(?:^|;)\s*authelia\.session\.id=[^;]+(.*)") {
    set $new_cookie $1$2;
}
proxy_set_header Cookie $new_cookie;

authelia_check-auth_block_internal_api

location = /.check-auth {
    internal;
    proxy_set_header Host $host;
    proxy_set_header X-Original-URI $request_uri;
    proxy_set_header X-Original-URL $scheme://$host$request_uri;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Content-Length "";
    proxy_pass_request_body off;
    resolver 127.0.0.11 valid=30s;
    set $upstream_authelia authelia;
    proxy_pass http://$upstream_authelia:9090/api/verify;
}

authelia_check-auth_block_external_api

location = /.check-auth {
    internal;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Original-URI $request_uri;
    proxy_set_header X-Original-URL $scheme://$host$request_uri;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Content-Length "";
    proxy_pass_request_body off;
    resolver 127.0.0.11 valid=30s;
    set $upstream_authelia authelia;
    proxy_pass http://$upstream_authelia:9090/api/verify;
}

(I know the above 2 files are identical but thats how I got it to work)

Next Authelia itself needs a subdomain definition. In /config/nginx/proxy-confs create the file below:

authelia.subdomain.conf

server {
    listen 80;
    server_name authelia.example.com;

    location / {
        include /config/nginx/authelia/default_headers;
        return 301 https://$server_name$request_uri;
    }
}

server {
    listen 443 ssl http2;
    server_name authelia.*;
    include /config/nginx/ssl.conf;

    location = /api/verify {
        include /config/nginx/authelia/default_headers;
        include /config/nginx/authelia/proxy_params;
        resolver 127.0.0.11 valid=30s;
        set $upstream_authelia authelia;
        proxy_pass http://$upstream_authelia:9090/api/verify;
    }

    location /secondfactor/totp/identity/finish {
        include /config/nginx/authelia/default_headers;
        include /config/nginx/authelia/proxy_params;
        resolver 127.0.0.11 valid=30s;
        set $upstream_authelia authelia;
        proxy_pass http://$upstream_authelia:9090;
        proxy_intercept_errors on;
        if ($request_method !~ ^(POST)$){
            error_page 401 = /error/401;
            error_page 403 = /error/403;
            error_page 404 = /error/404;
        }
    }

    location / {
        include /config/nginx/authelia/default_headers;
        include /config/nginx/authelia/proxy_params;
        resolver 127.0.0.11 valid=30s;
        set $upstream_authelia authelia;
        proxy_pass http://$upstream_authelia:9090;
        proxy_intercept_errors on;
        if ($request_method !~ ^(POST)$){
            error_page 401 = /error/401;
            error_page 403 = /error/403;
            error_page 404 = /error/404;
        }
    }
}

And finally lets assume you want to protect your heimdall page.
In /config/nginx/proxy-confs create the heimdall subdomain cofig file:

heimdall.subdomain.conf

# make sure that your dns has a cname set for heimdall
server {
    listen 80;
    server_name heimdall.*;

    location / {
        include authelia/default_headers;
        return 301 https://$server_name$request_uri;
    }
}

server {
    listen 443 ssl http2;
    
    root /config/www;
    index index.html index.htm index.php;

    server_name heimdall.*;

    include /config/nginx/ssl.conf;

    include /config/nginx/authelia/authelia_check-auth_block_internal_api;

    location / {
        include /config/nginx/authelia/default_headers;
        include /config/nginx/authelia/authelia_sso_params;
        include /config/nginx/authelia/proxy_params;
        resolver 127.0.0.11 valid=30s;
        set $upstream_heimdall heimdall;
        proxy_pass https://$upstream_heimdall:443;
        proxy_redirect off;
    }
}

Navigate to your Authelia webpage (https://authelia.example.com) and enroll your first user.
Then go to your heimdall page (https://heimdall.example.com) and login.

To protect additional pages follow the heimdall example and adjust accordingly.

Hope this helps someone.

Thanks to chbmb for helping with how to include Authelia config into the letsencrypt/nginx application structure/configuration.

Thanks, saved me writing that up and documenting it! I’m going to take some time to write this up as a blog post as well. As long as you don’t have any objections @MnM?

I’d just got home and was setting up OpenLDAP when your reply came in, although I’d got it all working with file based backend.

Hi - yes please go for it and make into a blog I have no objection to it.
I am sure it will help a few ppl.

I have seen some ppl asking about this in the Unraid forum so it might even be worthwhile making it into a template (sorry cant help with that as I dont run Unraid).

I have a policy of not making templates for docker containers we have no ability to control as I don’t think they can be adequately supported, so I’ll probably keep it generic docker.

Hi @chbmb

Do you ever get that blog posted? I’m trying to do the same thing you guys are discussing here. I’m trying to protect a portion of my bitwarden server with 2FA.

@kevdog Nah, it’s on my list of things to do…

Unfortunately I had to do a lot of overtime for work, then wife had baby, start new job next week, so never really got a chance to get it up and running again.

Looked at it briefly, but the V3 to V4 upgrade broke my config, so going to start from scratch at some point.

If you’re self hosting bitwarden, you can turn on the 2FA settings regardless. I use bitwarden_rs

Yea I’m self host bitwarden_rs. I only found out about the 2FA in bitwarden after getting the authelia stuff all up and running (DOH!)

I managed to get the authelia frontend all setup with docker-compose, mariadb, redis, and authelia containers with an external nginx reverse proxy. Probably a lot of work for little gain but I did learn a lot about docker, docker compose in the process which was actually kind of fun. I’m in the process of trying to write up things in a blog somewhere (yea somewhere is a kind of a problem for sure!). My end solution however was different from what you posted above. I originally found this thread and it was very well documented but for whatever reason I couldn’t make it work. The guys over at authelia were actually really really responsive in walking me through some of the problems (particularly with the duo activation and setting up the user database). Hopefully I’ll post the writeup soon.