How to Self-Host Keycloak with Docker
What Is Keycloak?
Keycloak is an open-source identity and access management platform maintained by Red Hat. It provides SSO, OIDC, SAML 2.0, LDAP/AD user federation, social login, multi-factor authentication, and fine-grained authorization — all through a comprehensive admin console. It’s the most battle-tested self-hosted identity provider, widely used in enterprise environments. Keycloak replaces cloud identity services like Okta, Auth0, Azure AD, and AWS Cognito.
Updated March 2026: Verified with latest Docker images and configurations.
Prerequisites
- A Linux server (Ubuntu 22.04+ recommended)
- Docker and Docker Compose installed (guide)
- 2 GB of free RAM minimum (Keycloak is a Java application — 4 GB recommended for production)
- 1 GB of free disk space
- A domain name with HTTPS configured
- A reverse proxy with SSL (guide)
Docker Compose Configuration
Create a project directory:
mkdir -p /opt/keycloak && cd /opt/keycloak
Create a docker-compose.yml file:
services:
keycloak:
image: quay.io/keycloak/keycloak:26.5.6
container_name: keycloak
restart: unless-stopped
command: start --optimized
environment:
# Admin credentials — change these immediately after first login
KC_BOOTSTRAP_ADMIN_USERNAME: admin
KC_BOOTSTRAP_ADMIN_PASSWORD: changeme-use-strong-password
# Database connection
KC_DB: postgres
KC_DB_URL: jdbc:postgresql://keycloak-db:5432/keycloak
KC_DB_USERNAME: keycloak
KC_DB_PASSWORD: changeme-db-password
# Hostname — set to your actual domain
KC_HOSTNAME: auth.example.com
# Proxy settings — required when behind a reverse proxy
KC_PROXY_HEADERS: xforwarded
KC_HTTP_ENABLED: "true"
# Health and metrics
KC_HEALTH_ENABLED: "true"
KC_METRICS_ENABLED: "true"
ports:
- "8080:8080" # HTTP
- "9000:9000" # Health/metrics
volumes:
- keycloak-import:/opt/keycloak/data/import
depends_on:
keycloak-db:
condition: service_healthy
networks:
- keycloak-net
deploy:
resources:
limits:
memory: 2G
keycloak-db:
image: postgres:16-alpine
container_name: keycloak-db
restart: unless-stopped
environment:
POSTGRES_DB: keycloak
POSTGRES_USER: keycloak
POSTGRES_PASSWORD: changeme-db-password
volumes:
- keycloak-db-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U keycloak"]
interval: 10s
timeout: 5s
retries: 5
networks:
- keycloak-net
volumes:
keycloak-db-data:
keycloak-import:
networks:
keycloak-net:
Start the stack:
docker compose up -d
Keycloak takes 30-60 seconds to start (Java startup time). Monitor the logs:
docker compose logs -f keycloak
Wait for Listening on: http://0.0.0.0:8080 before accessing the UI.
Initial Setup
- Open
http://your-server-ip:8080(or your domain if reverse proxy is configured) - Log in with the admin credentials from
KC_BOOTSTRAP_ADMIN_USERNAME/KC_BOOTSTRAP_ADMIN_PASSWORD - You’re now in the master realm admin console
- Create a new realm for your applications (don’t use the master realm for app users):
- Click the realm dropdown (top-left) → Create realm
- Name it something like
homelaborselfhosted
- Change the admin password immediately: Users → select admin → Credentials → Reset password
Configuration
Creating a Realm
Realms are isolated tenant environments. Create one realm for your self-hosted apps:
- Realm settings → General → set display name
- Realm settings → Login → enable “User registration” if you want self-registration
- Realm settings → Email → configure SMTP for password reset and verification emails
Registering an Application (Client)
For each self-hosted app that supports OIDC:
- Clients → Create client
- Client type: OpenID Connect
- Client ID: e.g.,
nextcloud,portainer,grafana - Valid redirect URIs:
https://app.example.com/callback(check your app’s docs for the exact callback path) - Client authentication: On (for confidential clients)
- Copy the Client secret from the Credentials tab
Adding Users
- Users → Add user
- Fill in username, email, first/last name
- Credentials tab → Set password (toggle off “Temporary” if you don’t want forced reset)
Enabling Two-Factor Authentication
- Authentication → Flows → browser
- The default flow already includes OTP as optional
- To make it required: set “OTP Form” to Required
- Users will be prompted to configure TOTP on next login
Advanced Configuration
LDAP/Active Directory Federation
Keycloak can federate users from existing LDAP or Active Directory:
- User federation → Add LDAP provider
- Configure connection URL, bind DN, and search base
- Keycloak imports users on first login or via periodic sync
Social Login
Add Google, GitHub, GitLab, or other social login providers:
- Identity providers → Add provider
- Select the provider (Google, GitHub, etc.)
- Enter client ID and secret from the provider’s developer console
- Keycloak automatically handles the OAuth flow
Custom Themes
Mount custom themes to override the login page appearance:
volumes:
- ./themes:/opt/keycloak/themes
Realm Export/Import
Export your realm configuration for backup or migration:
docker compose exec keycloak /opt/keycloak/bin/kc.sh export --dir /opt/keycloak/data/import --realm homelab
Import on startup by adding --import-realm to the command:
command: start --optimized --import-realm
Reverse Proxy
Keycloak requires specific reverse proxy configuration. For Nginx Proxy Manager or Caddy, point to port 8080 and ensure these headers are forwarded:
X-Forwarded-ForX-Forwarded-ProtoX-Forwarded-Host
The KC_PROXY_HEADERS: xforwarded setting tells Keycloak to trust these headers.
For Caddy:
auth.example.com {
reverse_proxy keycloak:8080
}
For more reverse proxy options, see our Reverse Proxy Setup guide.
Backup
Back up these components:
- PostgreSQL database — contains all users, realms, clients, and configuration:
docker compose exec keycloak-db pg_dump -U keycloak keycloak > keycloak-backup.sql - Import volume — if you store realm exports there
- Custom themes — if mounted
Restore the database:
docker compose exec -T keycloak-db psql -U keycloak keycloak < keycloak-backup.sql
For a comprehensive backup strategy, see Backup Strategy.
Troubleshooting
Keycloak won’t start — “Failed to obtain JDBC connection”
Symptom: Keycloak exits immediately with database connection errors.
Fix: Ensure the PostgreSQL container is healthy before Keycloak starts. The depends_on with condition: service_healthy in the Compose file handles this. If it persists, verify KC_DB_URL, KC_DB_USERNAME, and KC_DB_PASSWORD match the PostgreSQL configuration exactly.
”Invalid redirect URI” when logging into an app
Symptom: After entering credentials, you see “Invalid redirect URI” instead of being redirected to the app.
Fix: In the client settings, ensure the Valid redirect URIs field exactly matches the callback URL your app sends. Include the protocol (https://) and path. Use * only for development.
Admin console loads but shows blank page
Symptom: The admin URL responds but the UI doesn’t render.
Fix: This typically happens when KC_HOSTNAME doesn’t match the URL you’re accessing. Set KC_HOSTNAME to the exact domain you use in the browser.
High memory usage
Symptom: Keycloak consumes all available memory.
Fix: Keycloak uses -XX:MaxRAMPercentage=70 by default, meaning it’ll use up to 70% of the container’s memory limit. Always set a deploy.resources.limits.memory in your Compose file. 2 GB is the minimum; 4 GB is comfortable for a homelab with <100 users.
Slow startup time
Symptom: Keycloak takes 2+ minutes to become available.
Fix: This is normal for the first start when using start mode (production). Keycloak optimizes itself on first boot. Subsequent restarts are faster. If you need faster dev iteration, use start-dev temporarily (never in production).
Resource Requirements
- RAM: 512 MB minimum, 1-2 GB typical, 4 GB recommended for production
- CPU: Medium — Java-based, uses noticeable CPU during startup and under load
- Disk: 200 MB for the application, plus PostgreSQL data (grows with user count)
Verdict
Keycloak is the gold standard for self-hosted identity management. If you need a full-featured identity provider with SAML, LDAP federation, fine-grained authorization, and enterprise-grade reliability, Keycloak is the answer. It’s heavier than Authelia (which just does forward-auth SSO) and more complex than Authentik (which has a friendlier UI), but no other self-hosted IdP matches its protocol support and maturity. Choose Keycloak when you need the full enterprise feature set. Choose Authelia if you just want SSO + 2FA for your reverse proxy. Choose Authentik if you want a middle ground with a better UI.
FAQ
How does Keycloak compare to Authelia?
Different tools for different jobs. Authelia is a lightweight forward-auth proxy that adds SSO and 2FA to services behind a reverse proxy. Keycloak is a full identity provider with OIDC, SAML, LDAP federation, and user management. Use Authelia for simple homelab auth. Use Keycloak when apps need OIDC/SAML integration. See our Authelia vs Keycloak comparison.
How does Keycloak compare to Authentik?
Both are full identity providers. Authentik has a more modern UI and visual flow designer. Keycloak has broader protocol support (SAML is more mature), enterprise features, and a larger ecosystem. See our Authentik vs Keycloak comparison.
Can I use Keycloak with Nextcloud, Grafana, and Portainer?
Yes. All three support OIDC. Create a client in Keycloak for each app, configure the redirect URIs, and enter the client ID/secret in each app’s SSO settings. This gives you single sign-on across all your self-hosted services.
Is Keycloak overkill for a homelab?
For most homelabs with <10 services, yes — Authelia or Authentik are simpler choices. Keycloak makes sense when you need SAML support, LDAP federation, or manage 10+ applications with complex access policies.
Related
Get self-hosting tips in your inbox
Get the Docker Compose configs, hardware picks, and setup shortcuts we don't put in articles. Weekly. No spam.
Comments