Can a Reverse Proxy use SNI with SSL pass through?

Solution 1:

This IS possible with Haproxy. You can setup a TCP proxy and extract the SNI and do routing based on the SNI. Here's an example:

backend be.app1
    mode tcp
    no option checkcache
    no option httpclose
    tcp-request inspect-delay 5s
    tcp-request content accept if { req.ssl_hello_type 1 }
    tcp-request content reject
    use-server server1 if { req.ssl_sni -m beg app1. }
    server server1 server1:8443 check id 1 weight 0

It is essential to delay the request until you get the SSL hello, otherwise haproxy will try to make a connection before receiving the SNI header.

I am using servers with weight 0 because, in my current configuration, I only have one server running for each SNI and I don't want them to receive random requests. You can probably find better ways to play with this.

I hope this helps.

Solution 2:

You can use sniproxy : https://github.com/dlundquist/sniproxy

An example configuration :

listener 0.0.0.0:443 {
    protocol tls
    table TableHTTPS
    fallback 127.0.0.1:8443
}

listener 0.0.0.0:80 {
    protocol http
    table TableHTTP
    fallback 127.0.0.1:8080
}

table TableHTTPS {
    domain1.com backend1:443
    domain2.org backend2:443
}

table TableHTTP {
    domain1.com backend1:80
    domain2.org backend2:80
}

Solution 3:

This is certainly possible, even now in 2019 with the upcoming TLS 1.3! Many web servers or specialized reverse proxies provide this functionality out of the box:

  • Nginx ≥ 1.11.5 (Debian ≥ buster or stretch-backports)
  • HAProxy ≥ 1.5 (Debian ≥ jessie)
  • Sniproxy (Debian ≥ buster)
  • etc.

This is an example configuration for Nginx, which is a very popular choice for setups that require a reverse proxy:

stream {
  map $ssl_preread_server_name $selected_upstream {
    example.org upstream_1;
    example.net upstream_2;
    example.com upstream_3;
    default upstream_4;
  }
  upstream upstream_1 { server 10.0.0.1:443; }
  upstream upstream_2 { server 10.0.0.2:443; }
  upstream upstream_3 { server 10.0.0.3:443; }
  upstream upstream_4 { server 10.0.0.4:443; }
  server {
    listen 10.0.0.5:443;
    proxy_pass $selected_upstream;
    ssl_preread on;
  }
}

The relevant Nginx modules are stream_core and stream_ssl_preread. Manuals:

  • https://nginx.org/en/docs/stream/ngx_stream_core_module.html
  • https://nginx.org/en/docs/stream/ngx_stream_ssl_preread_module.html