SSL Termination: Multiple Domains Sharing Same IP and Port

Hello,

With the following LB setup:

OS: Deban 10 (Buster)
HA-Proxy version: 2.2.19

Trying to compose a config for:

  • SSL Termination of many domains/sub-domains
  • Multiple domains/subdomains on shared IP and Ports, with support for different cert per address
  • HTTP mode (for cookie stickiness, etc.)

Having the following config, requesting https adresses (for example https://sub1.domain.com) results in SSL_ERROR_RX_RECORD_TOO_LONG error (Firefox) :

global
  daemon
  chroot /var/lib/haproxy
  user haproxy
  group haproxy
  stats socket /run/haproxy/admin.sock user haproxy group haproxy mode 660 level admin expose-fd listeners
  stats timeout 30s
  ssl-default-bind-options no-sslv3
  ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS
  log /dev/log local0
  log /dev/log local1 notice
  ca-base /etc/ssl/certs
  crt-base /etc/ssl/private

defaults
  mode http
  log global
  option httplog
  option dontlognull
  timeout connect 5000
  timeout client 50000
  timeout server 50000
  errorfile 400 /etc/haproxy/errors/400.http
  errorfile 403 /etc/haproxy/errors/403.http
  errorfile 408 /etc/haproxy/errors/408.http
  errorfile 500 /etc/haproxy/errors/500.http
  errorfile 502 /etc/haproxy/errors/502.http
  errorfile 503 /etc/haproxy/errors/503.http
  errorfile 504 /etc/haproxy/errors/504.http

frontend plain
  mode http
  bind abns@haproxy-tls-2 accept-proxy ssl crt /etc/haproxy/ssl/2.pem force-tlsv12
  bind abns@haproxy-tls-1 accept-proxy ssl crt /etc/haproxy/ssl/1.pem force-tlsv12
  bind abns@haproxy-plain accept-proxy
  use_backend plain-1 if { hdr(host) -i sub1.domain.com } { dst_port 80 }
  use_backend ssl-1 if { hdr(host) -i sub1.domain.com } { dst_port 443 }
  use_backend plain-2 if { hdr(host) -i sub2.domain.com } { dst_port 80 }
  use_backend ssl-2 if { hdr(host) -i sub2.domain.com } { dst_port 443 }

frontend splitter
  mode tcp
  bind *:80
  bind *:443
  tcp-request inspect-delay 5s
  use_backend plain-traffic if !{ ssl_fc }
  default_backend tls-traffic

backend plain-traffic
  mode tcp
  server plain-loopback abns@haproxy-plain send-proxy-v2

backend tls-traffic
  mode tcp
  tcp-request content accept if { req.ssl_hello_type 1 }
  server tls-loopback abns@haproxy-tls send-proxy-v2

frontend tls-swith
  mode tcp
  bind abns@haproxy-tls accept-proxy
  log global
  option tcplog
  use_backend ssl-1-loopback if { req_ssl_sni -i sub1.domain.com } { dst_port 443 }
  use_backend ssl-2-loopback if { req_ssl_sni -i sub2.domain.com } { dst_port 443 }

backend ssl-1-loopback
  mode tcp
  server ssl-1-recircular abns@haproxy-tls-1 send-proxy-v2

backend ssl-2-loopback
  mode tcp
  server ssl-2-recircular abns@haproxy-tls-2 send-proxy-v2

backend plain-1
  balance roundrobin
  server 1 192.168.20.101:80 check
  server 2 192.168.20.102:80 check

backend plain-2
  balance roundrobin
  server 1 192.168.20.101:80 check
  server 2 192.168.20.102:80 check

backend ssl-1
  balance roundrobin
  server 1 192.168.20.101:80 check
  server 2 192.168.20.102:80 check

backend ssl-2
  balance roundrobin
  server 1 192.168.20.101:80 check
  server 2 192.168.20.102:80 check

listen stats
  bind xxx.xxx.xxx.xxx:8404
  stats enable
  stats uri /monitor
  stats refresh 5s

program api
  command dataplaneapi -f /etc/haproxy/dataplaneapi.hcl
  no option start-on-reload

Logs for http://sub1.domain.com :

Jan  5 09:49:21 srv134135 haproxy[10921]: xxx.xxx.xxx.xxx:64754 [05/Jan/2022:09:49:21.440] plain plain-1/2 0/0/2/4/6 200 423 - - ---- 2/1/0/0/0 0/0 "GET / HTTP/1.1"

Logs for https://sub1.domain.com (related to the error) :

Jan  5 09:55:53 srv134135 haproxy[10921]: xxx.xxx.xxx.xxx:64882 [05/Jan/2022:09:55:53.769] splitter plain-traffic/plain-loopback 1/0/4 169 SD 1/1/0/0/0 0/0

What’s wrong?

Thanks.

This configuration does not make sense to me, let’s clarify what your goals are first.

You do not appear to have any domains where you need to pass through SSL transparently, without SSL termination.

All the SSL termination should happen on haproxy, correct? There are no (real) backends that expect traffic on port 443?

Why all those duplicates backends?

Unless your requirements are way more complicated, just configure both certificates on the bind line:

frontend fe1
  bind *:80
  bind *:443 ssl crt /etc/haproxy/ssl/2.pem crt /etc/haproxy/ssl/1.pem force-tlsv12 force-tlsv12
  default_backend be1

backend be1
  balance roundrobin
  server 1 192.168.20.101:80 check
  server 2 192.168.20.102:80 check