Wrong backend selected with SNI when using HTTP/2

When I activate http/2 using “alpn h2,http”, the backend selection fails. I have a wildcard certificate and select the backends based on SNI. Here is the relevant section of haproxy.cfg (haproxy version :2.0.13-2ubuntu0.5 2022/03/02)
defaults
log global
mode http
option forwardfor
option http-keep-alive
option redispatch
timeout check 5s
timeout client 5s
timeout connect 5s
timeout server 16m
timeout tunnel 16m
timeout http-request 5s
timeout http-keep-alive 15s
frontend https
bind :443 ssl crt /etc/haproxy/ssl alpn h2,http/1.1
use_backend onlyoffice if { ssl_fc_sni onlyoffice.sampledomain.com }
use_backend alfresco if { ssl_fc_sni alfresco.sampledomain.com }
The browsers (Edge, Firefox) show (in developer tools) that requests are made to
GET https://onlyoffice.sampledomain.com/OfficeWeb/apps/api/documents/api.js
with response code 404 and request headers:
Accept
/
Accept-Encoding
gzip, deflate, br
Accept-Language
en-US,en;q=0.5
Cache-Control
no-cache
Connection
keep-alive
DNT
1
Host
onlyoffice.sampledomain.com
Pragma
no-cache
Referer
https://alfresco.sampledomain.com/
Sec-Fetch-Dest
script
Sec-Fetch-Mode
no-cors
Sec-Fetch-Site
same-site
TE
trailers
User-Agent
Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:101.0) Gecko/20100101 Firefox/101.0
In haproxy.log I have:
Jun 14 11:08:42 dd2 haproxy[161556]: 127.0.0.1:53856 [14/Jun/2022:11:08:42.352] https~ alfresco/alfresco 0/0/69/37/106 404 942 - - ---- 1/1/1/1/0 0/0 {0,"",0} “GET /OfficeWeb/apps/api/documents/api.js HTTP/2.0”
If I remove alpn h2, the request goes to the right backend:
Jun 14 11:10:13 dd2 haproxy[162131]: 127.0.0.1:34712 [14/Jun/2022:11:10:13.709] https~ onlyoffice/onlyoffice 11/0/31/31/73 302 371 - - ---- 3/3/0/0/0 0/0 {0,"",0} “GET /OfficeWeb/apps/a
pi/documents/api.js HTTP/1.1”
Can someone explain what’s going on? Both Firefox and Edge show the same behavior.

i have the same. a ssl certificate with multiple domains (ok, no wildcard, but that should not matter)
i use the config

bind 12.34.56.78:443 ssl crt /opt/haproxy/haproxy.ssl.crt crt /opt/haproxy/domain.pem  alpn h2,http/1.1
capture request header Host len 32
use_backend server1 if { hdr(host) - domain1.com }
use_backend server2 if { hdr(host) - domain2.com }

You must not have overlapping certificates (across backends) when you use SNI based routing.

This is because when a browser connects in H2 to a HTTPS server with a wildcard/SAN certificate covering different backends, the browser will keep using that HTTPS connection available to it because it will assume that the connection can be used for everything the certificate would be valid for. And SNI is a field in the SSL handshake (therefor once only at the begging of the SSL session), it’s not something that is available or updated per transaction (as opposed to the Host header in HTTP).

I have investigated further using tcpdump and the browser is reusing the same tcp connection - this is indeed the reason why SNI selection fails. This (connection coalescing) is part of HTTP/2 standard (I was not aware until now). The solution to use the host header for backend selection works fine.
I wonder if I could return a 421 error code (misdirected request) each time the SNI does not match the host header and keep using SNI. It would probably work but using just the host header looks cleaner.

In this particular configuration, using ssl_fc_sni doesn’t not make any sense at all. Only when using passthrough you are forced to use SNI based routing, but it should be avoided at all times.

I use two frontends and a passthru backend for this (works perfectly), by something like this
this because i have Websocket traffic. (DDP)