 | tech_notesA collection of notes on setups and implementations.
|
|
Log | Files | Refs | README |
commit 715e4894982c7f06e7fcb525db74bb43cf1ad57c
parent 388dc48a1d8fb7e10b30a0e7d2a578737ee178ab
Author: Julian Piribauer <julian.piribauer@gmail.com>
Date: Sat, 2 May 2026 07:18:58 +0000
Add Authentik setup note
Diffstat:
| A | authentik.md | | | 191 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
1 file changed, 191 insertions(+), 0 deletions(-)
diff --git a/authentik.md b/authentik.md
@@ -0,0 +1,191 @@
+# Authentik
+
+We document the setup of [Authentik](https://goauthentik.io), the identity provider used to protect the private services at `piribauer.ch`.
+Authentik runs in Docker and exposes its server on `127.0.0.1:9000`.
+All protected apps delegate authentication to it via nginx forward-auth — they never implement any login logic themselves.
+
+We assume Docker and nginx are already installed, and that a wildcard or per-subdomain TLS certificate is in place (we use Certbot).
+
+## Docker Compose
+
+We create the working directory and place the compose file there:
+
+```console
+$ mkdir -p /home/julian/authentik
+$ cd /home/julian/authentik
+```
+
+The `docker-compose.yml` runs four services: PostgreSQL, Redis, and the Authentik server and worker.
+The server is bound to `127.0.0.1:9000` so it is only reachable locally.
+
+```yaml
+services:
+ postgresql:
+ image: docker.io/library/postgres:16-alpine
+ restart: unless-stopped
+ volumes:
+ - database:/var/lib/postgresql/data
+ environment:
+ POSTGRES_PASSWORD: ${PG_PASS}
+ POSTGRES_USER: ${PG_USER:-authentik}
+ POSTGRES_DB: ${PG_DB:-authentik}
+
+ redis:
+ image: docker.io/library/redis:alpine
+ command: --save 60 1 --loglevel warning
+ restart: unless-stopped
+ volumes:
+ - redis:/data
+
+ server:
+ image: ghcr.io/goauthentik/server:2024.12.3
+ restart: unless-stopped
+ command: server
+ environment:
+ AUTHENTIK_REDIS__HOST: redis
+ AUTHENTIK_POSTGRESQL__HOST: postgresql
+ AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
+ AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
+ AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
+ AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
+ AUTHENTIK_ERROR_REPORTING__ENABLED: "false"
+ volumes:
+ - ./media:/media
+ - ./custom-templates:/templates
+ ports:
+ - "127.0.0.1:9000:9000"
+ - "127.0.0.1:9443:9443"
+
+ worker:
+ image: ghcr.io/goauthentik/server:2024.12.3
+ restart: unless-stopped
+ command: worker
+ user: root
+ environment:
+ AUTHENTIK_REDIS__HOST: redis
+ AUTHENTIK_POSTGRESQL__HOST: postgresql
+ AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
+ AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
+ AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
+ AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
+ AUTHENTIK_ERROR_REPORTING__ENABLED: "false"
+ volumes:
+ - /var/run/docker.sock:/var/run/docker.sock
+ - ./media:/media
+ - ./certs:/certs
+ - ./custom-templates:/templates
+
+volumes:
+ database:
+ driver: local
+ redis:
+ driver: local
+```
+
+## Environment file
+
+We create `/home/julian/authentik/.env` with the database credentials and a secret key.
+The secret key should be a long random string — it is used to sign sessions and must not change after the first start.
+
+```bash
+PG_PASS=<random password>
+PG_USER=authentik
+PG_DB=authentik
+AUTHENTIK_SECRET_KEY=<long random string>
+AUTHENTIK_ERROR_REPORTING__ENABLED=false
+```
+
+## Starting Authentik
+
+```console
+$ cd /home/julian/authentik
+$ docker compose up -d
+```
+
+Since docker.service is enabled in systemd and all containers have `restart: unless-stopped`, Authentik comes back up automatically after a reboot.
+
+On first start, we navigate to `https://auth.piribauer.ch/if/flow/initial-setup/` to set the admin password.
+
+## Nginx — Authentik itself
+
+We proxy `auth.piribauer.ch` to the local server:
+
+```nginx
+server {
+ server_name auth.piribauer.ch;
+
+ location / {
+ proxy_pass http://127.0.0.1:9000;
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection "upgrade";
+ 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_buffering off;
+ }
+
+ listen 443 ssl;
+ ssl_certificate /etc/letsencrypt/live/piribauer.ch/fullchain.pem;
+ ssl_certificate_key /etc/letsencrypt/live/piribauer.ch/privkey.pem;
+ include /etc/letsencrypt/options-ssl-nginx.conf;
+ ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
+}
+```
+
+## Creating a protected application
+
+For each service we want to protect, we create an application and a proxy provider in the Authentik admin UI at `https://auth.piribauer.ch/if/admin/`.
+
+Under **Providers**, we create a new *Proxy Provider* in forward-auth mode for the application's domain (e.g. `https://hub.piribauer.ch`).
+We then create an **Application** linked to that provider.
+Finally, under **Outposts**, we add the application to the embedded outpost so the outpost begins serving the forward-auth endpoint for it.
+
+## Nginx — forward-auth for protected apps
+
+Each protected app follows the same nginx pattern.
+We add two locations and an `auth_request` directive to the main location:
+
+```nginx
+# Authentik outpost endpoint
+location /outpost.goauthentik.io {
+ proxy_pass http://127.0.0.1:9000/outpost.goauthentik.io;
+ proxy_set_header Host $host;
+ proxy_set_header X-Original-URL $scheme://$host$request_uri;
+ 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_pass_request_body off;
+ proxy_set_header Content-Length "";
+ add_header Set-Cookie $auth_cookie;
+ auth_request_set $auth_cookie $upstream_http_set_cookie;
+}
+
+# Redirect unauthenticated requests to the login page
+location @goauthentik_proxy_signin {
+ internal;
+ add_header Set-Cookie $auth_cookie;
+ return 302 /outpost.goauthentik.io/start?rd=$scheme://$http_host$request_uri;
+}
+
+location / {
+ # ... proxy_pass or root directive ...
+
+ auth_request /outpost.goauthentik.io/auth/nginx;
+ error_page 401 = @goauthentik_proxy_signin;
+
+ auth_request_set $auth_cookie $upstream_http_set_cookie;
+ add_header Set-Cookie $auth_cookie;
+
+ # Optional: expose user attributes to the backend
+ auth_request_set $authentik_username $upstream_http_x_authentik_username;
+ auth_request_set $authentik_email $upstream_http_x_authentik_email;
+ proxy_set_header X-Authentik-Username $authentik_username;
+ proxy_set_header X-Authentik-Email $authentik_email;
+}
+```
+
+On each request, nginx calls the outpost's `/auth/nginx` endpoint.
+If the user has a valid session, the outpost returns 200 and nginx proceeds, injecting the username and email as headers.
+If not, nginx returns 401 which triggers the redirect to the login flow.