Nginx one ip and multiple ssl certificates

Nginx uses a "default server" that it picks to serve pages when there isn't another closest match. If you haven't specified the default server to use, I believe it uses the first that it finds (which in your case is one of your HTTPS sites). So you should be able to create a default server vhost with your IPv4 address for TLS (you are using only TLS and not SSL anymore right?) and have it listen on the IP that will catch the random HTTPS requests. You might also need to add the server_name item in there too for your 48 non-secure sites, but it may work without that.

#Your catch-all HTTPS server:
server {
  listen 104.218.234.204:443 default_server;
  server_name ruel.in ruel.pro;
  root /var/www/ruel.pro;
  index index.html;
  ssl on;
  ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
  ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
  ssl_dhparam /etc/ssl/private/dhparams_4096.pem;
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
}

#Regular HTTP server
server {
  listen ruel.in:80;
  server_name ruel.in;
  root /var/www/ruel.in;
  index index.php index.html index.htm;
  ...
}

#Regular HTTP server
server {
  listen ruel.pro:80;
  server_name ruel.pro;
  root /var/www/ruel.pro;
  index index.php index.html index.htm;
  ...
}

#Your HTTPS server
server {
  listen dallas.ruhnet.net:443 ssl;
  server_name dallas.ruhnet.net;
  ...
}

Another alternative is to go ahead and set them all up with HTTPS! With the Let's Encrypt project (https://www.letsencrypt.org) you can get trusted certificates for all those other sites for free. And it's quite easy.


I'm familiar with the issue.

We basically want to avoid at all cost that the first server definition in our config file is served as a catch-all-server for SSL connections. We all know that it does that (opposed to http and using default_server config which works nicely).

This cannot be achieved declaratively in Nginx for SSL (yet) so we have to code it with an IF...

The variable $host is the host name from the request line or the http header. The variable $server_name is the name of the server block we are in right now.

So if these two are not equal then you served this SSL server block for another host so that should be blocked.

We can implement this in each server block (with a generic include of course).

The code does not contain specific references to your server IP addresses or server names so it can easily be reused for other server configs without modification.

Example:

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    ###
    ### Section: SSL

    #
    ## Check if this certificate is really served for this server_name
    ##   http://serverfault.com/questions/578648/properly-setting-up-a-default-nginx-server-for-https
    if ($host != $server_name) {
        #return 404 "this is an invalid request";
        return       444;
    }

    # ...