H2 problem with multiple backends



I have a problem setting up h2 support.
I redirect to multiple backends depending on sni:

When I open www example com the page loads just fine and is served via h2. After that, I try to load mail example com. But it loads www example com. After pressing [CTRL] + [F5], it loads mail example com via h2.

I’m pretty sure, I’m just missing one little thing, but can’t figure out what it is.

This is my config:

# Global settings
    # to have these messages end up in /var/log/haproxy.log you will
    # need to:
    # 1) configure syslog to accept network log events.  This is done
    #    by adding the '-r' option to the SYSLOGD_OPTIONS in
    #    /etc/sysconfig/syslog
    # 2) configure local2 events to go to the /var/log/haproxy.log
    #   file. A line like the following can be added to
    #   /etc/sysconfig/syslog
    #    local2.*                       /var/log/haproxy.log
    log         /dev/log      local0
    log         /dev/log      local1 notice

    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     4096
    user        haproxy
    group       haproxy

    # turn on stats unix socket
    stats socket /var/lib/haproxy/stats

    # ssl config
    ssl-default-bind-options no-sslv3 no-tls-tickets
    tune.ssl.default-dh-param 2048
    tune.ssl.cachesize        100000
    tune.ssl.lifetime         600
    tune.ssl.maxrecord        1460

    # eigenen hostname statt "localhost" im log

# common defaults that all the 'listen' and 'backend' sections will
# use if not designated in their block
    mode    tcp
    log     global
    option  httplog
    option  dontlognull
    option  http-server-close
    option  forceclose
    option  forwardfor
    option  redispatch
    retries 1
    timeout http-request      10s
    timeout queue             1m
    timeout connect           10s
    timeout client            1m
    timeout server            1m
    timeout http-keep-alive   10s
    timeout check             10s
    timeout tunnel            15m
    timeout client-fin        30s
    maxconn 4096

listen stats
    bind :::8443 v4v6 ssl crt /etc/haproxy/cert/
    mode http
    stats enable
    stats hide-version
    stats realm secured
    stats auth <user>:<password>
    stats uri /
    stats refresh 5s

frontend fe_http
    bind :::80 v4v6
    mode http

    redirect prefix https://example.com code 302 if { hdr(Host) -i example.com }
    redirect prefix https://www.example.com code 302 if { hdr(Host) -i www.example.com }
    redirect prefix https://www.example.com code 302 if { hdr(Host) -i <ipv4> }
    redirect prefix https://www.example.com code 302 if { hdr(Host) -i [<ipv6>] }
    redirect prefix https://mail.example.com code 302 if { hdr(Host) -i mail.example.com }

frontend fe_https
    bind :::443 v4v6 ssl crt /etc/haproxy/cert/ alpn h2,http/1.1
    mode tcp

    tcp-request inspect-delay 5s
    tcp-request content accept if { req_ssl_hello_type 1 }

    acl host_www.example.com ssl_fc_sni -i www.example.com
    acl host_mail.example.com ssl_fc_sni -i mail.example.com
    acl host_non_www ssl_fc_sni -i example.com

    acl proto_h2 ssl_fc_alpn -i h2

    use_backend be_www if host_www.example.com !proto_h2
    use_backend be_www_h2 if host_www.example.com proto_h2

    use_backend be_mail if host_mail.example.com !proto_h2
    use_backend be_mail_h2 if host_mail.example.com proto_h2

    use_backend be_dummy_www if host_non_www

backend be_www
    balance roundrobin
    mode http
    server www.example.com check

backend be_www_h2
    balance roundrobin
    mode tcp
    server www.example.com check send-proxy

backend be_mail
    balance roundrobin
    mode http
    timeout server 3660s
    timeout client 3660s
    server mail.example.com check

backend be_mail_h2
    balance roundrobin
    mode tcp
    timeout server 3660s
    timeout client 3660s
    server mail.example.com check send-proxy

frontend fe_dummy_www
    mode http
    redirect prefix https://www.example.com code 302

backend be_dummy_www
    mode http
    server haproxy_www_dummy

I hope someone can help :wink:

Thanks in advance!


It is simple.

There must be different certificate for www.example.com and mail.example.com. They cannot overlap (due to SAN’s or wildcard certificate).

SNI routing won’t work correctly (if a certificate contains a number of SANs, a browser will assume it can reach all SAN domains over the same TLS connections, but SNI routing only occurs in the beginning with the client_hello, breaking the assumption that the browser will use the current TLS session for specific hostnames/SNI’s only).


Hi lukastribus,

I have 1 cert with SAN’s for both subdomains…
So requesting different certs for every subdomain will fix that?

Oh my god, I would never have thought of that!

I’ll try this.

Thank you very much!



When haproxy implements http/2 itself, this won’t be necessary anymore, but since we are only passing TCP payload through based on SNI values, that is what we have to do.


Tried it and it completely fixed the problem!

Thank you so much!