Setup


https://www.keycloak.org/server/containers
https://www.keycloak.org/server/configuration-production
https://www.keycloak.org/server/db
https://www.keycloak.org/server/hostname
https://www.keycloak.org/server/reverseproxy
https://www.keycloak.org/operator/installation
https://www.keycloak.org/operator/basic-deployment

1. Linux VM With systemd#

VM 部署适合小规模、传统网络、没有 Kubernetes 的环境。生产上仍然要使用 external PostgreSQL、HTTPS、反向代理和系统级监控。

layout:
    /opt/keycloak
    /etc/keycloak/keycloak.conf
    /var/log/keycloak
    /etc/keycloak/tls

Example config:

hostname=sso.example.com
http-enabled=false
https-certificate-file=/etc/keycloak/tls/tls.crt
https-certificate-key-file=/etc/keycloak/tls/tls.key

db=postgres
db-url=jdbc:postgresql://postgres.example.com:5432/keycloak
db-username=keycloak
db-password=${KC_DB_PASSWORD}

health-enabled=true
metrics-enabled=true
proxy-headers=xforwarded

systemd unit:

[Unit]
Description=Keycloak
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=keycloak
Group=keycloak
EnvironmentFile=/etc/keycloak/keycloak.env
WorkingDirectory=/opt/keycloak
ExecStart=/opt/keycloak/bin/kc.sh start --config-file=/etc/keycloak/keycloak.conf
Restart=on-failure
RestartSec=10
LimitNOFILE=65535

[Install]
WantedBy=multi-user.target

operations:

sudo systemctl daemon-reload
sudo systemctl enable --now keycloak
sudo systemctl status keycloak
journalctl -u keycloak -f

2. Docker#

Docker local dev:

docker run --name keycloak-demo --rm \
  -p 8080:8080 \
  -e KC_BOOTSTRAP_ADMIN_USERNAME=admin \
  -e KC_BOOTSTRAP_ADMIN_PASSWORD=change_me_now \
  quay.io/keycloak/keycloak:latest \
  start-dev

Production-like compose:

services:
  postgres:
    image: postgres:16
    environment:
      POSTGRES_DB: keycloak
      POSTGRES_USER: keycloak
      POSTGRES_PASSWORD: change_me_db
    volumes:
      - postgres-data:/var/lib/postgresql/data

  keycloak:
    image: quay.io/keycloak/keycloak:latest
    command:
      - start
    environment:
      KC_HOSTNAME: sso.example.com
      KC_PROXY_HEADERS: xforwarded
      KC_HTTP_ENABLED: "true"
      KC_DB: postgres
      KC_DB_URL: jdbc:postgresql://postgres:5432/keycloak
      KC_DB_USERNAME: keycloak
      KC_DB_PASSWORD: change_me_db
      KC_HEALTH_ENABLED: "true"
      KC_METRICS_ENABLED: "true"
      KC_BOOTSTRAP_ADMIN_USERNAME: admin
      KC_BOOTSTRAP_ADMIN_PASSWORD: change_me_now
    depends_on:
      - postgres
    ports:
      - "8080:8080"

volumes:
  postgres-data:

notes:

for production:
    do not use start-dev
    use managed PostgreSQL or HA PostgreSQL
    put TLS at load balancer or Keycloak
    use secrets instead of plaintext compose env
    pin image version, do not blindly use latest

3. K8S With Operator#

Keycloak has an official Operator. For production Kubernetes, prefer OLM with manual approval, or a carefully governed GitOps manifest. Community Helm charts can be useful, but treat them as third-party packaging and review upgrade behavior.

OLM baseline:

recommended:
    install Keycloak Operator through OLM
    use manual approval for Operator upgrades
    test Keycloak and Operator upgrades in staging first
    backup database before approving production upgrade

Operator install without OLM:

kubectl create namespace keycloak
kubectl apply -f https://raw.githubusercontent.com/keycloak/keycloak-k8s-resources/26.6.3/kubernetes/keycloaks.k8s.keycloak.org-v1.yml
kubectl apply -f https://raw.githubusercontent.com/keycloak/keycloak-k8s-resources/26.6.3/kubernetes/keycloakrealmimports.k8s.keycloak.org-v1.yml
kubectl -n keycloak apply -f https://raw.githubusercontent.com/keycloak/keycloak-k8s-resources/26.6.3/kubernetes/kubernetes.yml

Minimal Keycloak CR:

apiVersion: k8s.keycloak.org/v2alpha1
kind: Keycloak
metadata:
  name: keycloak
  namespace: keycloak
spec:
  instances: 3
  db:
    vendor: postgres
    host: postgres.example.com
    database: keycloak
    usernameSecret:
      name: keycloak-db
      key: username
    passwordSecret:
      name: keycloak-db
      key: password
  hostname:
    hostname: sso.example.com
  http:
    tlsSecret: keycloak-tls
  additionalOptions:
    - name: health-enabled
      value: "true"
    - name: metrics-enabled
      value: "true"

Verify:

kubectl -n keycloak get pods
kubectl -n keycloak get keycloak
kubectl -n keycloak logs deploy/keycloak -f
kubectl -n keycloak describe keycloak keycloak

Network policy baseline:

allow ingress:
    from ingress controller namespace to Keycloak HTTP/HTTPS port

allow egress:
    to PostgreSQL
    to external LDAP / AD if User Federation is used
    to upstream IdP metadata / JWKS endpoints
    to SMTP if email is used

deny:
    random namespace to admin endpoint

4. High Availability#

HA requirements:
    at least 2-3 Keycloak replicas
    external HA PostgreSQL
    shared hostname behind load balancer
    sticky sessions can help, but do not rely on a single pod
    readiness probe and rolling update configured
    DB connection pool sized for replicas

Capacity starting point:

estimate:
    peak login requests per minute
    token refresh rate
    admin/API automation rate
    number of apps / clients
    external LDAP / AD lookup latency if User Federation is used

scale:
    increase replicas for stateless HTTP pressure
    increase DB capacity for session/event/write pressure
    tune cache and DB pool only after metrics show bottleneck

Backup:

must backup:
    PostgreSQL database
    Keycloak signing keys
    custom themes
    realm config export
    secret manager entries

restore test:
    restore DB snapshot into isolated environment
    start Keycloak with same version
    verify admin login
    verify OIDC discovery
    verify one OIDC app and one SAML app

5. Operations#

Rolling restart:

kubectl -n keycloak rollout restart deployment/keycloak
kubectl -n keycloak rollout status deployment/keycloak

Useful checks:

curl -fsS https://sso.example.com/health/ready
curl -fsS https://sso.example.com/metrics
curl -fsS https://sso.example.com/realms/master/.well-known/openid-configuration

Upgrade checklist:

before:
    read Keycloak release notes
    backup database
    export realm config
    test upgrade in staging

during:
    upgrade one environment at a time
    watch logs, HTTP 5xx, DB pool, login errors
    verify OIDC, SAML, LDAP federation, admin console

rollback:
    rollback container/version only if DB schema is compatible
    otherwise restore DB snapshot into previous version
    keep version-specific runbook for major upgrades

Common diagnostics:

kubectl -n keycloak get pods -o wide
kubectl -n keycloak describe pod <pod>
kubectl -n keycloak logs <pod> --previous
kubectl -n keycloak top pod
kubectl -n keycloak get events --sort-by=.lastTimestamp