Mega Guide: How to Deploy Keycloak in a Cluster with Nginx in 10 Minutes!

Mi Do
9 min readFeb 4, 2025

If you have any questions — you can reach me in telegram https://t.me/r137y or here https://dorokhovich.com/

Overview of Keycloak and its clustering
Why use Nginx as a load balancer
Different clustering modes (JGroups, Kubernetes)
What is service discovery and why is it needed?
What discovery mechanisms does Keycloak support?
Load Balancing Configuration for Keycloak
Configuring Nginx as a Load Balancer

Overview of Keycloak and its clustering

Keycloak is a powerful access management system that provides Single Sign-On (SSO), integration with various authentication providers, and role-based access management. By using protocols such as OpenID Connect, OAuth 2.0, and SAML 2.0, Keycloak simplifies the user authentication process in web applications and services.

A standard standalone Keycloak installation is suitable for small deployments, but as the load increases or high availability requirements arise, scaling becomes necessary. In this case, Keycloak needs to be launched in clustered mode, where multiple nodes work together to ensure load balancing and seamless system operation even in case of a node failure.

There are several ways to organize a Keycloak cluster. One of the most common is Standalone Clustered Mode, where nodes exchange data via JGroups using TCP or auto-discovery mechanisms such as DNS. This option is suitable for deployment on physical servers or virtual machines but requires separate network configuration between nodes.

Another popular approach is deploying Keycloak in Kubernetes, where the cluster is managed using orchestration tools. In this case, the built-in KUBE_PING mechanism is used for node discovery. Kubernetes significantly simplifies scaling, allowing dynamic addition or removal of nodes depending on the load.

For high-load systems, not only fault tolerance but also high speed of operation is important. Infinispan helps here, being used as a distributed cache. It allows accelerating request processing by reducing database load through caching of user sessions and other frequently requested data.

The choice of clustering method depends on the infrastructure and system requirements. If deployment occurs on separate servers or virtual machines, JGroups is more convenient, whereas in a cloud environment, Kubernetes becomes the preferred solution. To achieve maximum performance and minimize delays, caching based on Infinispan is useful.

Why use Nginx as a load balancer

When deploying Keycloak in clustered mode, it is necessary to ensure even load distribution between nodes and reliable access to the service in case of a node failure. In this scenario, a critically important component is the load balancer, which manages incoming requests and directs them to available Keycloak instances. One of the most popular solutions for this purpose is Nginx due to its performance, flexibility, and ease of configuration.

One of the key reasons for choosing Nginx as a load balancer is its low resource consumption and high performance. It can handle thousands of simultaneous connections, making it an excellent choice for distributing load in high-traffic systems. Unlike hardware balancers, Nginx can be easily deployed on any server, and its configuration requires minimal time.

Another important advantage is its support for reverse proxying, which allows hiding the internal structure of the Keycloak cluster from users. Nginx receives HTTP requests from clients and forwards them to one of the Keycloak nodes, while the client only interacts with the balancer without knowing the number or location of the servers in the cluster. This simplifies administration and enhances system security.

Additionally, Nginx provides automatic failover to available nodes in case one of the servers goes down. This is implemented through health check mechanisms that monitor the status of each Keycloak instance and exclude temporarily unavailable nodes from load balancing. This approach ensures uninterrupted system operation even when failures occur on individual servers.

To ensure secure user interaction with the system, Nginx allows SSL/TLS termination, meaning it can receive HTTPS requests and decrypt them at the balancer level before forwarding them internally in a regular HTTP format. This reduces the load on Keycloak nodes by offloading encryption processing and simplifies security certificate management.

Furthermore, Nginx offers extensive configuration options for optimizing traffic flows, limiting request rates, and protecting against DDoS attacks. It also supports caching mechanisms, which can reduce the load on Keycloak by speeding up the processing of repeated requests.

Using Nginx as a load balancer for a Keycloak cluster ensures reliability, fault tolerance, and security for the system.

Different clustering modes (JGroups, Kubernetes)

When deploying Keycloak in clustered mode, it is important to choose the right method for data exchange between nodes. The main task here is to synchronize user sessions, cache data, and properly distribute the load. Keycloak supports two main clustering methods: JGroups and Kubernetes-native clustering.

Clustering via JGroups

JGroups is a Java library that allows cluster nodes to interact with each other in a distributed environment. In the context of Keycloak, it is used for automatic node discovery and data exchange, such as cache synchronization and session replication.

JGroups supports several different node discovery mechanisms:

  1. TCP — used for reliable connections between known servers, suitable for small private clusters.
  2. UDP — allows nodes to automatically find each other within the same subnet, which is useful for dynamic environments.
  3. TCPPING — requires explicitly specifying a list of all nodes, used in static clusters.
  4. DNS_PING — searches for other nodes through DNS records, which is useful in cloud environments.

