

You may also want to consider a hardened single sign-on solution, as that can enable 2FA for all your services, even those that don’t have them built-in. I use Authentik.


You may also want to consider a hardened single sign-on solution, as that can enable 2FA for all your services, even those that don’t have them built-in. I use Authentik.
authentik.pod
[Pod]
PodName=authentik
PublishPort=9000:9000
PublishPort=9443:9443
PublishPort=3389:3389
PublishPort=6636:6636
authenik_db.container
[Unit]
Description=authentik_db
Wants=network-online.target
After=network-online.target
[Service]
Restart=always
[Container]
EnvironmentFile=.env
Pod=authentik.pod
ContainerName=authentik_db
Image=docker.io/library/postgres:17-alpine
AutoUpdate=registry
Volume=authentik_db.volume:/var/lib/postgresql/data:Z
Environment=POSTGRES_USER=authentik
Environment=POSTGRES_DB=authentik
[Install]
WantedBy=default.target
authentik_server.container
[Unit]
Description=authentik_server
Wants=network-online.target
After=network-online.target
[Service]
Restart=always
[Container]
EnvironmentFile=.env
Pod=authentik.pod
ContainerName=authentik_server
Image=ghcr.io/goauthentik/server:2026.5
Exec=server
AutoUpdate=registry
Environment=AUTHENTIK_POSTGRESQL__HOST=authentik_db
Environment=AUTHENTIK_POSTGRESQL__USER=authentik
Environment=AUTHENTIK_POSTGRESQL__NAME=authentik
Volume=authentik_media.volume:/data/media:U,Z
Volume=authentik_data.volume:/data:U,Z
Volume=authentik_templates.volume:/templates:U,Z
[Install]
WantedBy=default.target
authentik_worker.container
[Unit]
Description=authentik_worker
Wants=network-online.target
After=network-online.target
[Service]
Restart=always
[Container]
EnvironmentFile=.env
Pod=authentik.pod
ContainerName=authentik_worker
Image=ghcr.io/goauthentik/server:2026.5
Exec=worker
AutoUpdate=registry
Environment=AUTHENTIK_POSTGRESQL__HOST=authentik_db
Environment=AUTHENTIK_POSTGRESQL__USER=authentik
Environment=AUTHENTIK_POSTGRESQL__NAME=authentik
Environment=AUTHENTIK_LISTEN__HTTP=[::]:9001
Environment=AUTHENTIK_LISTEN__METRICS=[::]:9301
Volume=authentik_media.volume:/data/media:U,Z
Volume=authentik_data.volume:/data:U,Z
Volume=authentik_templates.volume:/templates:U,Z
Volume=authentik_certs.volume:/certs:U,Z
Volume=/run/user/1000/podman/podman.sock:/var/run/docker.sock:z
[Install]
WantedBy=default.target
authentik_ldap.container
[Unit]
Description=authentik_ldap
Wants=network-online.target
After=network-online.target
[Service]
Restart=always
[Container]
Pod=authentik.pod
ContainerName=authentik_ldap
Image=ghcr.io/goauthentik/ldap:2026.5
AutoUpdate=registry
Environment=AUTHENTIK_HOST=https://authentik.mydomain.com/
Environment=AUTHENTIK_INSECURE="false"
Environment=AUTHENTIK_TOKEN=wowthisisquitethelongandsafetokenthatnoonewilleverhack
[Install]
WantedBy=default.target
````___`
I use authentik. It’s probably fairly easy to set up if you use their docker-compose, but I run it as rootless podman, which took a little work to get it converted to a quadlet pod. But now that it’s set up, it works great and handles a variety of self-hosted apps that use saml, oidc, ldap, and forward-auth. It’s one of the few options that handles all the different authentication types natively. I also set up passkeys and standard two-factor time codes.
There are some very helpful authentik youtube tutorials by Cooptonian.
i run it on opnsense. When my services were on individual subdomains each with their own certificate, they got hit a lot and crowdsec blocked lots of bots and scripts
I ultimately moved all my services to a wildcard sub-subdomain, and poof all the bots went away and now crowdsec doesn’t do much other than block port scanners which the firewall does anyway.
it’s not worth the hassle to uninstall though.
Self-Hoster 🏡