Deployment guide

Centralizing authentication with Authentik on VPS

Deploy on a VPS Cloud →

Tutorial

Security & Monitoring

Centralizing authentication with Authentik on VPS

Managing one password per application doesn't scale for an agency or a serious homelab. Authentik is an open source identity provider that centralizes SSO, MFA and user management. Deployed on your VPS, it becomes the single authentication point for your entire self-hosted ecosystem.

9 min read10 steps
Contents· Why centralize authentication on your VPS1/13
  1. 01Why centralize authentication on your VPS
  2. 02What you gain with Authentik
  3. 03Prerequisites, with numbers
  4. 04Checklist before the first docker compose up
  5. 05Deploy Authentik with Docker Compose
  6. 06Reverse proxy and TLS
  7. 07Protect an application with forward auth on nginx
  8. 08Back up and restore Authentik
  9. 09What to back up
  10. 10Upgrade without breaking SSO
  11. 11Redis is no longer part of the stack
  12. 12Troubleshooting: restart loop with AUTHENTIK_POSTGRESQL__USE_POOL
  13. 13Other common failures

Why centralize authentication on your VPS

When you accumulate self-hosted tools (Grafana, Nextcloud, Gitea, an internal dashboard), each brings its own user base and its own password policy. It's a nightmare to maintain and a multiplied attack surface. Authentik solves this by acting as an identity provider (IdP): it supports OAuth2/OIDC, SAML, LDAP and above all forward auth, which lets you protect any application behind a reverse proxy, even those with no notion of login at all. Self-hosting on a VPS guarantees that your credentials never pass through a third-party service and that you stay in control of the user tree and MFA policies.

What you gain with Authentik

  • A single set of credentials for all your applications, with centralized sign-out.
  • MFA (TOTP, WebAuthn/FIDO2 keys, backup codes) applied uniformly through policy.
  • Forward auth to protect "login-less" apps, which is impossible with a classic IdP.
  • Fully customizable flows (sign-up, recovery, captcha, access conditions).
  • OAuth2/OIDC, SAML and LDAP connectors to plug in modern and legacy apps alike.
  • Instant access provisioning and revocation when a team member leaves.

Prerequisites, with numbers

The official Authentik documentation asks for at least 2 CPU cores and 2 GB of RAM, with Docker Compose v2 (or Podman). On a real VPS we recommend 2 vCPUs and 4 GB of RAM: the server, the worker and PostgreSQL share the same machine, and 2 GB leaves no margin as soon as a connection spike or an outpost is added. Also plan for about twenty gigabytes of free disk for images, the database and a few local backups (an indicative estimate, not an official figure). Authentik is a guide provided on a VPS template: ServOrbit does not support it, you keep its administration.

Checklist before the first docker compose up

  • A 64-bit Linux VPS with Docker Engine and the Compose v2 plugin: 2 vCPUs and 4 GB of RAM recommended, 2 cores and 2 GB as the strict official minimum.
  • A dedicated subdomain, for example auth.example.com, with an A record (and AAAA if you have IPv6) pointing to the VPS IP.
  • Ports 80 and 443 open to the reverse proxy; ports 9000 and 9443 of the server container never exposed publicly.
  • A reverse proxy (nginx, Caddy or Traefik) able to obtain a Let's Encrypt certificate.
  • A way to recover the administrator account if you lose your second factor: backup codes stored in a password manager.
  • A backup location outside the VPS.

