Can a Reverse Proxy use SNI with SSL pass through?

23,904

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

This is certainly possible, even now in 2021 with more and more widespread 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:

Solution 3

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 4

Be aware that if the target servers use the same certificate (which is not very unlikely when wildcard certificates are in use), then HTTP/2 can not be used. It will route your traffic to the wrong server.

Sample:

  • a.example.com with certificate *.example.com
  • b.example.com with certificate *.example.com

If a.example.com and b.example.com are handled by the same reverse proxy then a single connection will be opened - and streamed to the server that is called for the first time. So if you call a.example.com, future requests to b.example.com may reach the wrong web server.

For reference, see

Share:
23,904

Related videos on Youtube

user319862
Author by

user319862

Updated on September 18, 2022

Comments

  • user319862
    user319862 over 1 year

    I need to serve several applications over https using one external ip address.

    The ssl certificates should not be managed on the reverse proxy. They are installed on the application servers.

    Can a reverse proxy be configured to use SNI and pass ssl through for termination at the endpoint?

    Is this possible using something like Nginx or Apache? What does the configuration look like?

  • user319862
    user319862 over 9 years
    Can you point me towards any documentation of this or a configuration snippet so I can accept the answer?
  • Michael Hampton
    Michael Hampton over 9 years
    @user319862 I found this nice tutorial which seems to be what's being discussed.
  • Florin Asăvoaie
    Florin Asăvoaie over 9 years
    Really? Why would someone downvote this answer?
  • user319862
    user319862 over 8 years
    Thanks for posting about that project. I was not aware of it
  • kyrofa
    kyrofa about 7 years
    The problem with this is that the IP address of the client doesn't get forwarded, so the server only ever sees traffic coming from the proxy.
  • Florin Asăvoaie
    Florin Asăvoaie about 7 years
    @Kyle Of course. It is TCP proxy. The only thing you can do about this is if you configure and set haproxy as a router for the server and use tproxy.
  • rafalefighter
    rafalefighter about 7 years
    @mick Hi mick when run SNI as a transparent proxy it break some sites wiht SSL errors. How to fix it ?
  • Michael Hampton
    Michael Hampton over 5 years
    @Kyle Even back when this answer was written haproxy had an answer for that, the PROXY protocol. It's supported in Apache, nginx, and many other web servers.
  • Benny Jobigan
    Benny Jobigan about 3 years
    Thanks for this recommendation. I choose to use sniproxy over nginx due to its comparatively simple config.
  • Tyris
    Tyris about 3 years
    Thanks for this answer, helped me solve this exact issue - where I had a common IP with a shared SSL certificate proxying to separate upstream services. The easiest solution seems to be to configure the upstream server to return a 421 if it receives messages intended for an unexpected endpoint. For me this looked like: server { listen 443 ssl http2 proxy_protocol default_server; listen [::]:443 ssl http2 proxy_protocol default_server; server_name _; # may need ssl certs here return 421; }