In this video, I’m setting up Authelia. It’s a very lightweight authentication service, which can be used to provide authentication to services which don’t natively support any form of authentication. I think this is a great choice for small scale homelab environments, as it’s simple to run and administer.

Contents

Video

Thumbnail

Authelia

I installed Authelia on an LXC container (Debian 12), and set it up with a dns name / AAAA record in public dns, and all the jazz required for normal HTTPS access. And of course did updates (apt update && apt full-upgrade -y) before starting.

Base Install

Now, we are going to install Auehtlia from their apt repository to make updates smooth in the future. The Debian repos tend to lag behind.

#Install required software for the apt repository
apt update
apt install -y apt-transport-https curl gnupg
#Download their signing key, add it with gpg / apt-key
curl https://apt.authelia.com/organization/signing.asc | apt-key add -
#Add their repo to sources.list.d
echo "deb https://apt.authelia.com/stable/debian/debian/ all main" > /etc/apt/sources.list.d/authelia-stable-debian.list
#Install authelia
apt update
apt install -y authelia

If you want to run with high availability (since authentication is critical), follow the guide here from authelia. In particular, you will need to setup the required services (Redis and Postgres) in HA themselves. I am not doing an HA setup, so I am using local databases (SQLite) for simplicity.

Allow Low-Numbered Ports

To get traffic to Authelia (port 9091) from the real TLS port (443), I found it is easiest to just port forward than to modify the service to add the appropriate capabilities. So, I wrote a port-forward service (/etc/systemd/system/authportfwd.service):

[Unit]
Description=Authelia Port Forwarding Service
After=network.target

[Service]
Type=oneshot
#Of course you can delete the iptabes if you are in the modern era exclusively
ExecStartPost=iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-ports 9091
ExecStopPre=iptables -t nat -D PREROUTING -p tcp --dport 443 -j REDIRECT --to-ports 9091
ExecStartPost=ip6tables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-ports 9091
ExecStopPre=ip6tables -t nat -D PREROUTING -p tcp --dport 443 -j REDIRECT --to-ports 9091
ExecStart=/bin/true

[Install]
WantedBy=multi-user.target

Of course, we also need to make sure iptables is installed, then we can enable the service:

#Install iptables
apt install iptables
#Enable it
systemctl daemon-reload
systemctl enable --now authportfwd

Configuration

Now we need to write our configuration.yml. It’s stored in /etc/authelia/configuration.yml. The package should have installed a default, so now we just need to modify it. The Getting Started Guide has great tips here. I configured it to use TLS with the default Certbot configuration, see below for Certbot itself.

Here’s what I used (this is a diff):

--- /etc/authelia/configuration.yml.default     2024-05-27 15:27:17.203817464 +0000
+++ /etc/authelia/configuration.yml     2024-05-27 21:42:31.879622715 +0000
@@ -21,7 +21,8 @@
 # certificates_directory: '/config/certificates/'
 
 ## The theme to display: light, dark, grey, auto.
-# theme: 'light'
+#All hail dark mode
+theme: 'dark'
 
 ## Set the default 2FA method for new users and for when a user has a preferred method configured that has been
 ## disabled. This setting must be a method that is enabled.
@@ -31,7 +32,7 @@
 ##
 ## Server Configuration
 ##
-# server:
+server:
   ## The address for the Main server to listen on in the address common syntax.
   ## Formats:
   ##  - [<scheme>://]<hostname>[:<port>][/<path>]
@@ -50,12 +53,12 @@
   # disable_healthcheck: false
 
   ## Authelia by default doesn't accept TLS communication on the server port. This section overrides this behaviour.
-  # tls:
+  tls:
     ## The path to the DER base64/PEM format private key.
-    # key: ''
+    key: '/etc/letsencrypt/live/auth.apalrd.net/privkey.pem'
 
     ## The path to the DER base64/PEM format public certificate.
-    # certificate: ''
+    certificate: '/etc/letsencrypt/live/auth.apalrd.net/fullchain.pem'
 
     ## The list of certificates for client authentication.
     # client_certificates: []
@@ -94,7 +97,7 @@
 
   ## Server Endpoints configuration.
   ## This section is considered advanced and it SHOULD NOT be configured unless you've read the relevant documentation.
-  # endpoints:
+  endpoints:
     ## Enables the pprof endpoint.
     # enable_pprof: false
 
@@ -102,10 +105,10 @@
     # enable_expvars: false
 
     ## Configure the authz endpoints.
-    # authz:
-      # forward-auth:
-        # implementation: 'ForwardAuth'
-        # authn_strategies: []
+    authz:
+      forward-auth:
+        implementation: 'ForwardAuth'
+        authn_strategies: []
       # ext-authz:
         # implementation: 'ExtAuthz'
         # authn_strategies: []
@@ -183,7 +186,7 @@
   disable: false
 
   ## The issuer name displayed in the Authenticator application of your choice.