How does JGroups work in Keycloak?

When one of the cluster nodes processes a user request, it updates the data in the distributed cache. The other nodes receive a notification about the changes to always have up-to-date data. This allows users to seamlessly switch between nodes without session interruption.

However, this method has limitations. It requires detailed network configuration and auto-discovery parameters. Additionally, when using a large number of nodes in a cluster, JGroups efficiency may decrease due to network latency.

Clustering via Kubernetes

In a Kubernetes environment, Keycloak uses built-in auto-discovery mechanisms, replacing JGroups with KUBE_PING. Instead of broadcast messages, Kubernetes provides services for cluster management, significantly simplifying scaling and administration.

Key benefits of Kubernetes clustering:

  1. Automatic node discovery via the Kubernetes Service API.
  2. Simplified scaling — new nodes are automatically added to the cluster without the need for manual configuration.
  3. Enhanced fault tolerance — Kubernetes monitors the state of pods and automatically restarts failed nodes.
  4. Easy integration with cloud services such as AWS, Google Cloud, and Azure.

How does it work in Kubernetes?

Keycloak runs as a set of pods, and Kubernetes manages their load balancing and auto-discovery. When the number of replicas changes (e.g., during horizontal scaling), Kubernetes automatically updates the list of cluster nodes, ensuring synchronization.

To work with Kubernetes, it is necessary to use a StatefulSet or Deployment with a ClusterIP-type service. This allows Keycloak nodes to see each other through Kubernetes’ internal DNS.

Which method to choose?

The choice of clustering method depends on the infrastructure and fault tolerance requirements.

If Keycloak is deployed in a traditional environment (on virtual machines or physical servers), it is better to use JGroups with TCP or DNS_PING.

If Keycloak operates in a cloud environment or Kubernetes, it is preferable to use KUBE_PING, as it simplifies management and scaling.

In the following sections, we will explore how to configure a Keycloak cluster using both methods and integrate it with Nginx for load balancing.

What is service discovery and why is it needed?

Service discovery is a mechanism that allows Keycloak nodes to automatically find and identify each other in a clustered environment. In a distributed architecture, this is especially important because nodes must be aware of the existence of other instances for proper data synchronization and fault tolerance.

Why is service discovery critically important

Dynamic scaling

  1. In cloud and containerized environments (e.g., Kubernetes), nodes can be dynamically added or removed.
  2. Service discovery allows new nodes to automatically register in the cluster without manual configuration.

Fault tolerance and load balancing

  1. If one of the nodes fails, the remaining nodes must quickly adjust the cluster topology and continue operating.
  2. The load balancer (e.g., Nginx) continues routing requests, while Keycloak automatically excludes unavailable nodes.

Session data sharing

  1. In a cluster, users may switch between nodes, but their sessions must remain active.
  2. To achieve this, Keycloak nodes synchronize authentication data via a shared cache (Infinispan) or a database.

Reducing administrative overhead

  1. Without service discovery, an administrator must manually specify node IP addresses in the configuration.
  2. With service discovery, the system automatically updates the list of available servers.

How does service discovery work?

When a new Keycloak node starts, it follows several steps:

  1. It checks the deployment environment and selects the appropriate discovery mechanism (JGroups, Kubernetes API, DNS, etc.).
  2. It initiates a request to discover other nodes (e.g., via UDP, TCP, a database, or DNS).
  3. It retrieves a list of active nodes and establishes connections for data exchange.
  4. It periodically checks the availability of other nodes and removes unavailable instances from the list.

What discovery mechanisms does Keycloak support?

Keycloak uses JGroups, a clustering library for Java applications, and several discovery mechanisms:

  1. TCPPING — Fixed IP addresses of nodes (suitable for static environments).
  2. UDP PING — Broadcast node discovery within a local network.
  3. JDBC_PING — Discovery via a shared database (used in Docker, OpenStack).
  4. KUBE_PING — Integration with the Kubernetes API for automatic discovery of Keycloak pods.
  5. DNS_PING — Uses DNS queries to determine nodes in cloud environments (AWS, GCP, Azure).

Choosing the right method based on the environment:

  1. In traditional deployments (bare-metal, VMs), TCPPING or JDBC_PING is used.
  2. In containerized environments (Docker, OpenShift), JDBC_PING is convenient.
  3. In Kubernetes, KUBE_PING is the preferred option.
  4. In cloud services (AWS, GCP, Azure), DNS_PING is the best choice.

