H2 problem with multiple backends


#1

Hi,

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
#---------------------------------------------------------------------
global
    # 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
    daemon

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

    # ssl config
    ssl-default-bind-options no-sslv3 no-tls-tickets
    ssl-default-bind-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK
    tune.ssl.default-dh-param 2048
    tune.ssl.cachesize        100000
    tune.ssl.lifetime         600
    tune.ssl.maxrecord        1460

    # eigenen hostname statt "localhost" im log
    log-send-hostname

#---------------------------------------------------------------------
# common defaults that all the 'listen' and 'backend' sections will
# use if not designated in their block
#---------------------------------------------------------------------
defaults
    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 127.0.0.1:81 check

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

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

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

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

backend be_dummy_www
    mode http
    server haproxy_www_dummy 127.0.0.1:8080

I hope someone can help :wink:

Thanks in advance!
Phil


#2

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).


#3

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!
Phil


#4

Correct.

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.


#5

Tried it and it completely fixed the problem!

Thank you so much!