-  # issuer: 'authelia.com'
+  issuer: 'apalrd.net'
 
   ## The TOTP algorithm to use.
   ## It is CRITICAL you read the documentation before changing this option:
@@ -274,7 +277,7 @@
     # jwt_algorithm: 'HS256'
 
     ## The secret key used to sign and verify the JWT.
-    jwt_secret: 'a_very_important_secret'
+    jwt_secret: 'NearbyOverhangParadoxSulphuric'
 
   ## Elevated Session flows. Adjusts the flow which require elevated sessions for example managing credentials, adding,
   ## removing, etc.
@@ -506,8 +509,8 @@
   ##
   ## Important: Kubernetes (or HA) users must read https://www.authelia.com/t/statelessness
   ##
-  # file:
-    # path: '/config/users_database.yml'
+  file:
+    path: '/etc/authelia/users_database.yml'
     # watch: false
     # search:
       # email: false
@@ -621,7 +624,9 @@
   ## Default policy can either be 'bypass', 'one_factor', 'two_factor' or 'deny'. It is the policy applied to any
   ## resource if there is no policy to be applied to the user.
   default_policy: 'deny'
-
+  rules:
+    - domain: '*.apalrd.net'
+      policy: 'one_factor'
   # networks:
     # - name: 'internal'
     #   networks:
@@ -718,14 +723,14 @@
 
   ## Cookies configures the list of allowed cookie domains for sessions to be created on.
   ## Undefined values will default to the values below.
-  # cookies:
-  #   -
+  cookies:
+    -
       ## The name of the session cookie.
-      # name: 'authelia_session'
+      name: 'authelia_session'
 
       ## The domain to protect.
       ## Note: the Authelia portal must also be in that domain.
-      # domain: 'example.com'
+      domain: 'apalrd.net'
 
       ## Required. The fully qualified URI of the portal to redirect users to on proxies that support redirections.
       ## Rules:
@@ -733,7 +738,7 @@
       ##   - The above 'domain' option MUST either:
       ##      - Match the host portion of this URI.
       ##      - Match the suffix of the host portion when prefixed with '.'.
-      # authelia_url: 'https://auth.example.com'
+      authelia_url: 'https://auth.apalrd.net'
 
       ## Optional. The fully qualified URI used as the redirection location if the portal is accessed directly. Not
       ## configuring this option disables the automatic redirection behaviour.
@@ -881,9 +886,9 @@
 ##
 ## This mechanism prevents attackers from brute forcing the first factor. It bans the user if too many attempts are made
 ## in a short period of time.
-# regulation:
+regulation:
   ## The number of failed login attempts before user is banned. Set it to 0 to disable regulation.
-  # max_retries: 3
+  max_retries: 3
 
   ## The time range during which the user can attempt login before being banned in the duration common syntax. The user
   ## is banned if the authentication failed 'max_retries' times in a 'find_time' seconds window.
@@ -896,11 +901,11 @@
 ## Storage Provider Configuration
 ##
 ## The available providers are: `local`, `mysql`, `postgres`. You must use one and only one of these providers.
-# storage:
+storage:
   ## The encryption key that is used to encrypt sensitive information in the database. Must be a string with a minimum
   ## length of 20. Please see the docs if you configure this with an undesirable key and need to change it, you MUST use
   ## the CLI to change this in the database if you want to change it from a previously configured value.
-  # encryption_key: 'you_must_generate_a_random_string_of_more_than_twenty_chars_and_configure_this'
+  encryption_key: 'MoviePassingUntitledBacteriaStapleMatriarchAftermathChubby'
 
   ##
   ## Local (Storage Provider)
@@ -910,9 +915,9 @@
   ##
   ## Important: Kubernetes (or HA) users must read https://www.authelia.com/t/statelessness
   ##
-  # local:
+  local:
     ## Path to the SQLite3 Database.
-    # path: '/config/db.sqlite3'
+    path: '/etc/authelia/db.sqlite3'
 
   ##
   ## MySQL / MariaDB (Storage Provider)
@@ -1064,34 +1069,34 @@
   ##        (only works for unauthenticated connections)
   ##   - validate the SMTP server x509 certificate during the TLS handshake against the hosts trusted certificates
   ##     (configure in tls section)
-  # smtp:
+  smtp:
     ## The address of the SMTP server to connect to in the address common syntax.
-    # address: 'smtp://127.0.0.1:25'
+    address: 'smtp://YourMailProvider:587'
 
     ## The connection timeout in the duration common syntax.
     # timeout: '5 seconds'
 
     ## The username used for SMTP authentication.
-    # username: 'test'
+    username: 'adventure@apalrd.net'
 
     ## The password used for SMTP authentication.
     ## Can also be set using a secret: https://www.authelia.com/c/secrets
-    # password: 'password'
+    password: 'SuperSecret'
 
     ## The sender is used to is used for the MAIL FROM command and the FROM header.
     ## If this is not defined and the username is an email, we use the username as this value. This can either be just
     ## an email address or the RFC5322 'Name <email address>' format.
