NODED.CLOUD/Blog/Self-Hosted SSO on a VPS: Authentik vs Keycloak, Setup and Backups

Self-Hosted SSO on a VPS: Authentik vs Keycloak, Setup and Backups

07 Nov 2026 · Mario Marin

Authentik or Keycloak for self-hosted single sign-on: what each needs, running them behind a reverse proxy, the ports, mail through a relay, backing up the identity store, and which plan to start on.

Self-hosted SSO means running your own identity provider, so the apps your team uses sign in through one login page on a server you control. Authentik and Keycloak are the two common choices: both speak OpenID Connect and SAML, both store everything in PostgreSQL, and both run on a small VPS behind a reverse proxy.

This post compares the two, lists what each needs, shows a reverse proxy setup and the ports, explains what to back up, and sizes a plan. Versions checked are authentik 2026.8.5 and Keycloak 26.8.1, the current releases.

What is self-hosted SSO, and which apps can it front?

An identity provider holds users, groups, passwords and second factors, and issues signed tokens that apps trust. Each app is registered once as a client; users log in at the identity provider and are sent back signed in. Removing someone from one place removes them everywhere, which is the real reason to run it.

Three ways an app can use it:

  • OpenID Connect or OAuth 2.0. Most current self-hosted apps support it: Grafana, Nextcloud, Gitea and Forgejo, Immich, Mastodon, and the Headscale control server, whose OIDC login turns your tailnet's devices into SSO-managed ones.
  • SAML. Older business software and many paid SaaS tools.
  • Forward authentication. For apps with no login integration at all, a proxy checks the session before passing the request on. authentik ships this as its proxy provider; with Keycloak you add a separate proxy such as oauth2-proxy.

Some apps need glue. Jitsi Meet's recommended login, for example, is JWT, so it needs a small token service between it and your identity provider, as our Jitsi Meet guide mentions.

Authentik vs Keycloak: how do they differ?

authentikKeycloak
Current release2026.8.526.8.1
Protocols as identity providerOAuth2/OIDC, SAML, plus LDAP, RADIUS, proxy, SCIM providersOIDC, OAuth 2.0, SAML
Apps without SSO supportBuilt-in proxy provider (outposts)Separate proxy needed
ContainersPostgreSQL, server, workerKeycloak, plus PostgreSQL
Documented minimum2 CPU cores, 2 GB RAM for the hostAbout 1,250 MB base memory per instance
Ports9000 HTTP, 9443 HTTPS8443 HTTPS, or 8080 with HTTP enabled; 9000 management
LicenceOpen source core with an enterprise editionApache-2.0

In practice: authentik suits a homelab or small company that wants one tool to cover modern apps, legacy LDAP clients and apps with no login at all, configured through flows in a web UI. Keycloak suits teams that mostly need standard OIDC and SAML, want a long-established project with detailed sizing guidance, or already run Java services. Both have a learning curve; plan an afternoon before the first app works end to end.

Both support second factors such as TOTP apps and WebAuthn security keys, both can pull users from an existing LDAP or Active Directory, and both can let people log in with an outside account such as GitHub or Google if you allow it. The choice is less about features than about which admin model your team finds easier to keep correct.

What do Authentik and Keycloak need to run?

authentik

The Docker Compose guide, described as fit for small-scale production, asks for at least 2 CPU cores and 2 GB of RAM. The current compose file runs three services: PostgreSQL 16, the server and a worker. Setup is a download and two secrets:

wget https://docs.goauthentik.io/compose.yml
echo "PG_PASS=$(openssl rand -base64 36 | tr -d '\n')" >> .env
echo "AUTHENTIK_SECRET_KEY=$(openssl rand -base64 60 | tr -d '\n')" >> .env
echo "COMPOSE_PORT_HTTP=127.0.0.1:9000" >> .env
echo "COMPOSE_PORT_HTTPS=127.0.0.1:9443" >> .env
docker compose pull && docker compose up -d

The two port lines bind authentik to localhost, because Docker-published ports bypass ufw. The worker mounts the Docker socket to manage outposts; the docs flag that as a risk and suggest a socket proxy or deploying outposts by hand. Then open the site and set the password for the default akadmin user.

Keycloak

Keycloak's sizing guide puts base memory at about 1,250 MB, including realm caches and 10,000 cached sessions. CPU goes mostly to password hashing: one vCPU per 15 password logins a second. As an example, 500 people logging in over five minutes is under 2 logins a second, well inside one core. PostgreSQL 14 to 18 is supported. A production start behind a proxy, on a Docker network shared with a PostgreSQL container:

docker run -d --name keycloak --network sso -p 127.0.0.1:8080:8080 \
  -e KC_BOOTSTRAP_ADMIN_USERNAME=admin \
  -e KC_BOOTSTRAP_ADMIN_PASSWORD=change-me-now \
  -e KC_DB=postgres \
  -e KC_DB_URL=jdbc:postgresql://postgres:5432/keycloak \
  -e KC_DB_USERNAME=keycloak -e KC_DB_PASSWORD=db-secret \
  quay.io/keycloak/keycloak:26.8.1 start \
  --hostname https://sso.example.org --http-enabled true --proxy-headers xforwarded

Create your own realm for users and apps; the docs reserve master for managing Keycloak itself.

How do you run SSO behind a reverse proxy, and which ports?

Both expect TLS to end at a proxy. authentik needs the original host, scheme and client IP forwarded, plus WebSocket upgrades for outposts; Caddy does all of that by default:

auth.example.org {
    reverse_proxy 127.0.0.1:9000
}

Keycloak's reverse proxy guide recommends exposing only /realms/, /resources/ and /.well-known/, and keeping /admin/ and /realms/master/ internal. Without --proxy-headers, requests through the proxy that Keycloak origin-checks fail with 403 errors.

sso.example.org {
    @internal path /admin/* /realms/master/*
    respond @internal 404
    reverse_proxy 127.0.0.1:8080
}

Reach the admin console over an SSH tunnel or a private network instead, with the hostname-admin option if you give it its own name.

PortServiceOpen to
22/tcpSSHYour IP only
80/tcp, 443/tcpCaddy: certificates and HTTPSEveryone
9000/tcp, 9443/tcpauthentik HTTP and HTTPSLocalhost only, behind the proxy
8080/tcpKeycloak HTTPLocalhost only, behind the proxy
9000/tcpKeycloak management (health, metrics)Localhost only; clashes with authentik if both share a host
5432/tcpPostgreSQLNever public

Login pages attract password spraying. Every Noded VPS includes 100 Gbps of always-on Layer 3/4 DDoS protection, which stops floods, not guessing: turn on rate limits, lockout or reputation policies in the identity provider, and require a second factor for admins.

Both send mail for verification, recovery and alerts. Outbound SMTP on TCP 25 is blocked on every Noded VPS, which authentik's email docs anticipate: use a relay on port 587 with AUTHENTIK_EMAIL__USE_TLS=true, or the same relay in Keycloak's realm email settings with STARTTLS.

How do you back up the identity store?

If the identity provider is lost, nobody can log in to anything, so treat the backup as the most important one you run. authentik's backup guide calls PostgreSQL the most important part: users, policies, flows and configuration all live there. Also copy /data (icons, uploads, reports), /certs, /custom-templates and /blueprints if you use them, and keep the .env with the secret key somewhere safe.

# authentik (compose service "postgresql")
docker compose exec -T postgresql pg_dump -U authentik -d authentik -Fc > authentik.dump
# Keycloak (PostgreSQL container "postgres")
docker exec postgres pg_dump -U keycloak -d keycloak -Fc > keycloak.dump

For Keycloak, a database dump is the routine backup. Its realm export command needs the server stopped for a consistent result, so keep it for migrations rather than nightly jobs. Our VPS plans have no snapshots or backups, so send the dumps to another machine, ideally in another EU country, with restic or Borg as our backup target post describes. Test a restore before you need one.

Which Noded plan fits self-hosted SSO?

Identity providers are light on bandwidth and heavy on reliability. Prices are monthly, in euros, excluding VAT, from our live catalogue; the RAM guidance follows the projects' documented minimums.

UsePlanvCPU / RAM / SSDBucharestSofia
Homelab or small team, either toolVPS II2 / 4 GB / 40 GB€6€9
Company use, room for PostgreSQL growthVPS III2 / 8 GB / 60 GB€10€16
Many apps, heavy login bursts, or both tools side by sideVPS IV4 / 16 GB / 80 GB€16€26

VPS I (2 GB) only just meets authentik's minimum before PostgreSQL is counted, so start at VPS II. A second small VPS in another location as the backup target costs from €4. Our PostgreSQL sizing post covers the database side if you move it to its own machine later.

Questions people ask

Is authentik or Keycloak better for self-hosted SSO?

authentik if you want LDAP, RADIUS and proxy login for apps without SSO in the same tool. Keycloak if you mainly need OIDC and SAML and value its detailed sizing and production guidance.

How much RAM does Keycloak need?

The sizing guide puts base memory at about 1,250 MB per instance, with roughly 300 MB of that outside the Java heap. Add PostgreSQL and the operating system, which makes 4 GB a comfortable start.

Can self-hosted SSO protect apps that have no login integration?

Yes, with forward authentication. authentik's proxy provider does it directly; with Keycloak, place a proxy such as oauth2-proxy in front of the app.

Do I need Redis for authentik?

Not with the current compose file, which runs only PostgreSQL, the server and the worker.

Running your identity provider in the EU

An identity store is personal data by definition: names, email addresses, group memberships and login history. Pick Bucharest or Sofia and the VPS and any images you capture stay in the EU under GDPR; our data processing agreement is part of the Terms, and the GDPR hosting page has the details. Order VPS II from the VPS hosting page, connect one low-stakes app first, and move admin accounts over last.

← All posts

Related services

Run this on NODED.CLOUD.

Keep reading

More from the NOC.

01 Sept 2026·Mario Marin

Self-Hosted Error Tracking: GlitchTip on a VPS

A sizing and setup guide for running GlitchTip, the open-source Sentry-compatible error tracker, on a self-hosted VPS — with a look at why teams move off per-event SaaS pricing and keep error data on EU infrastructure.

Read post
26 Aug 2026·Mario Marin

Self-Hosted Docker Registry on a VPS

A setup and sizing guide for running Docker Distribution or Harbor as a private registry on a VPS, matched to image storage volume and CI pull frequency to avoid Docker Hub's rate limits and per-seat pricing.

Read post
17 Aug 2026·Mario Marin

Dedicated IP for Email Deliverability

A shared sending IP means someone else's spam habits become your bounce problem. Here is how to warm up a dedicated IP, why the PTR record matters, and how to keep a self-hosted mail server out of the junk folder.

Read post

Like the way we run things? Spin up a server in 60 seconds.