Keycloak Ops
Isometric dark navy platform with glowing pink database cylinders and cubes linked by dashed lines, suggesting server resources for a Keycloak deployment
sizing

Keycloak Resource Requirements: CPU, RAM, Disk, Database

Keycloak resource requirements: a 2 GB memory limit, 2 vCPU and PostgreSQL cover a homelab. Official sizing math and an N100 compose file.

By Keycloak Ops Editorial · · 8 min read

Keycloak resource requirements for a homelab or small team come down to three numbers: a 2 GB container memory limit (750 MB is the documented floor), 2 vCPU, and a separate PostgreSQL database on SSD. Keycloak’s own sizing guide puts baseline usage at 1250 MB of RAM per instance. A four-core N100 mini-PC runs it with plenty to spare.

Past that, the numbers that matter are request rates, not user counts. A household generating a few logins an hour is nowhere near needing a second core. Memory is the line you have to set deliberately, because the JVM takes whatever you leave unbounded.

Keycloak resource requirements at a glance

ResourceDocumented figureOn one mini-PC
Container memory limit2 GB for smaller production deployments; 750 MB approximates the old 512 MB heapSet 2 GB
Baseline RAM per instance1250 MB, including realm caches and 10,000 cached sessionsWhat a quiet instance uses
Heap and non-heapHeap up to 70% of the container limit; about 300 MB non-heapAlways set a limit
CPU, password logins1 vCPU per 15 logins per secondNot your bottleneck
CPU, refresh and client credentials1 vCPU per 120 requests per secondNot your bottleneck
CPU headroom150% extra for spikes, startup and failoverDon’t cap CPU tightly
DatabasePostgreSQL 14 to 18 supported; dev-file not for productionPostgres, even for one user
Database load1400 write IOPS and 0.35 to 0.7 vCPU per 100 login, logout or refresh requests per secondLocal SSD, not a NAS share
Instance countTwo or more in typical productionOne, if you accept SSO downtime

Memory and CPU figures come from Keycloak’s sizing guide and container guide, the database rows from the database guide, and the instance count from the production configuration guide.

Those sizing numbers came from OpenShift on AWS Graviton c7g instances against Aurora PostgreSQL seeded with 1,000,000 users and 20,000 clients, and the guide says to “use these values as a starting point and perform your own load tests before going into production.” They describe a cloud cluster, but they are still the best published yardstick for a box under your desk.

How much RAM does Keycloak need?

Plan for a 2 GB memory limit per instance. The official image sizes the JVM heap from the container limit (-XX:MaxRAMPercentage=70, -XX:InitialRAMPercentage=50), so the limit decides how big the heap can grow. The container guide recommends a 2 GB limit for smaller production deployments and says at least 750 MB approximates the old 512 MB maximum heap.

Its more important instruction: always set a limit. Without one, the heap can grow to 70% of the memory the container sees, which on a bare docker run means 70% of the host. That is a lot of RAM for a login page.

The two official documents disagree slightly. The sizing guide’s worked example lands on a 1360 MB limit: 1250 MB of expected usage, minus 300 MB non-heap, divided by 0.7. That example keeps user sessions in the database, while the 2 GB figure buys slack for realm imports, extensions and cache growth. On a 16 GB mini-PC the extra 640 MB costs nothing. On a 2 GB VPS shared with other services, 1360 MB is a defensible squeeze.

For a fixed heap instead of percentages, the container guide documents the JAVA_OPTS_KC_HEAP override. Cache caps and the metrics worth watching are covered in Keycloak memory usage and heap sizing.

How much CPU does Keycloak need?

Two vCPU is a sensible floor, and the reason is startup and password hashing, not steady-state traffic. The sizing guide budgets 1 vCPU per 15 password logins per second because Keycloak “spends most of the CPU time hashing the password provided by the user,” using default Argon2 with 5 iterations and a 7 MiB minimum memory size.

In homelab terms, 15 logins per second is 54,000 an hour on one core. Refresh tokens and client credential grants are cheaper, at 120 per second per vCPU. Your Jellyfin and Grafana logins will not register.

Where you feel CPU at home is restarts. Running start on the stock image applies build options at boot, which the container guide says “significantly increases startup time.” The fix is a two-stage image that runs kc.sh build once and then start --optimized:

FROM quay.io/keycloak/keycloak:26.8.0 AS builder
ENV KC_HEALTH_ENABLED=true
ENV KC_DB=postgres
RUN /opt/keycloak/bin/kc.sh build

FROM quay.io/keycloak/keycloak:26.8.0
COPY --from=builder /opt/keycloak/ /opt/keycloak/
ENTRYPOINT ["/opt/keycloak/bin/kc.sh"]

This is optional. If Keycloak restarts once a month after an update, a slower boot is a minor annoyance, and the custom image is one more thing to rebuild.

Two cautions. The sizing guide says “performance of Keycloak dropped significantly when its Pods were throttled,” so don’t set cpus: 1 just to be tidy. And the per-vCPU figures aren’t portable to a 6 W chip in either direction: the guide saw x86 instances deliver up to twice the refresh and client credential operations per core of the Graviton machines, with password hashing roughly constant per core.

What does Keycloak need from the database?

A real PostgreSQL instance on fast local storage. The database guide says the bundled dev-file database “is not suitable for production use-cases,” and lists PostgreSQL 14.x through 18.x as supported, alongside MariaDB, MySQL, SQL Server and Oracle. Pick Postgres unless you already run one of the others.