Deploy Authentik with Docker Compose

  1. Create the folder and fetch the official compose file

    Create a dedicated folder (mkdir -p /opt/authentik && cd /opt/authentik) then download the reference file with wget https://docs.goauthentik.io/compose.yml. The current file declares three services: postgresql, server and worker. It references the version available at download time, so you must download it again at each upgrade.

  2. Generate the secrets in the .env file

    Run echo "PG_PASS=$(openssl rand -base64 36 | tr -d '\n')" >> .env then echo "AUTHENTIK_SECRET_KEY=$(openssl rand -base64 60 | tr -d '\n')" >> .env. The documentation states that PostgreSQL passwords longer than 99 characters are not supported. Protect the file (chmod 600 .env), never commit it and never reuse an example key.

  3. Bind the ports to localhost only

    By default the compose file publishes 9000 (HTTP) and 9443 (HTTPS) on all interfaces. Add COMPOSE_PORT_HTTP=127.0.0.1:9000 and COMPOSE_PORT_HTTPS=127.0.0.1:9443 to .env: only your local reverse proxy can reach them, and public traffic necessarily goes through HTTPS.

  4. Start the stack

    Run docker compose pull then docker compose up -d. Check with docker compose ps that the three containers are up and that postgresql is healthy, then follow initialization with docker compose logs -f server. Database migrations can take a few minutes on first launch.

  5. Finish the install through /if/flow/initial-setup/

    On first launch, open https://auth.example.com/if/flow/initial-setup/ to set the password of the akadmin account. It is your super-administrator: protect it with MFA immediately, then create a named administrator account for daily use.

  6. Create a provider and an application

    In the admin, create a Provider (OIDC for a modern app, or Proxy for forward auth) then the matching Application. For OIDC, grab the client_id / client_secret and the .well-known/openid-configuration URL to paste into the client app.

Reverse proxy and TLS

Authentik must be served over HTTPS for session cookies and WebAuthn to work. With nginx, the auth.example.com vhost does a proxy_pass http://127.0.0.1:9000; and forwards the Host, X-Forwarded-For and X-Forwarded-Proto headers, plus Upgrade and Connection for WebSockets. The certificate comes from certbot --nginx -d auth.example.com; Caddy and Traefik do it automatically. If the domain goes through Cloudflare in proxied mode, set the zone's SSL/TLS mode to Full (strict): in Flexible, nginx redirects HTTP to HTTPS and you get an infinite redirect loop.

Protect an application with forward auth on nginx

  1. Create the Proxy Provider

    Create a Proxy Provider in single-application forward auth mode, with the app's public URL (https://app.example.com) as External host. Attach it to an Application, then to the embedded outpost in the Outposts section.

  2. Wire auth_request into the app's vhost

    In location /, add auth_request /outpost.goauthentik.io/auth/nginx;, then error_page 401 = @goauthentik_proxy_signin;. Also copy the outpost cookies with auth_request_set $auth_cookie $upstream_http_set_cookie; and add_header Set-Cookie $auth_cookie;. Copy the full block from the nginx page of the documentation matching your version.

  3. Expose the outpost path without authentication

    Add a location /outpost.goauthentik.io that does a proxy_pass to http://127.0.0.1:9000, with Host set to the original host, X-Original-URL set to the full URL, proxy_pass_request_body off; and an empty Content-Length. This path must stay reachable without login, otherwise the redirect never works.

  4. Handle the redirect and large headers

    Declare a location @goauthentik_proxy_signin marked internal that returns a 302 to /outpost.goauthentik.io/start?rd= followed by the original URL. If you see the "upstream sent too big header" error, add proxy_buffers 8 16k; and proxy_buffer_size 32k;. Identities then reach the app in the X-authentik-username, X-authentik-groups and X-authentik-email headers.

Back up and restore Authentik

The PostgreSQL database is the most important part of a backup: it holds users, policies, flows and configuration. With the compose defaults (user and database authentik), a dump is made with docker compose exec -T postgresql pg_dump -U authentik -d authentik -Fc > /var/backups/authentik-$(date +%F).dump. To restore, first stop the application containers with docker compose stop server worker, then run docker compose exec -T postgresql pg_restore -U authentik -d authentik --clean --if-exists < file.dump, and restart. The order recommended by the documentation is: database first, verification, static directories, then start. A backup that was never restored is only a hypothesis: test on a throwaway machine.

