Tired of managing separate logins for every self-hosted service? Keycloak gives you enterprise-grade Single Sign-On (SSO) for your entire homelab — free, open-source, and under your control.
Why Self-Host Keycloak?
If you're running more than a handful of services, you've felt the pain: different passwords for Grafana, Portainer, Nextcloud, and every other tool. Password managers help, but they don't solve the real problem — identity sprawl.
Keycloak is an open-source Identity and Access Management (IAM) solution that centralizes authentication across all your services. One login. One password. One place to manage users, roles, and security policies.
What you get:
- Single Sign-On (SSO) — Log in once, access everything
- OIDC & SAML support — Works with virtually any modern application
- Two-Factor Authentication (2FA) — TOTP, WebAuthn, and more built-in
- User Federation — Connect to existing LDAP or Active Directory
- Social Login — Google, GitHub, GitLab as identity providers
- Fine-grained Authorization — Role-based access control (RBAC)
Unlike cloud identity providers, you own your data. No third-party dependencies, no subscription fees, no vendor lock-in.
Prerequisites
- A VPS or server with 2+ CPU cores, 2GB+ RAM (Keycloak is Java-based and memory-hungry)
- Docker and Docker Compose installed
- A domain name pointed to your server (for HTTPS)
- Reverse proxy like Traefik or Nginx (recommended for production)
Step 1: Create the Docker Compose File
Create a directory for Keycloak and a docker-compose.yml file:
version: '3.8'
services:
keycloak:
image: quay.io/keycloak/keycloak:24.0
container_name: keycloak
command: start-dev
environment:
KC_HOSTNAME: auth.yourdomain.com
KC_HOSTNAME_STRICT_BACKCHANNEL: "true"
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: your-secure-admin-password
KC_DB: postgres
KC_DB_URL: jdbc:postgresql://postgres:5432/keycloak
KC_DB_USERNAME: keycloak
KC_DB_PASSWORD: keycloak-db-password
ports:
- "8080:8080"
depends_on:
postgres:
condition: service_healthy
restart: unless-stopped
networks:
- keycloak-network
postgres:
image: postgres:16-alpine
container_name: keycloak-postgres
environment:
POSTGRES_DB: keycloak
POSTGRES_USER: keycloak
POSTGRES_PASSWORD: keycloak-db-password
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U keycloak"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
networks:
- keycloak-network
volumes:
postgres_data:
networks:
keycloak-network:
driver: bridge
Important: Replace auth.yourdomain.com, your-secure-admin-password, and keycloak-db-password with your actual values.
Step 2: Start Keycloak
Launch the stack:
docker compose up -d
Wait 30-60 seconds for Keycloak to initialize. Check logs if needed:
docker logs -f keycloak
You should see Listening on: http://0.0.0.0:8080 when ready.
Step 3: Initial Setup
- Open
http://your-server-ip:8080in your browser - Click Administration Console
- Log in with
admin/ your admin password
You'll land in the master realm. Important: Create a dedicated realm for your applications instead of using master:
- Hover over the realm dropdown (top-left) → Click Create Realm
- Name it
homelab(or whatever you prefer) - Click Create
Step 4: Configure Your First Client
A "client" in Keycloak represents an application that will use it for authentication. Let's set up Grafana as an example:
- In your realm, go to Clients → Create client
- Client ID:
grafana - Client authentication: On (confidential)
- Authentication flow: Enable Standard flow (authorization code)
- Valid redirect URIs:
https://grafana.yourdomain.com/login/generic_oauth - Save, then go to the Credentials tab and copy the Client Secret
Now configure Grafana's docker-compose.yml:
environment:
GF_AUTH_GENERIC_OAUTH_ENABLED: "true"
GF_AUTH_GENERIC_OAUTH_NAME: Keycloak
GF_AUTH_GENERIC_OAUTH_CLIENT_ID: grafana
GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET: your-client-secret-here
GF_AUTH_GENERIC_OAUTH_SCOPES: openid email profile
GF_AUTH_GENERIC_OAUTH_AUTH_URL: https://auth.yourdomain.com/realms/homelab/protocol/openid-connect/auth
GF_AUTH_GENERIC_OAUTH_TOKEN_URL: https://auth.yourdomain.com/realms/homelab/protocol/openid-connect/token
GF_AUTH_GENERIC_OAUTH_API_URL: https://auth.yourdomain.com/realms/homelab/protocol/openid-connect/userinfo
GF_AUTH_GENERIC_OAUTH_ALLOW_SIGN_UP: "true"
Restart Grafana. You'll now see a "Sign in with Keycloak" button on the login page.
Step 5: Add Users
- Go to Users → Add user
- Username:
ali(or your preferred username) - Email: your email
- Save, then go to the Credentials tab
- Set a password (disable "Temporary" if you want it permanent)
The user can now log in to any configured client with these credentials.
Step 6: Enable Two-Factor Authentication (Optional but Recommended)
- Go to Authentication → Required Actions
- Enable Configure OTP as a default action
Now every user will be prompted to set up TOTP (Google Authenticator, Authy, etc.) on first login.
Production Hardening
The setup above uses start-dev mode. For production:
- Use a reverse proxy (Traefik/Nginx) with HTTPS — Keycloak requires secure connections in production
- Switch to
startmode and configure TLS certificates - Enable production database — PostgreSQL (included above) is recommended over the default H2
- Configure email — Go to Realm Settings → Email for password resets and notifications
- Set up backups — Export your realm regularly:
docker exec keycloak /opt/keycloak/bin/kc.sh export --dir /tmp/export
Verification Checklist
- ✅ Keycloak admin console accessible at your domain
- ✅ Dedicated realm created (not using
master) - ✅ Test user can log in to admin console
- ✅ Grafana (or another client) shows "Sign in with Keycloak"
- ✅ OAuth redirect works end-to-end
- ✅ 2FA prompt appears if configured
Next Steps
- Add more clients — Portainer, Nextcloud, MinIO, and most modern apps support OIDC
- Social login — Connect Google/GitHub under Identity Providers
- Groups & roles — Map Keycloak groups to application roles for fine-grained access
- LDAP federation — If you have an existing directory, sync users instead of recreating them
Related Guides
- Self-Host Authentik: Your Own Identity Provider in 20 Minutes
- Self-Host Authelia: Add Two-Factor Authentication to Any Service in 15 Minutes
- Self-Host Traefik: The Ultimate Reverse Proxy for Your Homelab in 20 Minutes
Centralized identity isn't just convenient — it's a security upgrade. One strong password with 2FA beats a dozen weak ones scattered across services. Your future self will thank you.