The database matters more than it used to. Per the caching guide, persistent user sessions are the default, with sessions “loaded on-demand from the database into the embedded caches,” so every login is a database write. The sizing guide budgets 1400 write IOPS per 100 login, logout or refresh requests per second. You won’t approach that at home, but write latency is login latency, so pgdata belongs on the mini-PC’s NVMe drive, not on an NFS export from the NAS.

db-pool-max-size defaults to 100 connections. That is fine for one instance. If you ever run several against one Postgres, multiply by the instance count and check it against Postgres’s connection limit.

Disk on the Keycloak side is close to irrelevant; the database is the state.

Hardware that works for a single-box install

An Intel N100 mini-PC is the default homelab box for good reason. Intel’s spec sheet lists 4 cores, 4 threads, a 6 W TDP and a 16 GB maximum memory size. Give Keycloak 2 GB and Postgres a 1 GB guardrail, and roughly 13 GB is left for everything else you swore you would not self-host.

The NAS is the backup target, not the database host. Dump Postgres nightly to an SMB or NFS share and periodically restore a dump into a scratch container, because a backup you have never restored is a theory.

A compose file with the limits set

This assumes the Containerfile above sits next to compose.yml, a reverse proxy on the host terminates TLS, and PG_PASS and KC_ADMIN_PASS live in .env.

services:
  postgres:
    image: docker.io/library/postgres:17-alpine
    restart: unless-stopped
    environment:
      POSTGRES_DB: keycloak
      POSTGRES_USER: keycloak
      POSTGRES_PASSWORD: ${PG_PASS:?set PG_PASS in .env}
    volumes:
      - ./pgdata:/var/lib/postgresql/data
    mem_limit: 1g
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U keycloak -d keycloak"]
      interval: 30s
      retries: 5

  keycloak:
    build: .
    image: local/keycloak:26.8.0
    command: start --optimized
    restart: unless-stopped
    depends_on:
      postgres:
        condition: service_healthy
    environment:
      KC_DB_URL_HOST: postgres
      KC_DB_URL_DATABASE: keycloak
      KC_DB_USERNAME: keycloak
      KC_DB_PASSWORD: ${PG_PASS}
      KC_HOSTNAME: https://auth.example.com
      KC_HTTP_ENABLED: "true"
      KC_PROXY_HEADERS: xforwarded
      KC_BOOTSTRAP_ADMIN_USERNAME: admin
      KC_BOOTSTRAP_ADMIN_PASSWORD: ${KC_ADMIN_PASS:?set KC_ADMIN_PASS in .env}
    ports:
      - "127.0.0.1:8080:8080"
    mem_limit: 2g
    healthcheck:
      test: ["CMD", "bash", "-c", "{ printf 'HEAD /health/ready HTTP/1.0\\r\\n\\r\\n' >&0; grep -q 'HTTP/1.0 200'; } 0<>/dev/tcp/localhost/9000"]
      interval: 30s
      retries: 5
      start_period: 90s

mem_limit: 2g is the line that matters, and there is deliberately no cpus: cap on Keycloak. The healthcheck uses bash’s /dev/tcp because the image ships without curl, as the health guide explains, and it targets management port 9000, which stays unpublished. If the proxy throws 403s or redirect loops, that is configuration rather than resources; Keycloak hostname and proxy errors walks through the fixes.

When does one box stop being enough?

When SSO downtime costs you more than a second machine does, not when CPU runs out. The production guide says “a typical production environment contains two or more Keycloak instances” so users can still log in when one goes down. For a homelab, a five-minute outage during an update is an acceptable price.

For reference, the sizing guide’s cluster example targets 45 logins and logouts, 360 client credential grants and 360 refresh requests per second. It lands on three pods with 3 vCPU requested and a 1360 MB memory limit each, plus a 2 or 4 vCPU database. If your traffic is nowhere near that, clustering buys you Infinispan, a load balancer and a shared database to babysit. That is more work than it is worth unless you wanted to learn it anyway.

If a 2 GB JVM feels heavy for what it protects, Keycloak vs authentik vs Authelia covers when a lighter tool fits better.

FAQ

can keycloak run on 1gb of ram

Yes, for a handful of users, but with no slack. Keycloak’s container guide says a memory limit of at least 750 MB approximates the old 512 MB heap default, so a 1 GB limit gives the JVM roughly 700 MB of heap. That sits below the documented 1250 MB baseline with full caches, so expect more database reads.

is keycloak too heavy for a homelab

Not on a mini-PC with 8 GB of RAM or more. Budget 2 GB for Keycloak and a modest slice for PostgreSQL, and there is room left for the rest of the stack. It is too heavy when you only need forward-auth in front of a few web apps on a small VPS, where a lighter tool fits better.

how many users can keycloak handle on one server

There is no fixed user ceiling, because Keycloak sizes by request rate rather than user count. The sizing guide’s test database held 1,000,000 users and 20,000 clients, and CPU was budgeted at 15 password logins per second per vCPU. Stored users cost database rows and cache entries, not CPU, until they log in.

how much disk space does keycloak need

Very little on the Keycloak side, because the container holds no state worth keeping; everything lives in PostgreSQL. Database size grows with users, clients, persisted sessions and, if you enable saving them, user and admin events. Keep the Postgres data directory on local SSD and back it up to the NAS nightly.

Sources

  1. Keycloak: Concepts for sizing CPU and memory resources
  2. Keycloak: Running Keycloak in a container
  3. Keycloak: Configuring the database
  4. Keycloak: Configuring Keycloak for production
  5. Keycloak: Configuring distributed caches
  6. Keycloak: Tracking instance status with health checks
  7. Intel Processor N100 specifications
#keycloak #capacity-planning #homelab #postgresql#docker-compose

Related