What you will set up
authentik is an identity provider: it holds your users, their passwords and their second factors, and your apps let authentik check who is logging in. Each person has one account for everything, and when someone leaves, you turn off one account instead of one in every app. Apps connect to it with OpenID Connect, SAML or LDAP, which most self-hosted apps support.
Here it runs in a pod with PostgreSQL, under a user of its own called authentik, behind Caddy from the Podman guide. As an example, it becomes the login for the Matrix server from the Matrix guide.
Every step below was run on a Melonslab server with Debian 13:
- The first setup was done through Caddy, and authentik's event log showed each visitor's real address.
- A user created in the admin interface logged in to Matrix with single sign-on, and got a Matrix account with their name. An existing Matrix account was linked the same way.
- With an authenticator app set up, logging in asked for a code, and a wrong code was refused.
- An uploaded file was still there after a restart, and everything came back by itself after a reboot.
authentik used about 660 MB of memory. It needs at least 2 GB on the server.
Before you start
You need:
- a server set up as in the Podman guide, with Caddy running, and at least 2 GB of memory;
- an A record and an AAAA record for
auth.example.compointing at your server.
The examples use auth.example.com for authentik and 203.0.113.10 for your server's IPv4 address, which ip -brief address show eth0 shows. Replace them throughout.
1. Create the user
As root:
useradd -m -s /bin/bash authentik
loginctl enable-linger authentik
machinectl shell authentik@
Everything up to step 5 runs as authentik.
2. Create the secrets
openssl rand -hex 24 | tr -d '\n' | podman secret create authentik-db-password -
openssl rand -base64 60 | tr -d '\n' | podman secret create authentik-secret-key -
The first is the database password. The second is authentik's secret key, which signs its sessions and tokens. Neither is written into the files below.
3. Describe the pod
mkdir -p ~/.config/containers/systemd ~/authentik/data
podman unshare chown 1000:1000 ~/authentik/data
authentik runs as user 1000 inside its containers, and the chown lets that user write to the data folder, where authentik keeps files you upload, such as app icons.
Create ~/.config/containers/systemd/authentik.pod:
[Pod]
PodName=authentik
# Only Caddy, on this server, can reach authentik: the port is not open to the internet.
PublishPort=127.0.0.1:8092:9000
ShmSize=512m
[Install]
WantedBy=default.target
Create ~/.config/containers/systemd/authentik-db.container:
[Container]
ContainerName=authentik-db
Image=docker.io/library/postgres:18-alpine
Pod=authentik.pod
Volume=authentik-db:/var/lib/postgresql
Environment=POSTGRES_USER=authentik POSTGRES_DB=authentik
Secret=authentik-db-password,type=env,target=POSTGRES_PASSWORD
AutoUpdate=registry
[Service]
Restart=always
Create ~/.config/containers/systemd/authentik-server.container:
[Unit]
After=authentik-db.service
[Container]
ContainerName=authentik-server
Image=ghcr.io/goauthentik/server:2026.8
Pod=authentik.pod
Exec=server
EnvironmentFile=%h/authentik/authentik.env
Secret=authentik-db-password,type=env,target=AUTHENTIK_POSTGRESQL__PASSWORD
Secret=authentik-secret-key,type=env,target=AUTHENTIK_SECRET_KEY
Volume=%h/authentik/data:/data
AutoUpdate=registry
[Service]
Restart=always
Create ~/.config/containers/systemd/authentik-worker.container:
[Unit]
After=authentik-db.service
[Container]
ContainerName=authentik-worker
Image=ghcr.io/goauthentik/server:2026.8
Pod=authentik.pod
Exec=worker
EnvironmentFile=%h/authentik/authentik.env
# The server already uses these ports in the pod.
Environment=AUTHENTIK_LISTEN__HTTP=[::]:9001 AUTHENTIK_LISTEN__METRICS=[::]:9301
Secret=authentik-db-password,type=env,target=AUTHENTIK_POSTGRESQL__PASSWORD
Secret=authentik-secret-key,type=env,target=AUTHENTIK_SECRET_KEY
Volume=%h/authentik/data:/data
AutoUpdate=registry
[Service]
Restart=always
And ~/authentik/authentik.env, the settings both share:
AUTHENTIK_POSTGRESQL__HOST=127.0.0.1
AUTHENTIK_POSTGRESQL__USER=authentik
AUTHENTIK_POSTGRESQL__NAME=authentik
# Caddy's connections reach the pod from the server's own IPv4 address.
AUTHENTIK_LISTEN__TRUSTED_PROXY_CIDRS=203.0.113.10/32
The server answers web requests, and the worker runs background tasks. Both run the same image. In a pod they share one network, so the worker's two ports are moved away from the server's. authentik trusts the address Caddy sends for each visitor only from the addresses in TRUSTED_PROXY_CIDRS, and with rootless Podman, Caddy's connections come from the server's own IPv4 address.
The tag 2026.8 gets every fix to authentik 2026.8. Step 10 covers moving to the next version.
4. Start it
systemctl --user daemon-reload
systemctl --user start authentik-pod
The first start downloads the images, and then authentik sets up its database, which took about three minutes on our test server. Check it:
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8092/-/health/ready/
It answers 503 while authentik is still starting, and 200 when it is ready. Until then, the worker's log shows warnings about missing tables, which stop by themselves.
5. Put Caddy in front
Go back to root with exit, switch to machinectl shell caddy@, and add this block at the end of ~/Caddyfile:
auth.example.com {
reverse_proxy 127.0.0.1:8092
}
Restart Caddy with systemctl --user restart caddy.
6. Create the admin account
Open https://auth.example.com. authentik shows its first setup page for its admin user, akadmin. Enter your email address and a strong password twice. Base URL is filled in already: check that it is https://auth.example.com, and choose Continue.
Then log in as akadmin, with the password you just set. The admin interface is at https://auth.example.com/if/admin/.
7. Add your users
In the admin interface:
- Open Directory, then Users, and choose New User.
- Choose Internal User, and enter a Username, a Display Name and an Email Address. Choose Create.
- Choose the new user in the list. Under Recovery, choose Set password, enter a password, and choose Set Password.
The person logs in at https://auth.example.com, and can change the password under the gear icon, in User details.
8. Turn on two-factor authentication
Each person does this for their own account, once. At https://auth.example.com, choose the gear icon, then Credentials. Under MFA Devices, choose Enroll and then TOTP Device. Scan the QR code with an authenticator app, such as the one built into your phone's password manager, and enter the code it shows.
From then on, authentik asks for a code from the app after the password. The same menu has WebAuthn device, for passkeys and security keys, and Static tokens, one-time codes to print and keep in case the phone is lost.
9. Connect an app
Each app gets an application and a provider in authentik. Here the app is Matrix: people then log in to Element with their authentik account. In the admin interface:
- Open Applications, then Applications, and choose New Application.
- Enter
Matrixas the Application Name, and choose Next. - Choose OAuth2/OpenID Provider, and Next.
- Set Authorization Flow to default-provider-authorization-implicit-consent, which logs people in without asking them to approve the app each time.
- Copy the Client ID and Client Secret.
- Under Redirect URIs/Origins, choose Add entry, keep Strict, and enter
https://matrix.example.com/_synapse/client/oidc/callback. - Choose Next twice, then Create Application, and Finish.
Without anything under Configure Bindings, every user in authentik can log in to the app. authentik's address for the app is https://auth.example.com/application/o/matrix/, with the name in lower case.
Then, as root, switch to machinectl shell matrix@, and add this to ~/matrix/synapse.yaml, with the ID and secret you copied:
oidc_providers:
- idp_id: authentik
idp_name: authentik
discover: true
issuer: "https://auth.example.com/application/o/matrix/"
client_id: "CLIENT_ID"
client_secret: "CLIENT_SECRET"
scopes: ["openid", "profile", "email"]
allow_existing_users: true
user_mapping_provider:
config:
localpart_template: "{{ user.preferred_username }}"
display_name_template: "{{ user.name }}"
authentik runs on the same server, so Synapse has to reach it through the server rather than inside its own pod, as in the Podman guide. Add this line to ~/.config/containers/systemd/matrix.pod, under PublishPort:
AddHost=auth.example.com:host-gateway
Then restart Matrix:
systemctl --user daemon-reload
systemctl --user restart matrix-pod
Element's login page now has Continue with authentik. A person logging in for the first time gets a Matrix account with their authentik user name, such as @bob:example.com. With allow_existing_users: true, an authentik user with the same name as an existing Matrix account logs in to that account, so turn it on only if the names in authentik belong to the same people as in Matrix.
Other apps follow the same steps, with the redirect address from the app's own documentation. authentik's documentation has a page for many of them.
10. Keep it up to date
As authentik, turn on Podman's daily updates:
systemctl --user enable --now podman-auto-update.timer
That keeps authentik on the newest 2026.8 release, and PostgreSQL on the newest 18. authentik releases a new version every few months, such as 2026.11. Upgrade one version at a time, without skipping any, because authentik cannot go back to an older version: read the release notes, back up as in step 11, change the tag in both authentik-server.container and authentik-worker.container, and run systemctl --user daemon-reload and systemctl --user restart authentik-pod.
11. Back up
As authentik:
mkdir -p ~/backup
podman exec authentik-db pg_dump -U authentik authentik > ~/backup/authentik-db.sql
tar -czf ~/backup/authentik-data.tar.gz -C ~/authentik data
podman secret inspect --showsecret --format '{{.SecretData}}' authentik-secret-key > ~/backup/authentik-secret-key
The database holds the users, their passwords and second factors, and every application. The secret key is needed to restore it. Copy ~/backup to another machine, and keep it private.
Troubleshooting
An app's login fails, and https://auth.example.com/application/o/matrix/.well-known/openid-configuration shows addresses starting with http://. authentik does not trust Caddy. Check that AUTHENTIK_LISTEN__TRUSTED_PROXY_CIDRS in step 3 is your server's IPv4 address, and restart with systemctl --user restart authentik-server.
The first setup page shows Not Found. authentik is still setting itself up. Wait a minute after the health check in step 4 answers 200, and open https://auth.example.com again.
Synapse cannot reach authentik. The AddHost line from step 9 is missing from matrix.pod, or names a different host.