Problem: Misdirected Request Error After Update to UCS 5.2 with HAProxy and SSO

Problem: Misdirected Request Error After Update to UCS 5.2 with HAProxy and SSO

Problem:

After updating to UCS 5.2 (Debian 12 Bookworm), attempts to log in via SSO (Keycloak) on a UCS Portal server (e.g., portal.uni.vention.de) that is accessed behind a proxy (HAProxy) fail with the following error when the portal is accessed via FQDN from browser:

Misdirected Request

The client needs a new connection for this request as the requested host name does not match the Server Name Indication (SNI) in use for this connection.

Screenshot from 2025-09-24 13-54-52

curl https://portal.uni.vention.de/realms/ucs/protocol/saml/descriptor

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>421 Misdirected Request</title>
</head><body>
<h1>Misdirected Request</h1>
<p>The client needs a new connection for this
request as the requested host name does not match
the Server Name Indication (SNI) in use for this
connection.</p>
<hr>
<address>Apache/2.4.65 (Debian) Server at portal.uni.vention.de Port 443</address>
</body></html>

Root Cause:

UCS 5.2 (based on Debian 12) ships with Apache 2.4, which has long supported Server Name Indication (SNI). A key change in Debian 12 is the availability of the directive SSLStrictSNIVHostCheck in Apache’s configuration.

This directive, found in /etc/apache2/mods-enabled/ssl.conf, enforces stricter validation of hostnames during the TLS handshake:

  • SSLStrictSNIVHostCheck Off (default): Apache serves requests even if the client does not send an SNI header or the hostname does not match a configured virtual host. In such cases, Apache falls back to the first available SSL-enabled virtual host.
  • SSLStrictSNIVHostCheck On: Apache only accepts requests where the client provides a correct SNI hostname that matches one of the configured virtual hosts. Requests with missing or mismatched SNI headers are rejected.

While this stricter validation increases security, it can also break compatibility in environments with reverse proxies or older clients that do not properly handle SNI.

Source: Debian Apache2 changelog


Investigation:

The error message “Misdirected Request” (HTTP 421) occurs because the UCS Portal server detects a mismatch between the hostname in the HTTP request header and the SNI field in the TLS handshake.

This problem is typically observed when using HTTP/2 and a reverse proxy such as HAProxy, particularly in these cases:

  • A wildcard certificate (*.domain.com) or a multi-domain SAN certificate is in use.
  • The browser reuses an existing TCP connection (a feature of HTTP/2).

Example flow

  1. The browser first connects to portal.domain.com. HAProxy reads the SNI header and forwards the request correctly to the UCS server.
  2. During SSO login, the browser needs to connect to another subdomain (e.g., sso.domain.com) but reuses the already established TCP connection.
  3. The request for sso.domain.com is sent over a connection where the original SNI was portal.domain.com.
  4. Apache on the UCS Portal server detects this mismatch and responds with HTTP 421 Misdirected Request, forcing the client to open a new connection.

Solution:

The solution is to configure HAProxy to properly pass SNI information to the backend servers, ensuring that the UCS Portal and SSO services can validate the request correctly.

Option 1: SSL Offloading at HAProxy

The most common setup is to terminate TLS at HAProxy. HAProxy decrypts incoming TLS traffic, forwards it as plain HTTP to the backend UCS servers, and re-encrypts responses.

Example HAProxy configuration:

frontend http_in
  bind *:80
  mode http
  redirect scheme https code 301 if !{ ssl_fc }

frontend https_in
  bind *:443 ssl crt /etc/haproxy/certs/portal.pem
  bind *:443 ssl crt /etc/haproxy/certs/sso.pem
  mode http
  http-request set-header X-Forwarded-Proto https
  use_backend ucs_portal if { hdr(Host) -i portal.domain.com }
  use_backend ucs_sso if { hdr(Host) -i sso.domain.com }

backend ucs_portal
  mode http
  server portal_server 192.168.1.10:80

backend ucs_sso
  mode http
  server sso_server 192.168.1.11:80

Option 2: Passing SNI Through to Backends

If TLS termination should remain on the UCS servers, configure HAProxy to forward SNI correctly to each backend.

Example configuration:

backend BE_UCS-SSO
  fullconn 30000
  balance leastconn
  stick-table type ip size 120m expire 2h
  stick on src
  option httpchk GET /
  http-check expect rstatus [2-3][0-9][0-9]
  server ucs-sso-server [BACKEND_IP]:443 sni sso.domain.com ssl verify none check maxconn 15000
  server ucs-sso-server_1 [BACKEND_IP]:443 sni sso.domain.com ssl verify none check maxconn 15000

UCS Server configuration

Ensure the UCS servers accept HTTP traffic on port 80 and honor the X-Forwarded-Proto header. This is already standard in most UCS Apache setups.


:white_check_mark: With this configuration, HAProxy either:

  • terminates SSL and ensures consistent Host headers for all backend requests, or
  • forwards the correct SNI values to UCS servers when SSL termination is not used.

Konfiguration example in opensense: