Nginx – Fix SNI and HTTP Hostname Mismatch

nginxssl

I have been having an SSL website in one of my servers for a while without have any issues, then I had to add a second SSL website in the same server using the same port (4433). My configuration looks like this: I have two nginx front end and apache back end websites in my server, both with the same exact configuration (except for the server name, etc).

My problems started to arise that when I hit one of the websites and then I visit the second website, then I see the following error in the browser:

Your browser sent a request that this server could not understand.

Then I looked at apache error log and I see the following error in there:

[Fri Nov 09 16:17:51.247904 2018] [ssl:error] [pid 18614] AH02032:
Hostname firstwebsite.intweb.net provided via SNI and hostname
secondwebsite.intweb.net provided via HTTP are different

So, I decided to isolate the problem to see if the problem was coming from nginx or the way apache process the data received from nginx. First, I try to do it with nginx by just having nginx to be in the front and backend with the proxy_pass https://127.0.0.1:44133 call.

What it was a susprise for me is that the problem is in nginx, as you can see in the following curl calls, I could see that in fact the backend sni and the backend hostheader were for some reason different in the second website I try to hit.

Here is the proof:

[root@webdev http]# curl -I https://firstwebsite.intweb.net
HTTP/1.1 200 OK
Server: nginx/1.12.0
Date: Thu, 29 Nov 2018 00:08:05 GMT
Content-Type: application/octet-stream
Content-Length: 0
Connection: keep-alive
X-backend-ssl-sni: firstwebsite.intweb.net
X-backend-hostheader: firstwebsite.intweb.net
Strict-Transport-Security: max-age=31536000

[root@webdev http]# curl -I https://secondwebsite.intweb.net
HTTP/1.1 200 OK
Server: nginx/1.12.0
Date: Thu, 29 Nov 2018 00:08:10 GMT
Content-Type: application/octet-stream
Content-Length: 0
Connection: keep-alive
X-backend-ssl-sni: firstwebsite.intweb.net
X-backend-hostheader: secondwebsite.intweb.net
Strict-Transport-Security: max-age=31536000

And this will happen the other way around as well, I mean, if I call the seconwebsite first and then the firstwebsite second, I will get the backend-sni and the backend hostheader with the same value for the secondwebsite but different for the firstwebsite. It would be like if there was like any kind of caching or something similar. I really don't have any idea what could be happening.

Here are the configuration files for each one of the websites:

First website conf: https://paste.ngx.cc/9b

Second website conf: https://paste.ngx.cc/43

Any help on this will be greatly appreciated.

Best Answer

Apache 2.2 (that you use; end of life btw) strictly forbids different SNI hostname and Host hostname. Apache 2.4 relaxes that condition and only failing if:

"The request does not select the virtual host that was selected by the SNI and its SSL parameters are different"

https://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/ssl/ssl_engine_kernel.c?view=annotate#l335

nginx reuses backend connections if keepalive is enabled but you don't have that in your configs.

Looking into nginx source code there are other possible conditions:

         * set u->keepalive if response has no body; this allows to keep
         * connections alive in case of r->header_only or X-Accel-Redirect

Solutions: switch to apache 2.4.

Workarounds: do not use https between frontend and backend (especially that in your setup both are on the same machine). mod_rpaf and mod_remoteip will help exposing "fake" ssl information to other apache modules.