Published

Keycloak

Identity and access management server: single sign-on over OpenID Connect, OAuth 2.0 and SAML for your apps, with realms, user federation (LDAP, Kerberos), social and enterprise login, two-factor authentication and an admin console. The self-hosted stack is one Java (Quarkus) server and PostgreSQL, which holds all of its state.

Resources by load level

What the app itself needs at each level, next to what we recommend for a server that runs only this app.

LevelWhat it meansApp requirementsRecommended
LightEstimateUp to 1,000 users in a few realms and ~10 client apps; peaks of 2 password logins and 24 token refreshes a second.2 vCPU · 3 GiB RAM · 7.5 GiB disk2.52 vCPU · 5.1 GiB RAM · 18.055 GiB disk
MediumEstimateUp to 10,000 users; peaks of 6 password logins, 48 token refreshes and 12 client credential grants a second.3.25 vCPU · 3 GiB RAM · 7.5 GiB disk4.02 vCPU · 5.1 GiB RAM · 18.055 GiB disk
HeavyEstimateUp to 50,000 users; peaks of 12 password logins, 96 token refreshes and 24 client credential grants a second.6.5 vCPU · 6 GiB RAM · 52.5 GiB disk7.92 vCPU · 8.7 GiB RAM · 69.805 GiB disk

Recommended = app requirements + system baseline + safety headroom, under sizing policy 2026.10.0. Options stay at their defaults. “Estimate” means the sources give no number for that case, so it is worked out from them by the method stated under Components. How the numbers are built

Size it in the Stack Sizer

Ready-to-run files

Support level Supported

Compose template from the official sources; not yet verified by a run.

Create docker-compose

Components

What each component needs at each load level, before baseline and headroom.

