Keycloak
Keycloak gives your applications one login: they redirect to it, it authenticates the user, and hands back a token the application trusts. It speaks OpenID Connect and SAML, federates users from LDAP and Active Directory, and manages realms, clients, roles and users in an admin console. Two containers: the server and PostgreSQL.
Last run on a host 8 Nov 2026
Pinned at 26.8.2 (released 5 Nov 2026) · the newest upstream release
In the upstream images: 1 CRITICAL · 26 HIGH with a published fix — per image
To try it: Docker, nothing else. See Try it locally.
To deploy it behind the proxy: Traefik running and a domain.
Try it locally
Section titled “Try it locally”On your own machine, with no proxy, domain or certificate. From
core/keycloak/:
cp .env.local.example .env.local
# The secrets ship empty; generate the ones this stack needs{ echo "DB_PASSWORD=$(openssl rand -hex 32)" echo "BOOTSTRAP_ADMIN_PASSWORD=$(openssl rand -base64 24 | tr -d '\n')"} >> .env.local
mkdir -p volumes/local/postgres volumes/local/datasudo chown 1000:0 volumes/local/data
docker compose -p keycloak-local -f docker-compose.local.yml --env-file .env.local up -dThe first start takes about 30 seconds. Open http://localhost:8080/admin and
sign in as the bootstrap administrator. The explicit project name in the
command keeps this apart from a production stack in the same directory.
Installation
Section titled “Installation”For a deployment on a server. From core/keycloak/:
-
Copy the environment file and set
APP_TRAEFIK_HOSTandTZ:Terminal window cp .env.example .envThe hostname is the issuer. Every token names it, and Keycloak refuses requests for any other host.
-
Generate the secrets and the data directory:
Terminal window mkdir -p .secrets volumes/postgres volumes/dataopenssl rand -hex 32 | tr -d '\n' > .secrets/db_pwd.txtopenssl rand -base64 24 | tr -d '\n' > .secrets/bootstrap_admin_pwd.txtchmod 700 .secrets && chmod 600 .secrets/*.txtsudo chown 1000:0 volumes/data -
Start it:
Terminal window docker compose up -d -
Open
https://<APP_TRAEFIK_HOST>/adminand sign in astemp-adminwith the password from step 2. Create a permanent administrator in the master realm, sign in as that user, and delete the temporary one. -
Create a realm for your applications. The master realm administers Keycloak itself.
Verify
Section titled “Verify”docker compose ps # both healthycurl -fsS https://<APP_TRAEFIK_HOST>/realms/master/.well-known/openid-configuration | grep -o '"issuer":"[^"]*"'The issuer must be https://<APP_TRAEFIK_HOST>/realms/master. A different
scheme or host means Traefik’s forwarded headers are not reaching the server.
Connecting an application
Section titled “Connecting an application”In your realm, Clients → Create client: OpenID Connect, the application’s
redirect URI, client authentication on. The application gets three values —
the issuer URL https://<APP_TRAEFIK_HOST>/realms/<realm>, the client ID and
the secret — and reads everything else from the discovery document.
That is the whole integration, and also its limit: Keycloak has no proxy of its own. An application that speaks neither OpenID Connect nor SAML cannot be put behind it with what this stack ships. This blueprint also ships Authentik for the same role — for a side-by-side on containers, memory, federation and ecosystem, see Choosing between services → Single sign-on.
Backup
Section titled “Backup”The database holds everything: realms, clients, users, sessions.
volumes/data is staging for imports and exports and is otherwise empty.
Restore the database, then start the container — it migrates the schema at
boot and refuses a schema newer than itself. kc.sh export gives a
realm-level JSON as a second, portable copy; the README has the borgmatic
block.
Updates
Section titled “Updates”-
Read the release notes and the upgrading guide. A minor release may migrate the schema and rename options.
-
Back up the database, then raise
APP_TAGin.envand:Terminal window docker compose pull && docker compose up -ddocker compose logs keycloak-app | grep -E 'started in|Migrat' -
Sign in, and let one application authenticate.
Troubleshooting
Section titled “Troubleshooting”The container exits and the log ends with no password was provided. A
KC_*_FILE variable was used. Keycloak accepts them into its configuration
and ignores them; the entrypoint wrapper is how the passwords arrive.
The discovery document shows http:// or the wrong host. The server is
not receiving X-Forwarded-Proto and X-Forwarded-Host. Through Traefik
they are always present; through anything else, set the same headers.
The admin console stops at “Timeout when waiting for 3rd party check
iframe message”. The browser console adds that the page refused to load in
a frame because X-Frame-Options is deny. The console frames its cookie
check from its own origin, and Keycloak sets the frame headers itself. The
stack therefore ships headers-application-owned: the proxy sets the HSTS
base only, and Keycloak’s own headers reach the browser; the one it lacks,
Permissions-Policy, is the header-permissions@file block the compose file
places before the profile. If the message appears, the router’s
APP_TRAEFIK_HEADERS has been set to headers-standard, whose DENY
overwrites Keycloak’s header on every page.
/health/ready is DOWN for a minute after start. The rebuild at every
boot takes that long. The healthcheck allows 90 seconds.
The container exits with Read-only file system. read_only: true was
added. The official image writes to its own lib/quarkus at start and
cannot run that way.
Repository files
Section titled “Repository files”core/keycloak/README.md— setup, security model, the comparison, backupcore/keycloak/UPSTREAM.md— source, licence, upgrade checklist
Official sources
Section titled “Official sources”© 2026 SecDockBlueCode Apache-2.0Site content CC BY-NC 4.0