Keycloak “ERR_TOO_MANY_REDIRECTS” Behind HAProxy
Problem
The Keycloak administration console is not accessible from enxternal network when accessed through HAProxy, the browser returns ERR_TOO_MANY_REDIRECTS, preventing access to the application.
The issue can be reproduced using curl, which reveals an endless sequence of HTTP 301 redirects. Instead, the behavior indicates a reverse proxy configuration issue, most likely related to the communication between HAProxy and the backend service.
When accessed externally, the browser displayed:
ERR_TOO_MANY_REDIRECTS
Root Cause
HAProxy backend configuration:
server <redacted-server-name> <redacted-private-ip>:80 id 108
If the intended configuration is to forward requests with:
X-Forwarded-Proto: https
X-Forwarded-Port: 443
the question arises:
If HAProxy explicitly forwards the request as HTTPS on port 443, why is the backend server configured to use HTTP (port 80)?
Investigation
The browser reported “ERR_TOO_MANY_REDIRECTS”, which could also be reproduced using curl.
curl -I https://<redacted-hostname>/admin/master/console/ -L
Output (excerpt):
HTTP/2 301
Server: Apache
Location: https://<redacted-hostname>/admin/master/console/
HTTP/2 301
Server: Apache
Location: https://<redacted-hostname>/admin/master/console/
HTTP/2 301
Server: Apache
Location: https://<redacted-hostname>/admin/master/console/
...
curl: (47) Maximum (50) redirects followed
Since direct access and authentication were working internally, as described, the issue did not initially appear to be caused by a UCS or Keycloak misconfiguration.
Is it possible to configure the HAProxy backend to send the X-Forwarded-Proto header?
When performing the following test:
curl -I \
-H "X-Forwarded-Proto: https" \
https://<redacted-hostname>/admin/master/console/
the redirect loop no longer occurred.
Please verify the HAProxy backend configuration for the Keycloak service and ensure the forwarding headers are configured as follows:
backend keycloak_backend
http-request set-header X-Forwarded-Proto https
http-request set-header X-Forwarded-Port 443
# Optional but recommended
http-request set-header X-Forwarded-For %[src]
server keycloak-backend <backend-ip>:443 ssl verify none
# Alternatively, if the backend intentionally uses HTTP:
# server keycloak-backend <backend-ip>:80
Please also verify the following UCR variable and provide its output:
ucr get apache2/force_https
HAProxy Configuration
The frontend already contained the following configuration:
http-request set-header X-Forwarded-Proto http if !https
http-request set-header X-Forwarded-Proto https if https
The backend was updated with the following directives:
http-request set-header X-Forwarded-Proto https
http-request set-header X-Forwarded-Port 443
http-request set-header X-Forwarded-For %[src]
The backend server configuration remained:
server keycloak-backend <backend-ip>:80 id 108
Solution
Modify the backend server configuration to use HTTPS instead of HTTP:
server keycloak-backend <backend-ip>:443 ssl verify none id 108
Reload HAProxy to apply the updated configuration.
Finally, verify the behavior by executing:
curl -I https://<redacted-hostname>/admin/master/console/ -L
Additional
Using ssl verify none means that HAProxy establishes a TLS connection to the backend but does not verify whether the certificate is signed by a trusted Certificate Authority or whether the certificate matches the backend hostname.
The backend system (<backend-ip>:443) presents a certificate signed by the internal UCS Root CA (/etc/univention/ssl/ucsCA/CAcert.pem). Since HAProxy does not trust this CA by default, removing verify none without importing the CA would cause TLS handshake failures, resulting in a 502 Bad Gateway instead of a redirect loop.
Instead of using verify none, the recommended approach is to import the UCS Root CA into HAProxy’s trust store:
scp root@<backend-ip>:/etc/univention/ssl/ucsCA/CAcert.pem \
/var/etc/haproxy/ucs-ca.pem
After importing the CA certificate, the backend configuration can be changed to perform proper certificate validation instead of relying on:
ssl verify none