vCPU / GiB RAM / GiB disk
ComponentLightMediumHeavySources
Keycloak server (app)1 / 2 / 12.25 / 2 / 14.5 / 2 / 1[2][13][14][15][31]
PostgreSQL (database)1 / 1 / 6.51 / 1 / 6.52 / 4 / 51.5[7][8][14][15][35][36][37][38][39][40][41]
How the estimates are worked out
  • Keycloak server · Light: CPU by the sizing guide: 2 logins/s ÷ 15 + 24 refreshes/s ÷ 120 = 0.333 vCPU, plus 150% headroom = 0.833, rounded up to 1 vCPU. RAM: the container guide's 2 GB for small production (base use 1250 MB with caches and 10,000 sessions); heap pinned at 1434 MiB. Disk: 265,677,312 B compressed image × 3 = 0.742 GiB, rounded up to 1 GiB; no data on disk.
  • Keycloak server · Medium: CPU by the sizing guide: 6 ÷ 15 + 48 ÷ 120 + 12 ÷ 120 = 0.9 vCPU (refreshes at the guide's 1:8 login ratio), plus 150% headroom = 2.25 vCPU. RAM stays at 2 GiB: memory follows the cached data (10,000 entries per cache by default), not the request rate. Disk: 0.742 GiB image, rounded up to 1 GiB.
  • Keycloak server · Heavy: CPU by the sizing guide: 12 ÷ 15 + 96 ÷ 120 + 24 ÷ 120 = 1.8 vCPU, plus 150% headroom = 4.5 vCPU; password hashing takes most of it. RAM stays at 2 GiB: the guide's own example serves 45 logins/s per cluster with 1250 MB per node. Disk: 0.742 GiB image, rounded up to 1 GiB.
  • PostgreSQL · Light: ~26 login, logout and refresh requests/s × 0.35–0.7 vCPU per 100 (Keycloak's database measurements) = 0.09–0.18 vCPU over a 0.3 vCPU idle load, inside the sidecar's 1 vCPU; ~364 write IOPS. The pool is capped at 20 connections. Light preset method: shared_buffers 25% of RAM, 0.5 GiB image + 5 GiB data + 1 GiB WAL.
  • PostgreSQL · Medium: ~55 login, logout and refresh requests/s × 0.35–0.7 vCPU per 100 = 0.19–0.39 vCPU over a 0.3 vCPU idle load, still inside 1 vCPU; ~770 write IOPS. 10,000 users × an assumed 20 KB of rows = 0.2 GB, inside 5 GB; pool capped at 20. Light preset method: shared_buffers 25% of RAM, 0.5 GiB image + 5 GiB data + 1 GiB WAL.
  • PostgreSQL · Heavy: ~110 login, logout and refresh requests/s × 0.35–0.7 vCPU per 100 = 0.38–0.77 vCPU over a 0.3 vCPU idle load: up to 1.07 vCPU, past the sidecar's 1 vCPU, so the PostgreSQL profile's medium preset (2 vCPU, 4 GiB). ~1,540 write IOPS. 50,000 users × an assumed 20 KB = 1 GB of rows.

Ports

Public ports are meant to be reached from outside the stack, usually through a reverse proxy; internal ones stay on the stack's own network.

ComponentPortExposurePurposeSources
Keycloak server8080/tcpPublic, through a proxyLogin pages, OIDC/SAML endpoints, Admin Console and Admin API (HTTP; TLS at the proxy)[5][11]
Keycloak server9000/tcpInternal onlyManagement interface: /health and /metrics; never expose it[3][4]
Keycloak server7800/tcpInternal onlyJGroups unicast transport of the ispn caches (jdbc-ping stack)[10]
Keycloak server57800/tcpInternal onlyJGroups failure detection (FD_SOCK2, bind port + 50000)[10]
PostgreSQL5432/tcpInternal onlyPostgreSQL connections from Keycloak (also its jdbc-ping node registry)[7][40]

Every port in the catalog, with conflicts between apps

User and permissions (UID/GID)

The user each container's process runs as, and the paths it writes to. A bind mount for one of these paths must be writable by that UID:GID.

ComponentUID:GIDUserStarts as rootWrites toSources
Keycloak serverDerived1000:0keycloakNo/opt/keycloak/data/opt/keycloak/lib[11][16][17]
PostgreSQL999:999postgresYes, prepares its directories, then drops to this user/var/lib/postgresql/var/run/postgresql[33][34][40]
  • Keycloak server: USER 1000 (keycloak, group 0) from the start, with /opt/keycloak owned by 1000:0 and group-writable. data/ holds runtime files; start without --optimized writes its build into lib/. Neither needs a volume: realms, users and sessions live in PostgreSQL.

Storage growth

How much each component's data grows per month at each load level, on top of the disk in the profile. A value marked Assumption is ANAROQ's stated assumption, not a figure from the sources; the notes say what it rests on.

GiB per month
ComponentLightMediumHeavySources
PostgreSQLAssumption0.0010.010.05[19][27]
What the growth figures rest on
  • PostgreSQL: New users a month (an assumed 50, 500 and 2,500) × an assumed 20 KB of rows each. Sessions are persisted but expire, so they hold a steady size; stored user and admin events are off by default and, once on, grow until their expiration removes them.

Upgrade and rollback

How to move to a new version safely, and how to go back if it fails.

Back up first

Take a pg_dump of the keycloak database and keep the .env: the migrated schema no longer works with the old server. [22]

Upgrade steps

  1. Read the upgrade notes of every version between yours and the new one in the Upgrading Guide: breaking changes are listed per release. [21]
  2. Change the pinned keycloak tag, then run docker compose pull and docker compose up -d. Compose stops the old container first, as minor and major upgrades require; the schema migrates at the first start (30 minute timeout). Follow docker compose logs -f keycloak until it is healthy. [22][23]
  3. On tables over 300,000 rows the migration skips new indexes and PostgreSQL builds them in the background after startup; expect extra database load for a while. [23]

Roll back

Keycloak cannot roll back database changes: stop it, restore the dump from before the upgrade, and pin the image back to the previous tag. [21][22]

Known breaking changes

  • In 26.8.1: With Enable StartTLS on, SMTP now requires a successful STARTTLS upgrade instead of falling back to plaintext; email fails against servers without STARTTLS. [24]
  • In 26.8.0: Login failures for brute force detection are stored in the database by default, with more database connections and CPU; disabled clients no longer appear in token audiences. [25]
  • In 26.7.0: The view-system admin role was removed, the shutdown timeout grew from 1 s to 10 s, and ephemeral writes (sessions, events) use PostgreSQL async commit. [26]
  • In 26.0.0: KEYCLOAK_ADMIN and KEYCLOAK_ADMIN_PASSWORD gave way to KC_BOOTSTRAP_ADMIN_USERNAME and KC_BOOTSTRAP_ADMIN_PASSWORD; hostname v1 and the proxy option were removed, and all user sessions are persisted in the database. [27]

Limits

  • One Keycloak node. CPU follows password hashing: 1 vCPU per 15 password logins a second, plus 150% headroom. The heap is pinned at 1434 MiB for the 2 GiB preset; change JAVA_OPTS_KC_HEAP if you give Keycloak more memory. [2][13][14]
  • Sessions live in PostgreSQL: every 100 login, logout and refresh requests a second need about 1,400 write IOPS, so a slow disk limits throughput before CPU does. [7][15]
  • The stock image runs its build at every start, which makes starts slower. Custom providers, themes or build options such as features need an optimized image of your own, which the template does not build. [2][16]

Security

  • The admin from .env is temporary and exists only to get in: sign in, create a permanent admin with two-factor authentication, then delete the temporary account. The bootstrap variables are ignored once the master realm exists. [16][18]
  • The proxy forwards everything. The reverse proxy guide recommends exposing only /realms/, /resources/ and /.well-known/, and keeping /admin/ and /realms/master/ internal: block them at your proxy, or use the master realm only from a private network. [5][6]
  • Behind a proxy Keycloak trusts X-Forwarded-* headers (KC_PROXY_HEADERS=xforwarded). Your proxy must set and overwrite them, and port 8080 must not be reachable around it; health and metrics stay on the unpublished port 9000. [4][5]
  • Brute force detection is off by default. Turn it on in each realm (Realm settings, Security defenses) before exposing login pages. [19]

Backup

  • All state is in PostgreSQL: realms, users, credentials, clients, signing keys and sessions. Back up a pg_dump of the keycloak database together with the .env; the Keycloak container has no volume. [7][22]
  • Realm exports from the Admin Console are not backups: they leave out secrets and users. Only exports taken at boot (kc.sh export) are fit for backups or moving to another server. [19][20]

Latest release

Newest upstream release
Keycloak 26.8.1 [29][30]
This profile was checked against

Keycloak 26.8.1

This profile was checked against the newest release.

Checked on
14 Oct 2026
State
Checked within the last 90 days
Where releases are published
GitHub Releases

Latest releases of every app

Version

Profile status
Published
Checked against release
Keycloak 26.8.1
Profile version
1.0.0
Figures verified
14 Oct 2026
Catalog release
2026.10.10
Sizing policy
2026.10.0
Compose file
Unverified
Official site
www.keycloak.org

Sources

  1. Docker Docs: Control startup order in Compose (pg_isready healthcheck, service_healthy) (Official docs · read 11 Oct 2026)
  2. Keycloak Docs: Running Keycloak in a container (plain start re-runs the build at every start; KC_BOOTSTRAP_ADMIN_*; heap 70% of the memory limit, 2 GB recommended for small production) (Official docs · read 14 Oct 2026)
  3. Keycloak Docs: Health checks (/health/ready on management port 9000 with health-enabled; no curl in the image; bash /dev/tcp HEALTHCHECK example) (Official docs · read 14 Oct 2026)
  4. Keycloak Docs: Management interface (/health and /metrics on port 9000, kept off the main HTTP port) (Official docs · read 14 Oct 2026)
  5. Keycloak Docs: Configuring the hostname v2 (hostname as a full URL, http-enabled for edge TLS on 8080, proxy-headers xforwarded) (Official docs · read 14 Oct 2026)
  6. Keycloak Docs: Configuring a reverse proxy (expose /realms/, /resources/, /.well-known/; keep /admin/ and /realms/master/ internal; proxy must overwrite X-Forwarded-*) (Official docs · read 14 Oct 2026)
  7. Keycloak Docs: Configuring the database (PostgreSQL 18.x to 14.x supported, tested with 18; db-url, db-username, db-password; connection pool) (Official docs · read 14 Oct 2026)
  8. Keycloak Docs: All configuration (bootstrap-admin-username temp-admin, db-pool-max-size 100, http-enabled false, cache ispn, health-enabled false, management port 9000) (Official docs · read 14 Oct 2026)
  9. Keycloak Docs: Configuring Keycloak for production (with health enabled, ports open during bootstrap and /health/ready stays DOWN until it ends) (Official docs · read 14 Oct 2026)
  10. Keycloak Docs: Configuring distributed caches (start uses ispn with the jdbc-ping stack; ports 7800 and 57800; local cache only for development) (Official docs · read 14 Oct 2026)
  11. keycloak repository: quarkus/container/Dockerfile at 26.8.1 (ubi9-micro, /opt/keycloak owned 1000:0, USER 1000, EXPOSE 8080 8443 9000, ENTRYPOINT kc.sh, no HEALTHCHECK) (Official repository · read 14 Oct 2026)
  12. keycloak repository: quarkus/container/ubi-null.sh at 26.8.1 (the image keeps bash and coreutils-single for a shell; no curl) (Official repository · read 14 Oct 2026)
  13. keycloak repository: kc.sh at 26.8.1 (in a container, JAVA_OPTS_KC_HEAP defaults to MaxRAMPercentage=70 and InitialRAMPercentage=50; a set value replaces it) (Official repository · read 14 Oct 2026)
  14. Keycloak Docs: Concepts for sizing CPU and memory (1250 MB base; 1 vCPU per 15 password logins/s, per 120 refreshes/s, per 120 client credential grants/s; 150% CPU headroom) (Official docs · read 14 Oct 2026)
  15. keycloak repository: perf_recommendations.adoc at 26.8.1 (database: 1400 write IOPS and 0.35 to 0.7 vCPU per 100 login/logout/refresh per second; idle 0.3 vCPU) (Official repository · read 14 Oct 2026)
  16. Keycloak Docs: Configuring Keycloak (start runs a build under the covers; --optimized skips it; bootstrap admin variables are ignored once an admin exists) (Official docs · read 14 Oct 2026)
  17. Keycloak Docs: Directory structure (/opt/keycloak in containers; data/ holds runtime information such as transaction logs; lib/ used internally) (Official docs · read 14 Oct 2026)
  18. Keycloak Docs: Bootstrapping and recovering an admin account (bootstrap admin is temporary, created only with the master realm; remove it manually) (Official docs · read 14 Oct 2026)
  19. Keycloak Server Administration Guide (brute force detection off by default; Save events off until enabled; Admin Console exports are not backups) (Official docs · read 14 Oct 2026)
  20. Keycloak Docs: Importing and exporting realms (kc.sh export with users; Admin Console partial export leaves out users and masks secrets) (Official docs · read 14 Oct 2026)
  21. Keycloak Upgrading Guide (back up the database first; schema migrates at first start; database changes cannot be rolled back) (Official docs · read 14 Oct 2026)
  22. keycloak repository: upgrading/topics/prep_migration.adoc at 26.8.1 (shut down for minor and major upgrades; back up the database; no rollback of schema changes) (Official repository · read 14 Oct 2026)
  23. keycloak repository: upgrading/topics/migrate_db.adoc at 26.8.1 (automatic migration, 30 min timeout, indexes on tables over 300,000 rows built in the background) (Official repository · read 14 Oct 2026)
  24. Keycloak 26.8.1 upgrade notes (SMTP StartTLS is required when enabled, CVE-2026-107121) (Release notes · read 14 Oct 2026)
  25. Keycloak 26.8.0 upgrade notes (login failures stored in the database by default; disabled clients left out of token audiences) (Release notes · read 14 Oct 2026)
  26. Keycloak 26.7.0 upgrade notes (view-system admin role removed; shutdown timeout 10 s; async commit on PostgreSQL) (Release notes · read 14 Oct 2026)
  27. Keycloak 26.0.0 upgrade notes (KEYCLOAK_ADMIN replaced by KC_BOOTSTRAP_ADMIN_*; hostname v1 and proxy option removed; sessions persisted) (Release notes · read 14 Oct 2026)
  28. Keycloak Release Notes (26.8.0 is the newest minor release) (Release notes · read 14 Oct 2026)
  29. Keycloak: Downloads (26.8.1 server distribution and container image) (Official docs · read 14 Oct 2026)
  30. Quay tags of quay.io/keycloak/keycloak (newest release 26.8.1, pushed 2026-10-13; 26.8 and latest point to the same index) (Official repository · read 14 Oct 2026)
  31. Quay manifest of quay.io/keycloak/keycloak:26.8.1 (linux/amd64): 4 layers, 265,677,312 B compressed; config User 1000, no Healthcheck (Measurement · read 14 Oct 2026)
  32. keycloak repository: LICENSE.txt at 26.8.1 (Apache License 2.0) (Official repository · read 14 Oct 2026)
  33. docker-library/postgres: 18/trixie Dockerfile (postgres uid/gid 999, VOLUME /var/lib/postgresql) (Official repository · read 14 Oct 2026)
  34. docker-library/postgres: 18/trixie docker-entrypoint.sh (chown PGDATA, then gosu postgres) (Official repository · read 14 Oct 2026)
  35. PostgreSQL 18 documentation: 19.4 Resource Consumption (Official docs · read 10 Oct 2026)
  36. PostgreSQL 18 documentation: 19.3 Connections and Authentication (Official docs · read 10 Oct 2026)
  37. PostgreSQL 18 documentation: 19.10 Vacuuming (autovacuum settings) (Official docs · read 10 Oct 2026)
  38. PostgreSQL 18 documentation: 19.5 Write Ahead Log (max_wal_size) (Official docs · read 10 Oct 2026)
  39. PostgreSQL 18 documentation: 51.2 How Connections Are Established (Official docs · read 10 Oct 2026)
  40. Docker Official Image postgres: documentation (docker-library/docs) (Official docs · read 10 Oct 2026)
  41. Docker Hub: library/postgres tag 18.6 (compressed image sizes) (Official repository · read 10 Oct 2026)

All self-hosted apps