Mixing TLS termination and SNI passthrough in one haproxy configuration


I am trying to have one listener both do “TLS passthrough” with SNI (when requesting https://other.example.org/ and terminate TLS for everything else.

The TLS passthrough for other.example.org is working.

Also, when I connect with curl to the unix socket on /var/run/haproxy.sock I get the expected certificate from /etc/haproxy/certs/acme.

However, when I connect to port 443 with another SNI servername I get a TLS handshake error (openssl s_client says 140735681221512:error:140790E5:SSL routines:ssl23_write:ssl handshake failure:s23_lib.c:177:.


    log /var/run/log local0 debug
    uid 65534
    gid 65534
    stats socket /var/run/haproxy.stat mode 600 level admin
    maxconn 400
    ulimit-n 81000

    ssl-default-bind-options no-sslv3 no-tls-tickets
    tune.ssl.default-dh-param 1024

    log global
    option tcplog
    option http-server-close
    #option httpclose
    option redispatch
    retries                 3
    timeout http-request    10s
    timeout queue           1m
    timeout connect         10s
    timeout client          1m
    timeout server          1m
    timeout http-keep-alive 20s
    timeout check           10s
    maxconn                 5000

frontend admin
    bind  *:5000
    mode                http
    option              httplog
    default_backend     stats_auth
    monitor-uri         /ping

backend stats_auth
    mode http	
    stats enable
    stats auth  admin:verysecret
    stats admin if TRUE
    stats uri     /admin?stats
    stats refresh 30s

frontend tls
  bind *:443
  mode tcp
  tcp-request inspect-delay 5s
  tcp-request content accept if { req_ssl_hello_type 1 }
  use_backend other-tls if { req_ssl_sni -i other.example.org }
  default_backend https-back

backend https-back
    mode tcp
    server https-front unix@/var/run/haproxy.sock send-proxy-v2

frontend https-front
    bind   unix@/var/run/haproxy.sock ssl crt /etc/haproxy/certs/acme/ accept-proxy
    mode   http
    #option httplog
    option forwardfor
    reqdel X-Forwarded-Proto
    reqadd X-Forwarded-Proto:\ https if { ssl_fc }

    default_backend local

frontend http
    bind *:80
    mode   http
    option httplog
    option forwardfor

    reqdel X-Forwarded-Proto
    reqadd X-Forwarded-Proto:\ https if { ssl_fc }

    acl letsencrypt-request path_beg -i /.well-known/acme-challenge/
    redirect scheme https if !{ ssl_fc } !letsencrypt-request

    use_backend other if { hdr(host) -i other.example.org }

    use_backend acmetool if letsencrypt-request
    default_backend local

backend local
    mode   http
    server local

backend other
    mode   http
    server other

backend other-tls
    mode tcp
    server other

backend acmetool
    mode   http
    server acmetool

I think this is just a permission problem on the unix socket. Think about it, you bind the listening socket with root privileges, but access it with uid 65534; gid 65534.

Try replacing it with a TCP port on or add uid 65534 gid 65534 to the bind line in frontend https-front.

1 Like

Thanks Lukas, you are a genius! :smile:

As soon as I skimmed the word “permission” in the email notification I got from discourse I knew you’d figured it out for me.

Thank you. I’d stared at it for way too long without getting anywhere (or getting any useful logs out of haproxy, even when running with “-d”).

1 Like

Thanks a lot for this, @ask!

Part to the issue for me is that I didn’t know what the terms to search for this were. I’ll include them here for SEO…I was looking for:

  • Preventing haproxy from handling ssl handshake
  • Serving certificate only for some traffic on port 443 with HAProxy
1 Like