[[_setting-up-a-load-balancer-or-proxy]] === Setting Up a load balancer or proxy This section discusses a number of things you need to configure before you can put a reverse proxy or load balancer in front of your clustered {project_name} deployment. It also covers configuring the built-in load balancer that was <<_clustered-domain-example, Clustered Domain Example>>. The following diagram illustrates the use of a load balancer. In this example, the load balancer serves as a reverse proxy between three clients and a cluster of three {project_name} servers. [[load-balancer-diagram]] .Example Load Balancer Diagram image:{project_images}/load_balancer.png[] ==== Identifying client IP addresses A few features in {project_name} rely on the fact that the remote address of the HTTP client connecting to the authentication server is the real IP address of the client machine. Examples include: * Event logs - a failed login attempt would be logged with the wrong source IP address * SSL required - if the SSL required is set to external (the default) it should require SSL for all external requests * Authentication flows - a custom authentication flow that uses the IP address to for example show OTP only for external requests * Dynamic Client Registration This can be problematic when you have a reverse proxy or loadbalancer in front of your {project_name} authentication server. The usual setup is that you have a frontend proxy sitting on a public network that load balances and forwards requests to backend {project_name} server instances located in a private network. There is some extra configuration you have to do in this scenario so that the actual client IP address is forwarded to and processed by the {project_name} server instances. Specifically: * Configure your reverse proxy or loadbalancer to properly set `X-Forwarded-For` and `X-Forwarded-Proto` HTTP headers. * Configure your reverse proxy or loadbalancer to preserve the original 'Host' HTTP header. * Configure the authentication server to read the client's IP address from `X-Forwarded-For` header. Configuring your proxy to generate the `X-Forwarded-For` and `X-Forwarded-Proto` HTTP headers and preserving the original `Host` HTTP header is beyond the scope of this guide. Take extra precautions to ensure that the `X-Forwarded-For` header is set by your proxy. If your proxy isn't configured correctly, then _rogue_ clients can set this header themselves and trick {project_name} into thinking the client is connecting from a different IP address than it actually is. This becomes really important if you are doing any black or white listing of IP addresses. Beyond the proxy itself, there are a few things you need to configure on the {project_name} side of things. If your proxy is forwarding requests via the HTTP protocol, then you need to configure {project_name} to pull the client's IP address from the `X-Forwarded-For` header rather than from the network packet. To do this, open up the profile configuration file (_standalone.xml_, _standalone-ha.xml_, or _domain.xml_ depending on your <<_operating-mode, operating mode>>) and look for the `{subsystem_undertow_xml_urn}` XML block. .`X-Forwarded-For` HTTP Config [source,xml,subs="attributes+"] ---- ... ... ---- Add the `proxy-address-forwarding` attribute to the `http-listener` element. Set the value to `true`. If your proxy is using the AJP protocol instead of HTTP to forward requests (i.e. Apache HTTPD + mod-cluster), then you have to configure things a little differently. Instead of modifying the `http-listener`, you need to add a filter to pull this information from the AJP packets. .`X-Forwarded-For` AJP Config [source,xml,subs="attributes+"] ---- ... ... ... ---- ==== Enabling HTTPS/SSL with a reverse proxy Assuming that your reverse proxy doesn't use port 8443 for SSL you also need to configure to what port the HTTPS traffic is redirected. [source,xml,subs="attributes+"] ---- ... ... ---- .Procedure . Add the `redirect-socket` attribute to the `http-listener` element. The value should be `proxy-https` which points to a socket binding you also need to define. . Add a new `socket-binding` element to the `socket-binding-group` element: + [source,xml] ---- ... ... ---- ==== Verifying the configuration You can verify the reverse proxy or load balancer configuration .Procedure . Open the path `/auth/realms/master/.well-known/openid-configuration` through the reverse proxy. + For example if the reverse proxy address is `\https://acme.com/` then open the URL `\https://acme.com/auth/realms/master/.well-known/openid-configuration`. This will show a JSON document listing a number of endpoints for {project_name}. . Make sure the endpoints starts with the address (scheme, domain and port) of your reverse proxy or load balancer. By doing this you make sure that {project_name} is using the correct endpoint. . Verify that {project_name} sees the correct source IP address for requests. + To check this, you can try to login to the Admin Console with an invalid username and/or password. This should show a warning in the server log something like this: + [source] ---- 08:14:21,287 WARN XNIO-1 task-45 [org.keycloak.events] type=LOGIN_ERROR, realmId=master, clientId=security-admin-console, userId=8f20d7ba-4974-4811-a695-242c8fbd1bf8, ipAddress=X.X.X.X, error=invalid_user_credentials, auth_method=openid-connect, auth_type=code, redirect_uri=http://localhost:8080/auth/admin/master/console/?redirect_fragment=%2Frealms%2Fmaster%2Fevents-settings, code_id=a3d48b67-a439-4546-b992-e93311d6493e, username=admin ---- . Check that the value of `ipAddress` is the IP address of the machine you tried to login with and not the IP address of the reverse proxy or load balancer. ==== Using the built-in load balancer This section covers configuring the built-in load balancer that is discussed in the <<_clustered-domain-example, Clustered Domain Example>>. The <<_clustered-domain-example, Clustered Domain Example>> is only designed to run on one machine. To bring up a slave on another host, you'll need to . Edit the _domain.xml_ file to point to your new host slave . Copy the server distribution. You don't need the _domain.xml_, _host.xml_, or _host-master.xml_ files. Nor do you need the _standalone/_ directory. . Edit the _host-slave.xml_ file to change the bind addresses used or override them on the command line .Procedure . Open _domain.xml_ so you can registering the new host slave with the load balancer configuration. . Go to the undertow configuration in the `load-balancer` profile. Add a new `host` definition called `remote-host3` within the `reverse-proxy` XML block. + .domain.xml reverse-proxy config [source,xml,subs="attributes+"] ---- ... ... ---- + The `output-socket-binding` is a logical name pointing to a `socket-binding` configured later in the _domain.xml_ file. The `instance-id` attribute must also be unique to the new host as this value is used by a cookie to enable sticky sessions when load balancing. . Go down to the `load-balancer-sockets` `socket-binding-group` and add the `outbound-socket-binding` for `remote-host3`. + This new binding needs to point to the host and port of the new host. + .domain.xml outbound-socket-binding [source,xml] ---- ... ---- ===== Master bind addresses Next thing you'll have to do is to change the `public` and `management` bind addresses for the master host. Either edit the _domain.xml_ file as discussed in the <<_bind-address, Bind Addresses>> chapter or specify these bind addresses on the command line as follows: [source] ---- $ domain.sh --host-config=host-master.xml -Djboss.bind.address=192.168.0.2 -Djboss.bind.address.management=192.168.0.2 ---- ===== Host slave bind addresses Next you'll have to change the `public`, `management`, and domain controller bind addresses (`jboss.domain.master-address`). Either edit the _host-slave.xml_ file or specify them on the command line as follows: [source] ---- $ domain.sh --host-config=host-slave.xml -Djboss.bind.address=192.168.0.5 -Djboss.bind.address.management=192.168.0.5 -Djboss.domain.master.address=192.168.0.2 ---- The values of `jboss.bind.address` and `jboss.bind.address.management` pertain to the host slave's IP address. The value of `jboss.domain.master.address` needs to be the IP address of the domain controller, which is the management address of the master host. [role="_additional-resources"] .Additional resources * See link:{appserver_loadbalancer_link}[the load balancing] section in the _{appserver_loadbalancer_name}_ for information how to use other software-based load balancers.