When is Nginx serving wrong virtual host (vhost) SSL certificate

Nginx serving wrong virtual host (vhost) SSL certificate

How to correctly setup SSL certificates with Nginx serving multiple https virtual hosts

Eager to serve valuable content from your new Linux SSD VPS server via multiple domains ?

You just deployed a new Linux VPS server in one of VPSie datacenters, optimized it’s security, installed nginx, mysql, php and you’ve got your SSL certificates ready.

After copying https virtual hosts configuration from an old nginx vps server or from the internet, you set up your virtual hosts as below:
Nginx SSL Virtual host 1


root@ubuntu-vps:/etc/nginx/conf.d# cat server1.conf
server {
        server_name server1.domain.com;
        #server_name server1.domain.com;
        server_tokens off;

        listen       10.1.1.60:443 ssl;
        ssl                  on;
        ssl_certificate      /etc/nginx/server1.pem;
        ssl_certificate_key  /etc/nginx/private.key;
        ssl_session_timeout  5m;
        ssl_protocols  TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers ECDHE-ECDSA-AES128-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:AES128-SHA:AES256-SHA:ECDHE-RSA-RC4-SHA:DHE-RSA-AES128-SHA;
        ssl_prefer_server_ciphers   on;
        ssl_ecdh_curve secp521r1;
        ssl_session_cache shared:SSL:10m;

        root /var/www/public_html/server1;
        index index.html index.htm;
}

Nginx SSL Virtual host 2


root@ubuntu-vps:/etc/nginx/conf.d# cat server2.conf
server {
        server_name server2.domain.com;
        server_tokens off;

        listen       443 ssl;
        ssl                  on;
        ssl_certificate      /etc/nginx/server2.pem;
        ssl_certificate_key  /etc/nginx/private.key;
        ssl_session_timeout  5m;
        ssl_protocols  TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers ECDHE-ECDSA-AES128-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:AES128-SHA:AES256-SHA:ECDHE-RSA-RC4-SHA:DHE-RSA-AES128-SHA;
        ssl_prefer_server_ciphers   on;
        ssl_ecdh_curve secp521r1;
        ssl_session_cache shared:SSL:10m;

        root /var/www/public_html/server2;
        index index.html index.htm;
}

Everything should be working. First you test https://server1.domain.com and you find that it is working properly (no warnings are displayed). When you check https://server2.comain.com you notice a warning in your browser:
Nginx serving wrong virtual host (vhost) SSL certificate

Why is nginx serving the public certificate for server1.domain.com when my browser requests server2.domain.com ?

Troubleshooting wrong https

virtual host

 certificate served by NGINX

Let’s confirm that the browser is correctly sending the Server Name Indication in clear text so that NGINX has a chance to look at the domain before actual encrypting/decrypting any data. We take a look at the hex format of the “Client Hello” SSL handshake packet sent by the browser to nginx, in tcpdump:


