Keycloak Docker Setup Guide: Self-Host SSO and Auth That Actually Works
Auth is one of those things you don't want to get wrong — and you definitely don't want to build from scratch. Keycloak is the open-source identity and access management solution that gives you SSO, OAuth2, OpenID Connect, SAML, MFA, and fine-grained role management out of the box. This Keycloak Docker setup guide walks you through a complete deployment: from zero to a working SSO layer protecting your apps.
Prerequisites
Make sure you have the following before starting:
- A Linux server or local machine (Ubuntu 20.04+ recommended)
- Docker Engine installed and running
- Docker Compose v2
- At least 2GB RAM — Keycloak is a Java app and needs breathing room
- A domain name (optional for local testing, required for production)
- Ports 8080 (HTTP) and 8443 (HTTPS) available
Verify Docker is ready:
docker --version
docker compose version
sudo systemctl status docker
What Is Keycloak and When Should You Use It?
Keycloak is a battle-tested identity provider (IdP) maintained by Red Hat. It handles the full auth lifecycle so your apps don't have to.
What You Get Out of the Box
- Single Sign-On (SSO) — log in once, access everything
- OpenID Connect & OAuth2 — standard token-based auth for APIs and SPAs
- SAML 2.0 — enterprise federation support
- Social login — Google, GitHub, Facebook, and more via identity brokering
- MFA — TOTP, WebAuthn, SMS (with extensions)
- User federation — connect to LDAP or Active Directory
- Fine-grained roles and permissions via realm and client roles
If you're building a multi-app platform, an internal developer portal, or any product where users need a single identity across services — Keycloak is the right tool.
Deploying Keycloak with Docker Compose
Basic Setup with PostgreSQL
Keycloak's default H2 database is fine for testing but not production. Use PostgreSQL from the start. Create a project directory and add this Compose file:
# docker-compose.yml
version: '3.8'
services:
postgres:
image: postgres:15-alpine
container_name: keycloak_db
restart: always
environment:
POSTGRES_DB: keycloak
POSTGRES_USER: keycloak
POSTGRES_PASSWORD: strongpassword123
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- keycloak_net
keycloak:
image: quay.io/keycloak/keycloak:24.0
container_name: keycloak
restart: always
command: start-dev
environment:
KC_DB: postgres
KC_DB_URL: jdbc:postgresql://postgres:5432/keycloak
KC_DB_USERNAME: keycloak
KC_DB_PASSWORD: strongpassword123
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: adminpassword
KC_HTTP_ENABLED: "true"
KC_HOSTNAME_STRICT: "false"
ports:
- "8080:8080"
depends_on:
- postgres
networks:
- keycloak_net
volumes:
postgres_data:
networks:
keycloak_net:
Start everything:
docker compose up -d
docker compose logs -f keycloak
Wait for the line Keycloak 24.0 on JVM (powered by Quarkus) — that's your signal it's ready. Then open http://localhost:8080 and log in with your admin credentials.
Production Mode with HTTPS
For production, swap start-dev for start and provide TLS certificates. Update the Keycloak service command and environment:
keycloak:
image: quay.io/keycloak/keycloak:24.0
container_name: keycloak
restart: always
command: start
environment:
KC_DB: postgres
KC_DB_URL: jdbc:postgresql://postgres:5432/keycloak
KC_DB_USERNAME: keycloak
KC_DB_PASSWORD: strongpassword123
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: adminpassword
KC_HOSTNAME: auth.yourdomain.com
KC_HTTPS_CERTIFICATE_FILE: /opt/keycloak/conf/tls.crt
KC_HTTPS_CERTIFICATE_KEY_FILE: /opt/keycloak/conf/tls.key
volumes:
- ./certs/tls.crt:/opt/keycloak/conf/tls.crt:ro
- ./certs/tls.key:/opt/keycloak/conf/tls.key:ro
ports:
- "8443:8443"
If you're putting Keycloak behind an Nginx reverse proxy (covered below), you can keep HTTP internally and let Nginx handle TLS termination.
Configuring Realms, Clients, and Users
Creating a Realm
A realm is an isolated namespace — like a tenant. The master realm is for Keycloak administration only. Create a dedicated realm for your app:
- In the admin console, click the realm dropdown (top-left) → Create Realm
- Set a realm name (e.g.,
myapp) - Enable it and click Create
All users, clients, and roles for your app live inside this realm. Never put app users in the master realm.
Creating an OIDC Client
A client represents an application that will use Keycloak for auth. To create one:
- Inside your realm, go to Clients → Create Client
- Set Client type to
OpenID Connect - Set a Client ID (e.g.,
my-web-app) - Enable Client authentication if it's a confidential client (server-side app)
- Set Valid redirect URIs to your app's callback URL (e.g.,
https://myapp.com/callback)
After saving, go to the Credentials tab to grab your client secret.
Adding Users and Roles
Create a test user under Users → Add User. Set a temporary password under the Credentials tab. Then assign roles under Role Mapping — either realm-level or client-specific roles depending on your access model.
Putting Keycloak Behind Nginx
For a clean setup in production, run Keycloak on HTTP internally and let Nginx terminate TLS at the edge. Here's a working Nginx config:
server {
listen 80;
server_name auth.yourdomain.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name auth.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/auth.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/auth.yourdomain.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
}
}
The X-Forwarded-Proto https header is critical — without it Keycloak generates HTTP redirect URIs even when you're on HTTPS. Also update your Keycloak environment to trust the proxy:
KC_PROXY: edge
KC_HOSTNAME: auth.yourdomain.com
KC_HTTP_ENABLED: "true"
KC_HOSTNAME_STRICT: "false"
Reload Nginx and test:
sudo nginx -t && sudo systemctl reload nginx
curl -I https://auth.yourdomain.com/realms/myapp/.well-known/openid-configuration
A 200 response from the well-known endpoint confirms your OIDC discovery document is accessible — that's what your apps will use to auto-configure auth.
Connecting an App to Keycloak via OIDC
The Authorization Code Flow (Standard Web Apps)
For a server-side web app, the flow is: redirect user to Keycloak → user logs in → Keycloak redirects back with an auth code → your server exchanges the code for tokens. Here's the token exchange as a curl call for testing:
curl -s -X POST \
https://auth.yourdomain.com/realms/myapp/protocol/openid-connect/token \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'client_id=my-web-app' \
-d 'client_secret=YOUR_CLIENT_SECRET' \
-d 'grant_type=authorization_code' \
-d 'code=AUTH_CODE_HERE' \
-d 'redirect_uri=https://myapp.com/callback' | jq .
Using the Keycloak JS Adapter (SPAs)
For React, Vue, or plain JS frontends, use the official Keycloak JS adapter. Install it:
npm install keycloak-js
Then initialize it in your app entry point:
import Keycloak from 'keycloak-js';
const keycloak = new Keycloak({
url: 'https://auth.yourdomain.com',
realm: 'myapp',
clientId: 'my-spa-client'
});
keycloak.init({ onLoad: 'login-required' }).then(authenticated => {
if (authenticated) {
console.log('User is authenticated');
console.log('Token:', keycloak.token);
// Pass token in Authorization header for API calls
}
});
For SPAs, set the client to public (no secret) and use PKCE. In Keycloak client settings, set Client authentication to off and ensure Standard flow is enabled.
Tips, Gotchas, and Troubleshooting
Keycloak Takes Forever to Start
That's normal on first boot — it's running database migrations. Subsequent starts are faster. If it never starts, check memory: Keycloak needs at least 512MB, ideally 1–2GB. Check logs:
docker logs keycloak --tail 50 -f
Redirect URI Mismatch Error
This is the most common error when connecting an app. The redirect URI sent during login must exactly match one of the Valid redirect URIs configured in your client — including trailing slashes. Double-check both and use wildcards sparingly (never in production).
HTTPS Mixed Content / HTTP Redirect Loops
If Keycloak is generating HTTP URLs while your app is on HTTPS, ensure KC_PROXY: edge is set and Nginx is sending the X-Forwarded-Proto: https header. Restart Keycloak after any environment change.
Forgot Admin Password
Reset it via CLI inside the running container:
docker exec -it keycloak /opt/keycloak/bin/kcadm.sh \
set-password \
--server http://localhost:8080 \
--realm master \
--user admin \
--new-password newpassword123
Updating Keycloak
Stop, pull, and restart — your data is in the PostgreSQL volume and survives updates:
docker compose down
docker pull quay.io/keycloak/keycloak:latest
# Update the image tag in docker-compose.yml, then:
docker compose up -d
Pro Tips
- Export realm configs as JSON and commit them to version control. Go to Realm Settings → Action → Partial Export.
- Use realm roles for coarse-grained access and client roles for app-specific permissions. Keep them separate.
- Enable brute force protection under Realm Settings → Security Defenses to automatically lock accounts after failed login attempts.
- Set token lifespans appropriately — short-lived access tokens (5 min) with longer refresh tokens (30 min) is a solid default for most apps.
- Use the Keycloak Admin REST API for automation — every action in the UI is available as an API call, making it easy to script realm setup in CI/CD.
Wrapping Up
A solid Keycloak Docker setup gives you enterprise-grade auth infrastructure that you fully control. You get SSO, OIDC, SAML, MFA, and role-based access — without paying per-user SaaS fees or handing your user data to a third party.
Start with the Docker Compose stack, wire up one client, and get comfortable with realms and roles. Then layer in social login, user federation, and token customization as your platform grows. The learning curve is real but the payoff — one auth layer for all your apps — is worth it.
Need Help Deploying Auth at Scale?
Setting up Keycloak for a production platform with high availability, LDAP federation, or multi-tenant architecture takes experience. The sysbrix team has done it — and we can help you do it right, fast, without the trial-and-error overhead.
Talk to Us →