Self-Hosting Guide: Deploy Keycloak for Authentication
·OSSAlt Team
keycloakauthenticationself-hostingdockerguide
Self-Hosting Guide: Deploy Keycloak for Authentication
Keycloak is the most battle-tested open source identity platform. It replaces Auth0, Okta, and Azure AD — providing SSO, OIDC, SAML, LDAP, and social login for all your applications.
Requirements
- VPS with 2 GB RAM minimum (4 GB recommended)
- Docker and Docker Compose
- Domain name (e.g.,
auth.yourdomain.com) - 10+ GB disk
Step 1: Create Docker Compose
# docker-compose.yml
services:
keycloak:
image: quay.io/keycloak/keycloak:latest
container_name: keycloak
restart: unless-stopped
ports:
- "8080:8080"
environment:
- KC_DB=postgres
- KC_DB_URL_HOST=db
- KC_DB_URL_DATABASE=keycloak
- KC_DB_USERNAME=keycloak
- KC_DB_PASSWORD=your-strong-password
- KC_HOSTNAME=auth.yourdomain.com
- KC_PROXY_HEADERS=xforwarded
- KC_HTTP_ENABLED=true
- KEYCLOAK_ADMIN=admin
- KEYCLOAK_ADMIN_PASSWORD=your-admin-password
command: start
depends_on:
- db
db:
image: postgres:16-alpine
container_name: keycloak-db
restart: unless-stopped
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
- POSTGRES_DB=keycloak
- POSTGRES_USER=keycloak
- POSTGRES_PASSWORD=your-strong-password
volumes:
postgres_data:
Step 2: Start Keycloak
docker compose up -d
Step 3: Reverse Proxy (Caddy)
# /etc/caddy/Caddyfile
auth.yourdomain.com {
reverse_proxy localhost:8080
}
sudo systemctl restart caddy
Step 4: Initial Configuration
- Open
https://auth.yourdomain.com - Login with admin credentials
- Create a new realm (don't use the master realm for applications)
Recommended realm setup:
- Click Create Realm
- Name it (e.g.,
mycompany) - Enable it
Step 5: Configure a Client (Your Application)
- Go to your realm → Clients → Create client
- Client type: OpenID Connect
- Client ID:
my-app - Client authentication: On (for server-side apps) / Off (for SPAs)
- Valid redirect URIs:
https://myapp.com/callback - Web origins:
https://myapp.com
Save and note the client secret from the Credentials tab.
Step 6: Add Social Login Providers
Go to Identity Providers:
| Provider | Configuration |
|---|---|
| Client ID + Secret from Google Cloud Console | |
| GitHub | Client ID + Secret from GitHub OAuth Apps |
| Microsoft | Client ID + Secret from Azure App Registration |
| Apple | Service ID + Key from Apple Developer Portal |
Step 7: Integrate with Your App
Next.js (with NextAuth.js):
// app/api/auth/[...nextauth]/route.js
import NextAuth from 'next-auth'
import KeycloakProvider from 'next-auth/providers/keycloak'
export const authOptions = {
providers: [
KeycloakProvider({
clientId: 'my-app',
clientSecret: 'your-client-secret',
issuer: 'https://auth.yourdomain.com/realms/mycompany',
}),
],
}
const handler = NextAuth(authOptions)
export { handler as GET, handler as POST }
React SPA (with keycloak-js):
import Keycloak from 'keycloak-js'
const keycloak = new Keycloak({
url: 'https://auth.yourdomain.com',
realm: 'mycompany',
clientId: 'my-spa',
})
await keycloak.init({ onLoad: 'login-required' })
console.log('Authenticated:', keycloak.authenticated)
console.log('Token:', keycloak.token)
Any OIDC-compatible app:
Issuer URL: https://auth.yourdomain.com/realms/mycompany
Auth URL: https://auth.yourdomain.com/realms/mycompany/protocol/openid-connect/auth
Token URL: https://auth.yourdomain.com/realms/mycompany/protocol/openid-connect/token
Userinfo URL: https://auth.yourdomain.com/realms/mycompany/protocol/openid-connect/userinfo
Step 8: User Management
Create users manually:
- Users → Add user
- Set username, email, first/last name
- Credentials tab → set password
LDAP integration:
- User Federation → Add LDAP provider
- Configure connection URL, bind DN, user DN
- Sync users on demand or schedule
Self-registration:
- Realm Settings → Login tab
- Enable User registration
Step 9: Configure Email
Go to Realm Settings → Email:
| Setting | Value |
|---|---|
| Host | smtp.resend.com |
| Port | 587 |
| From | auth@yourdomain.com |
| Enable StartTLS | ✅ |
| Username | resend |
| Password | re_your_api_key |
Required for password reset, email verification, and account notifications.
Step 10: Security Settings
Brute force protection:
- Realm Settings → Security Defenses
- Enable brute force detection
- Set max login failures (e.g., 5)
- Set lockout duration (e.g., 15 minutes)
Password policies:
- Authentication → Policies → Password Policy
- Add: length(8), digits(1), upperCase(1), specialChars(1)
MFA/2FA:
- Authentication → Flows
- Set OTP as required or conditional for browser flow
Production Hardening
Performance tuning:
environment:
- KC_CACHE=ispn
- KC_CACHE_STACK=kubernetes # For clustered deployments
- JAVA_OPTS_KC_HEAP=-Xms512m -Xmx1024m
Backups:
# Database backup (daily cron)
docker exec keycloak-db pg_dump -U keycloak keycloak > /backups/keycloak-$(date +%Y%m%d).sql
# Export realm configuration
docker exec keycloak /opt/keycloak/bin/kc.sh export \
--dir /opt/keycloak/data/export \
--realm mycompany
docker cp keycloak:/opt/keycloak/data/export /backups/keycloak-realm-$(date +%Y%m%d)
Updates:
docker compose pull
docker compose up -d
Monitoring:
- Enable health endpoint:
KC_HEALTH_ENABLED=true - Monitor
/health/readyand/health/live - Track login failures and token issuance rates
Resource Usage
| Users | RAM | CPU | Disk |
|---|---|---|---|
| 1-500 | 2 GB | 2 cores | 10 GB |
| 500-5K | 4 GB | 4 cores | 20 GB |
| 5K-50K | 8 GB | 8 cores | 50 GB |
VPS Recommendations
| Provider | Spec (1K users) | Price |
|---|---|---|
| Hetzner | 4 vCPU, 8 GB RAM | €8/month |
| DigitalOcean | 2 vCPU, 4 GB RAM | $24/month |
| Linode | 2 vCPU, 4 GB RAM | $24/month |
Compare authentication platforms on OSSAlt — protocols, features, and pricing side by side.