22:25:29.100189 IP 192.168.3.100.57413 > 10.1.1.60.443: Flags [P.], seq 1:209, ack 1, win 4117, options [nop,nop,TS val 626190298 ecr 540309], length 208
	0x0000:  4500 0104 84e8 4000 3f06 e6c2 c0a8 0364  E.....@.?......d
	0x0010:  0a01 013c e045 01bb e739 71fe 1a4d 0a0e  ...............S
	0x0040:  091a 6b0c 9463 6bc2 9987 7506 bd72 a40c  ..k..ck...u..r..
	0x0050:  005b 23e3 1f22 17ec 3026 055e 78d1 8800  .[#.."..0&.^x...
	0x0060:  0020 c02b c02f c00a c009 c013 c014 c007  ...+./..........
	0x0070:  c011 0033 0032 0039 002f 0035 000a 0005  ...3.2.9./.5....
	0x0080:  0004 0100 007e 0000 0017 0015 0000 1273  .....~.........s
	0x0090:  6572 7665 7232 2e64 6f6d 6169 6e2e 636f  erver2.domain.co   --> SNI
	0x00a0:  6dff 0100 0100 000a 0008 0006 0017 0018  m...............
	0x00b0:  0019 000b 0002 0100 0023 0000 3374 0000  .........#..3t..
	0x00c0:  0010 0021 001f 0568 322d 3134 0873 7064  ...!...h2-14.spd
	0x00d0:  792f 332e 3106 7370 6479 2f33 0868 7474  y/3.1.spdy/3.htt
	0x00e0:  702f 312e 3100 0500 0501 0000 0000 000d  p/1.1...........
	0x00f0:  0012 0010 0401 0501 0201 0403 0503 0203  ................
	0x0100:  0402 0202                                ….

We confirm that the packet from client to https server (destination port 443) contains server2.domain.com as the SNI.
And we take the same look at the “Server hello” TCP packet returned by the nginx https server:


22:30:28.182532 IP 10.1.1.60.443 > 192.168.3.100.57454: Flags [P.], seq 1:1346, ack 209, win 235, options [nop,nop,TS val 615080 ecr 626487909], length 1345
	0x0000:  4500 0575 6a13 4000 4006 fc26 0a01 013c  E..uj.@.@..&...<
	0x0010:  c0a8 0364 01bb e06e d775 08b5 5365 cf91  ...d...n.u..Se..
	0x0020:  8018 00eb d4b0 0000 0101 080a 0009 62a8  ..............b.
	0x0030:  2557 7265 1603 0300 4a02 0000 4603 0303  %Wre....J...F...
	0x0040:  a4f0 db9e e0da b40e 82c6 9125 5bca b516  ...........%[...
	0x0050:  e199 e450 1522 339c d201 f8dd d110 6100  ...P."3.......a.
	0x0060:  c02f 0000 1eff 0100 0100 000b 0004 0300  ./..............
	0x0070:  0102 0023 0000 3374 0009 0868 7474 702f  ...#..3t...http/
	0x0080:  312e 3116 0303 034e 0b00 034a 0003 4700  1.1....N...J..G.
	0x0090:  0344 3082 0340 3082 0228 0209 00df 5d29  .D0..@0..(....])
	0x00a0:  dac3 4bd0 f930 0d06 092a 8648 86f7 0d01  ..K..0...*.H....
	0x00b0:  010b 0500 3062 310b 3009 0603 5504 0613  ....0b1.0...U...
	0x00c0:  0241 5531 1330 1106 0355 0408 0c0a 536f  .AU1.0...U....So
	0x00d0:  6d65 2d53 7461 7465 3121 301f 0603 5504  me-State1!0...U.
	0x00e0:  0a0c 1849 6e74 6572 6e65 7420 5769 6467  ...Internet.Widg
	0x00f0:  6974 7320 5074 7920 4c74 6431 1b30 1906  its.Pty.Ltd1.0..
	0x0100:  0355 0403 0c12 7365 7276 6572 312e 646f  .U....server1.do  --> SSL certificate "Common Name"
	0x0110:  6d61 696e 2e63 6f6d 301e 170d 3135 3032  main.com0...1502
	0x0120:  3233 3230 3436 3531 5a17 0d31 3630 3232  23204651Z..16022
	0x0130:  3332 3034 3635 315a 3062 310b 3009 0603  3204651Z0b1.0...
	0x0140:  5504 0613 0241 5531 1330 1106 0355 0408  U....AU1.0...U..
	0x0150:  0c0a 536f 6d65 2d53 7461 7465 3121 301f  ..Some-State1!0.
	0x0160:  0603 5504 0a0c 1849 6e74 6572 6e65 7420  ..U....Internet.
	0x0170:  5769 6467 6974 7320 5074 7920 4c74 6431  Widgits.Pty.Ltd1
	0x0180:  1b30 1906 0355 0403 0c12 7365 7276 6572  .0...U....server
	0x0190:  312e 646f 6d61 696e 2e63 6f6d 3082 0122  1.domain.com0..”

You will notice that the server, indeed sends a certificate valid for server1.domain.com.

What can we troubleshoot further ?

Debug SSL certificate problem with OpenSSL s_client

If we confirm that remote https clients are sending correct SNI, let’s see what OpenSSL reports when initating an https connection to nginx on the localhost.

root@ubuntu-vps:/etc/nginx/conf.d# openssl s_client -connect localhost:443 -servername server2.domain.com
CONNECTED(00000003)
depth=0 C = AU, ST = Some-State, O = Internet Widgits Pty Ltd, CN = server2.domain.com
verify error:num=18:self signed certificate
verify return:1
depth=0 C = AU, ST = Some-State, O = Internet Widgits Pty Ltd, CN = server2.domain.com
verify return:1
---
Certificate chain
 0 s:/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=server2.domain.com
   i:/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=server2.domain.com

Note: The “-servername” directive sets the SNI in the “Client Hello” packets. It is added in recent versions of openssl.

So we have two situations: Remote clients accessing nginx server via https to IP 10.1.1.60 receive a certificate for server1.domain.com and localhost client receives certificate for server2.domain.com. In both situations server2.domain.com is requested.

The only obvious place is the virtual host configurations in nginx, specifically the “listen” lines:


root@ubuntu-vps:/etc/nginx/conf.d# grep listen *
server1.conf:        listen       10.1.1.60:443 ssl;
server2.conf:        listen       443 ssl;

 

The reason behind it is that server2 vhost configuration instructs nginx to server https over port 443, without specifying the IP address to serve it on. It looks like NGINX interprets this as listen to localhost when other https virtual hosts are configured for that specific IP address.

This nginx behavior can be rectified by either removing the IP from server1 vhost configuration or adding it to to server2 vhost configuration.

 

You can actually try those configuration on our platform in few minutes utilizing our PCS (Private Cloud Solution) which allows you to have VPSie(s) on a private network – NAT – Port forward – traffic control for inbound and outbound – multiple gateway IPs which you could use for the load-balancing and failover.

Related Articles