Does anyone have some experience working with Authelia on Nixos, specifically with Nginx? I have been playing around with it a bit and got something working, configs below. This is based on the following:
https://matwick.ca/authelia-nginx-sso/
I welcome any suggestions or corrections on how to improve this, as by no means do I know what I am doing.
There is one thing I would like to improve that I can’t seem to figure it out, making adding Authelia authorization to a site simpler. That is not having to copy so many extraConfig to each virtual hosts. Is there a way to create the equivalent of a snippet for the nix config. That is, define all the text to be included in the extraConfig once and then be able to add it to any virtual hosts in one or two lines?
Thank you
# /etc/nixos/nginx.nix
{config, pkgs, ...}:
{
# Setup ACME
security.acme = {
acceptTerms = true;
defaults = {
email = "admin@example.com";
dnsProvider = "dynu";
credentialsFile = "${pkgs.writeText "dynu-creds" ''
DYNU_API_KEY=supersecretkey
''}";
};
};
# Open Port in Firewall
networking.firewall.allowedTCPPorts = [ 80 443 ];
# Enable Nginx and set bassic settigns
services.nginx = {
enable = true;
# Use recommended settings
recommendedGzipSettings = true;
recommendedOptimisation = true;
recommendedProxySettings = true;
recommendedTlsSettings = true;
# Only allow PFS-enabled ciphers with AES256
# sslCiphers = "AES256+EECDH:AES256+EDH:!aNULL";
commonHttpConfig = ''
# Add HSTS header with preloading to HTTPS requests.
# Adding this header to HTTP requests is discouraged
map $scheme $hsts_header {
https "max-age=31536000; includeSubdomains; preload";
}
add_header Strict-Transport-Security $hsts_header;
'';
};
# base Virtual Host
services.nginx.virtualHosts."example.com" = {
enableACME = true;
forceSSL = true;
acmeRoot = null;
};
}
# /etc/nixos/authelia.nix
{ config, pkgs, ... }:
{
services.authelia.instances.main = {
enable = true;
secrets = {
jwtSecretFile = "${pkgs.writeText "jwtSecretFile" "supersecretkey"}";
storageEncryptionKeyFile = "${pkgs.writeText "storageEncryptionKeyFile" "supersecretkey"}";
sessionSecretFile = "${pkgs.writeText "sessionSecretFile" "supersecretkey"}";
};
settings = {
theme = "dark";
default_redirection_url = "https://example.com";
server = {
host = "127.0.0.1";
port = 9091;
};
log = {
level = "debug";
format = "text";
};
authentication_backend = {
file = {
path = "/var/lib/authelia-main/users_database.yml";
};
};
access_control = {
default_policy = "deny";
rules = [
{
domain = ["auth.example.com"];
policy = "bypass";
}
{
domain = ["*.example.com"];
policy = "one_factor";
}
];
};
session = {
name = "authelia_session";
expiration = "12h";
inactivity = "45m";
remember_me_duration = "1M";
domain = "example.com";
redis.host = "/run/redis-authelia-main/redis.sock";
};
regulation = {
max_retries = 3;
find_time = "5m";
ban_time = "15m";
};
storage = {
local = {
path = "/var/lib/authelia-main/db.sqlite3";
};
};
notifier = {
disable_startup_check = false;
filesystem = {
filename = "/var/lib/authelia-main/notification.txt";
};
};
};
};
services.redis.servers.authelia-main = {
enable = true;
user = "authelia-main";
port = 0;
unixSocket = "/run/redis-authelia-main/redis.sock";
unixSocketPerm = 600;
};
services.nginx.virtualHosts."auth.example.com" = {
enableACME = true;
forceSSL = true;
acmeRoot = null;
locations."/" = {
proxyPass = "http://127.0.0.1:9091";
proxyWebsockets = true;
};
};
}
# /etc/nixos/test.nix
{ config, pkgs, ... }:
{
services.nginx.virtualHosts."test.example.com" = {
enableACME = true;
forceSSL = true;
acmeRoot = null;
extraConfig = ''
# 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;
}
'';
locations."/" = {
root = "/var/www/test/";
index = "index.html";
extraConfig = ''
# 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;
'';
};
};
}