What to back up

  • The PostgreSQL database: essential, without it Authentik cannot be brought back.
  • The ./data directory (icons, flow backgrounds, uploaded files, CSV reports), unless you use S3 storage.
  • The ./certs directory if you rely on filesystem certificates; certificates already imported live in the database.
  • The ./custom-templates directory if you changed the look and feel, and custom blueprints if any.
  • The .env file (secret key and PostgreSQL password), encrypted and kept outside the VPS.
  • A copy of the dumps on remote storage, never only on the machine hosting the database.

Upgrade without breaking SSO

Authentik does not support downgrading: back up the database before each upgrade and read the release notes of the target. Upgrade sequentially, going through the latest patch of each major.minor version without skipping any. Download the compose file again (wget -O compose.yml https://docs.goauthentik.io/compose.yml), then docker compose pull and docker compose up -d. Upgrade all outposts at the same time: their version must match the server's. Then check the version under Dashboards > Overview; if it did not change and the logs contain migration inconsistency, restore the backup and move up version by version.

Redis is no longer part of the stack

Many older tutorials, including the first version of this article, describe a four-container stack with Redis. The 2025.10 release notes state that Authentik no longer uses Redis at all: cache, embedded outpost and WebSockets moved to PostgreSQL, tasks having already moved in 2025.8. The current compose file therefore contains only postgresql, server and worker. Two consequences: expect roughly 50% more PostgreSQL connections, and if your PostgreSQL requires TLS, Authentik requires TLS 1.3 or the Extended Master Secret extension. Remove any Redis settings left in your configuration.

Troubleshooting: restart loop with AUTHENTIK_POSTGRESQL__USE_POOL

Symptom reported in goauthentik/authentik issue 14320, opened in May 2025 on version 2025.4.0: with AUTHENTIK_POSTGRESQL__USE_POOL=true, the server restarts in a loop, with SSL errors such as "decryption failed or bad record mac" or "SSL SYSCALL error: EOF detected", then a gunicorn worker exiting with code 3 ("Worker failed to boot"). Release 2025.4.1, published in May 2025, disabled the option as a precaution, since the root cause had not been found. Actual state of the issue as read on October 30, 2026: still open, labeled confirmed bug, with no linked fix PR, and a 2026.11.0 milestone marked Required since October 23, 2026. A maintainer's hypothesis: the async SSL context shared across threads, although it is not thread-safe. Reported, unofficial lead: a user stated in September 2026 that AUTHENTIK_WEB__WORKERS=1 and AUTHENTIK_WEB__THREADS=1 removed the problem; in a maintainer's tests, 1 worker and 1 thread are fine, while 2 or more workers reproduce it. This is neither a fix nor a guarantee, and it limits the interface's capacity. The safest course is not to enable the pool (remove the variable from .env) and to reread the issue before any upgrade.

Other common failures

  • Redirect loop behind Cloudflare: the zone's SSL/TLS mode is Flexible; switch to Full (strict) and check that X-Forwarded-Proto is forwarded.
  • WebAuthn or cookies refused: the interface is served over HTTP or under another hostname; enforce HTTPS on Authentik's exact domain.
  • 502 error on the protected app: look for "upstream sent too big header" in the nginx logs and increase proxy_buffer_size.
  • server and worker do not start: postgresql is not healthy; read docker compose logs postgresql, and remember that PG_PASS and AUTHENTIK_SECRET_KEY are mandatory.
  • Outpost unreachable after an upgrade: its version no longer matches the server's; upgrade it.
  • Containers killed without a message: on 2 GB of RAM the OOM killer strikes; check with dmesg | grep -i oom and move to 4 GB.

Enable an embedded Outpost and use "property mappings" to inject headers (X-authentik-username, X-authentik-groups) into your forward-auth applications: many apps (Grafana, for example) can read these headers to auto-provision users and assign roles. You get not just SSO but a fully automated group-to-role mapping, with no manual configuration in each tool.

Centralize your access on your own VPS

The ServOrbit Cloud VPS with a preconfigured Docker template offers the RAM and storage needed for the Authentik stack (server, worker, PostgreSQL, Redis) ready to receive your applications.