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.