Load Balancing Configuration for Keycloak

Load balancing in a Keycloak cluster plays a key role in ensuring even distribution of requests among nodes, system fault tolerance, and scalability. The primary task of the load balancer is to direct incoming requests to active Keycloak nodes, monitor their status, and exclude faulty servers from the traffic flow.

Choosing a Load Balancing Strategy

When configuring load balancing for Keycloak, several request distribution strategies can be used:

  1. Round Robin — Requests are evenly distributed among all nodes in a circular manner.
  2. Least Connections — Requests are sent to the server with the fewest active connections, reducing the load on overloaded nodes.
  3. IP Hash — Users are bound to a specific server based on their IP address to minimize session interruptions.

The most commonly used strategies are Round Robin or Least Connections, but IP Hash can be useful when dealing with distributed sessions.

Configuring Nginx as a Load Balancer

Nginx acts as a reverse proxy and load balancer for Keycloak, receiving HTTP(S) requests from clients and directing them to available nodes. The Nginx configuration should consider:

  1. Defining the list of Keycloak nodes
  2. Setting the load balancing algorithm
  3. Handling node failures

Example Nginx Configuration for Keycloak Load Balancing:

events {
worker_connections 1024;
}

http {
resolver 127.0.0.11 valid=30s ipv6=off;

upstream keycloak_cluster {
zone keycloak_cluster 64k;
server keycloak:8080 resolve;
}

upstream keycloak_cluster_ssl {
zone keycloak_cluster_ssl 64k;
server keycloak:8443 resolve;
}

server {
listen 80;
server_name _;

return 301 https://$host$request_uri;
}

server {
listen 443 ssl;
server_name _;

ssl_certificate /etc/nginx/certs/tls.crt;
ssl_certificate_key /etc/nginx/certs/tls.key;

ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;

location / {
proxy_pass https://keycloak_cluster_ssl;
proxy_http_version 1.1;

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;
}
}
}

Configuration Explanation

The Nginx configuration is based on two upstream blocks:

  1. keycloak_cluster — Proxies HTTP requests to Keycloak nodes on port 8080.
  2. keycloak_cluster_ssl — Balances HTTPS requests to port 8443.

Nginx uses dynamic DNS resolution (resolve), allowing it to automatically detect changes in Keycloak node IP addresses. This is especially useful in containerized environments like Docker and Kubernetes.

Additionally, automatic HTTP to HTTPS redirection is configured to ensure that all connections are encrypted.

server {
listen 80;
server_name _;

return 301 https://$host$request_uri;
}

The server running on port 443 processes HTTPS requests using SSL certificates:

ssl_certificate     /etc/nginx/certs/tls.crt;
ssl_certificate_key /etc/nginx/certs/tls.key;

For security, only modern TLS versions (1.2 and 1.3) are enabled, and weak encryption algorithms are excluded.

Main Reverse Proxy

The primary reverse proxy forwards incoming HTTPS requests to Keycloak:

proxy_pass https://keycloak_cluster_ssl;

At the same time, headers are passed to ensure correct processing of client requests:

  1. Host — Forwards the original host so that Keycloak can correctly route requests.
  2. X-Real-IP and X-Forwarded-For — Preserve the client’s IP address.
  3. X-Forwarded-Proto — Informs Keycloak that the connection was established over HTTPS.

HTTPS Traffic Balancing

This configuration allows Nginx to act as an SSL terminator, receiving HTTPS requests, decrypting them, and forwarding them within the internal network in plain HTTP format. This reduces the load on Keycloak and simplifies certificate management.

Monitoring and Failure Handling

To improve fault tolerance, a health-check can be configured to check the availability of Keycloak nodes before adding them to the load balancer. This can be done by adding a location check for /realms/master/health:

location /health {
proxy_pass http://keycloak_cluster/realms/master/health;
proxy_set_header Host $host;
}

If Keycloak stops responding, Nginx will automatically remove it from the list of active nodes.

Using Nginx for Keycloak load balancing ensures high availability, scalability, and security. This configuration automatically redirects HTTP traffic to HTTPS, supports dynamic node discovery, and reduces the load on Keycloak through SSL termination. In the future, monitoring of node status and protection against overload can be added by implementing request rate limits and response caching.

If you want to integration Keycloak into your project and don’t know where to start — you can reach me in telegram https://t.me/r137y

You can find cache-ispn-jdbc-ping.xml that is used for JDBC PING setup here — https://gist.github.com/metronom72/8d581e94904613e1d1eb0edca5eb96f8

--

--

Mi Do
Mi Do

Written by Mi Do

You need any support - feel free to reach me out https://dorokhovich.com/

No responses yet