Nginx as reverse proxy and SNI

I had some difficulty to find a good title for this article that would really cover the contents. Therefore, let me start with describing the problem I faced which led to this article.

I have a lot of sites running on my home server (this blog being one of them) using different technologies. As I have a single IPv4 address, all these sites are behind a reverse proxy, for which I use Nginx. A couple of those sites are Domino sites and last week I realised there was something wrong in that area. I have several internet site documents on Domino for different urls. However, last week I realised that all my urls that were forwarded to Domino, were being serviced based on the same internet site document. In other words, Domino did not recognise for which internet site a request was meant.

Important to know is how the traffic is forwarded. In this case, Nginx does SSL offloading and onloading when it sends traffic to Domino, so the proxy_pass directive is pointing to a https:// address. If I would replace the https:// with http:// (no SSL onloading), the problem would be gone. However, that causes other problems like not being to able to use Bearer tokens for authentication.

In the old days, every SSL Internet site in Domino would have to have its own IP address, but that’s no longer the case. Server Name Indication (SNI), the TLS extension which allows multiple TLS protected sites on the same IP address, was introduced in HCL Domino in version 11.0.1 (released in April 2020). However, if Domino is behind a reverse proxy, for SNI to work, the reverse proxy does have to pass through the server name, and that’s something that I had not configured.

Configuring Nginx for SNI Passthrough

Which brings us to the topic of this article. How to get Nginx to pass through the server name to the downstream HTTP server? It’s actually quite simple, once you know it. There are two directives in the ngx_stream_proxy_module (that’s responsible for proxying requests) to enable this:

Syntax:proxy_ssl_name name;
Default:proxy_ssl_name host from proxy_pass;
Context:streamserver

Allows overriding the server name used to verify the certificate of the proxied server and to be passed through SNI when establishing a connection with the proxied server. The server name can also be specified using variables (1.11.3).

By default, the host part of the proxy_pass address is used.

Most of the time, you either proxy to an IP address or to an internal dns name of the server, so using the proxy_pass address is usually not helpful.

Syntax:proxy_ssl_server_name on | off;
Default:proxy_ssl_server_name off;
Context:streamserver

Enables or disables passing of the server name through TLS Server Name Indication extension (SNI, RFC 6066) when establishing a connection with the proxied server.

This directive is necessary to make sure the server name is passed along in the proxy request.

So, to summarise, you will have to add these two lines to enable SNI passthrough:

            proxy_ssl_name          $host;
            proxy_ssl_server_name   on;

This will grab the hostname from the incoming request and pass it on to downstream server.