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: stream
,server
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: stream
,server
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.
Thank you sir, you saved me a lot of trouble figuring out how to proxy pass SSL correctly just now. My usecase was similar, although I needed to configure a NextCloud-instance behind my Webproxy.
Let’s mention that some more specific for the search engines to find: nextcloud reverse proxy nginx sni ssl
Thanks! Have a great day! š
Iām glad that I could be of help. Thanks for letting me know.