HAProxy route https SNI and http over the same port

I have an HAProxy routing HTTPS without termination using SNI.

The configuration is similar to the following:

frontend ft_ssl_vip
  bind 0.0.0.0:5000
  mode tcp
  option tcplog

  tcp-request inspect-delay 5s
  tcp-request content accept if { req.ssl_hello_type 1 }

  default_backend bk_ssl_default

# Using SNI to take routing decision
backend bk_ssl_default
  mode tcp

  acl application_1 req.ssl_sni -i foo.example.com
  acl application_2 req.ssl_sni -i bar.example.com

  use-server server1 if application_1
  use-server server2 if application_2
  use-server server3 if !application_1 !application_2

  option ssl-hello-chk
  server server1 127.0.0.1:777
  server server2 127.0.0.1:778
  server server3 127.0.0.1:779

I need to also route HTTP traffic over the same port (5000).

How can I modify my configuration to accommodate both HTTP and HTTPS via SNI without termination over the same port?


edit


I've gotten much closer. The HTTPS routing appears to be working but the HTTP backend acl is not matching the domain for some reason.

Here is where I am at:

frontend app
  bind 0.0.0.0:5000
  mode tcp
  option tcplog

  tcp-request inspect-delay 5s
  tcp-request content accept if HTTP
  tcp-request content accept if { req.ssl_hello_type 1 }


  use_backend testing_http if HTTP

  default_backend testing_https



backend testing_https
  mode tcp

  acl app_2 req.ssl_sni -i foo.bar.com

  use-server server2 if app_2
  use-server default if !app_2

  server server2 127.0.0.1:777
  server default 127.0.0.1:443



backend testing_http
  mode http

  acl app_2 hdr(host) -i foo.bar.com

  use-server server2 if app_2
  use-server default if !app_2

  server server2 127.0.0.1:777
  server default 127.0.0.1:80

I am posting an answer to my own question because I have been able to piece something together and this question doesn't seem to have any interest. If it comes up in a google search, this should help someone.

The following seems to work for me so far:

frontend app
  bind 0.0.0.0:5000
  mode tcp
  option tcplog

  tcp-request inspect-delay 5s
  tcp-request content accept if HTTP
  tcp-request content accept if { req.ssl_hello_type 1 }


  use_backend testing_http if HTTP

  default_backend testing_https



backend testing_https
  mode tcp

  acl app_2 req.ssl_sni -i foo.bar.com

  use-server server2 if app_2
  use-server default if !app_2

  server server2 127.0.0.1:777
  server default serverfault.com:443



backend testing_http
  mode http

  acl app_2 hdr_dom(host) -i foo.bar.com

  use-server server2 if app_2
  use-server default if !app_2

  server server2 127.0.0.1:777
  server default www.example.com:80

The important parts to understand -- frontend checks if the request is HTTP. If it isn't, it checks if it is an SNI request. Otherwise, it doesn't accept.

The other part that tripped me up was the host matching on the http backend. It was important to use domain matching with hdr_dom instead of hdr so that a manually specified port in the string doesn't break the acl.

The most difficult part is that tcp mode on the front end has unhelpful logging for http. And since the http backend can't log, you don't get any http information.