-    # sender: 'Authelia <admin@example.com>'
+    sender: 'Authelia <adventure@apalrd.net>'
 
     ## HELO/EHLO Identifier. Some SMTP Servers may reject the default of localhost.
-    # identifier: 'localhost'
+    identifier: 'auth.apalrd.net'
 
     ## Subject configuration of the emails sent. {title} is replaced by the text from the notifier.
     # subject: '[Authelia] {title}'
 
     ## This address is used during the startup check to verify the email configuration is correct.
     ## It's not important what it is except if your email server only allows local delivery.
-    # startup_check_address: 'test@authelia.com'
+    startup_check_address: 'adventure@apalrd.net'
 
     ## By default we require some form of TLS. This disables this check though is not advised.
     # disable_require_tls: false

Since it’s a diff and the file is absolutely massive, I suggest you first copy my diff into a file (say diff.patch), edit the things which are relevant to you, and then apply it with patch /etc/authelia/configuration.yml < diff.patch. You might need to apt install patch.

Initial User File

I’ve created an initial users file (/etc/authelia/users_database.yml), by taking my username and hashing a password. Here’s the file, and how to hash your own password. Of course, if you have SMTP configured, you can let users change their own passwords later. Delete the original and recreate.

users:
  apalrd:
    disabled: false
    displayname: 'apalrd'
    password: '$argon2id$v=19$m=65536,t=3,p=4$6D0CA3wVZ7AwvLG6VM7L3w$PqbNjQPhCxD9VoWz2hb+XBKcTOCC1KRb46FRNjg6l6I'
    #This corresponds to CorrectHorseBatteryStaple
    email: 'adventure@apalrd.net'
    groups:
      - 'admins'
  karen:
    disabled: false
    displayname: 'karen'
    password: '$argon2id$v=19$m=65536,t=3,p=4$Gb28FoQveOUloo8zpWWYgg$Kb3kJJU9mMznSIM2nDDVtuBvhiwF+SdQwoqoF3v80Rg'
    #This corresponds to karen

And to generate your own password, run:

authelia crypto hash generate argon2
#It will prompt you for a password

TLS Certificate

We need a TLS cert for Authelia. Authelia is more than capable of handling TLS on its own (without a reverse proxy in front of it), but it’s not capable of doing ACME protocol cert renewal, so I’m setting up Certbot to do it for us. We aren’t going to use port 80 for Authelia, so Certbot can have it.

# Install certbot
apt update
apt install certbot -y
#Rewnew the first time manually, this will configure renewal in the future, and restart Authelia when it does renew
certbot certonly --standalone -d auth.apalrd.net --deploy-hook "/usr/bin/systemctl restart authelia"
#Answer the questions, it will be automatic in the future

Testing

#Enable the services now
systemctl enable --now authelia
#Certbot is automatic

You should be able to navitate to your auth site, and it should let you login at this point.

Protected Service Example

Here I’m going to setup a service to be protected by Authelia, using Caddy as my reverse proxy of choice.

Caddy

I’m installing Caddy directly on the LXC container that runs the service (Frigate in this case). However, there’s nothing stopping you from adding this to the same Caddyfile / Caddy instance you used earlier (don’t duplicate the global section at the top, of course).

Here’s the Caddyfile I am using with Frigate:

# The Caddyfile is an easy way to configure your Caddy web server.

# Global section for automatic TLS via Let's Encrypt (requires an email)
{
        email "adventure@apalrd.net"
}

# Frigate server
corona.apalrd.net {
        #Authenticate via Authelia
        forward_auth https://auth.apalrd.net {
                uri /api/authz/forward-auth
                copy_headers Remote-User Remote-Groups Remote-Email Remote-Name
                #Only include this if you are using a self-signed or staging cert at Authelia
                #transport http {
                        #tls_insecure_skip_verify
                #}
        }
        #Reverse proxy to localhost (Frigate only binds to v4 sockets)
        reverse_proxy [127.0.0.1]:5000
}

If you want to restrict access to the /config endpoint to users in the admins group, you can use the following bit of yaml in your Authelia config to filter on that URL. Remember that rules are processed in order! If you add a default-allow rule on your domain like I did above, then it will all ow everyone anyway, so delete that one and make more specific rules now that you know what you are doing.

  rules:
    # Allow admins with two factor auth to edit configs
    - domain: 'corona.apalrd.net'
      policy: 'two_factor'
      subject:
       - 'group:admins'
      resources:
       - '^/config([/?].*)?$'
    # Catch anyone else trying to get to config and deny them
    - domain: 'corona.apalrd.net'
      policy: 'deny'
      resources:
       - '^/config([/?].*)?$'
    # Catch any other resources on this domain and require one factor
    - domain: 'corona.apalrd.net'
      policy: 'one_factor'

I also found in this specific case that the javascript frontend rewrites the URL to /config instead of requesting that page, so it will initially load, but changing the configuration (the api endpoints) will still fail.