Nginx – Prevent SSL Server Block from Acting as Catchall

nginxssl

I have a web server with many virtual servers. Only 1 of which is SSL. The problem is, because there is no catchall server block listening for SSL, any https request to the other sites is served by the 1 SSL block.

My configuration, essentially, looks like this:

# the catch all
server {
  listen 80 default;

  # I could add this, but since I have no default cert, I cannot enable SSL,
  # and this listen ends up doing nothing (apparently).
  # listen 443; 

  server_name _;
  # ...
}

# some server
server {
  listen 80;
  server_name server1.com;
  # ...
}

# some other server ...
server {
  listen 80;
  server_name server2.com;
  # ...
}

# ... and it's https equivalent
server {
  listen 443;
  ssl on;
  server_name server2.com;
  # ...
}

Now as there's no default listener for 443, a request like https://server1.com will end up being served by the server2.com https block. This follows the logic for server_name in the docs.

If there is no match, a server { … } block in the configuration
file will be used based on the following order:

  1. the server block with a matching listen directive marked as [default|default_server]
  2. the first server block with a matching listen directive (or implicit listen 80;)

What is the preferred solution for this problem? Do I need to set up dummy cert for my catch all server block just so I can listen on 443 and handle the bad requests? Is there a parameter I'm unaware of that forces an exact hostname match with server?

Best Answer

Ideally either I'd like nginx to not serve https at all unless the hostname matches, or for it to redirect to http at the same host.

Neither is possible. The connection from a client that goes to https://foo.example.com/ cannot be accepted by anything but an SSL certificate with "foo.example.com" as one of its names. There is no opportunity to redirect until the SSL connection is accepted.

If you configure each site for SSL, a user who clicks through the certificate error will get the site they requested. If you configure a "catch all" site for SSL that provides only an error page and configure name-based virtual hosting for the one site that is supposed to support SSL, you can serve an error page to clients.

SSL and HTTP virtual hosting just don't play nicely together.