1

The problem

I have an nginx server serving 3 subdomains - say a.example.com, b.example.com, and c.example.com.

The configuration files are a.example.com.conf, b.example.com.conf, and c.example.com.conf respectively. They are stored in /etc/nginx/sites-available and soft-linked from /etc/nginx/sites-enabled.

In the configuration files, each server clause has its appropriate server_name directive. If it matters, all three subdomains use the same SSL certificate issues by Let's Encrypt (which works fine).

When b.example.com.conf is removed from sites-enabled, I expect an error message when trying to browse to it. Surprisingly, nginx redirects the traffic to a.example.com. In fact, every incoming connection without a matching server name in /etc/nginx/sites-enabled - including just the machine IP - is routed to a.example.com.

How to configure nginx to make the server directive exclusive, so that requests to b.example.com will never be served by a.example.com?

Configuration

a.example.com.conf

server {
    listen 443 ssl;
    server_name a.example.com;

    ssl_certificate     /etc/letsencrypt/live/a.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/a.example.com/privkey.pem;

    location / {
        proxy_pass http://localhost:8080;
    }
}

b.example.com.conf

server {
    listen 443 ssl;
    server_name b.example.com;

    # I'm using a multi-domain certificate called `a.example.com`, which is
    # serving a.example.com, b.example.com and c.example.com - not an error

    ssl_certificate     /etc/letsencrypt/live/a.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/a.example.com/privkey.pem;

    location / {
        proxy_pass http://localhost:8090;
    }
}

Temporary solution

I have created a default server that catches all default requests and returns error 404. However, I would like to have a more holistic solution preventing requests from any given server served by another server.

server {
    listen       443  default_server;
    server_name  _;
    return       404;

    ssl_certificate     /etc/letsencrypt/live/a.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/a.example.com/privkey.pem;
}
Adam Matan
  • 13,194
  • 19
  • 55
  • 75

1 Answers1

5

From nginx documentation:

In this configuration nginx tests only the request’s header field “Host” to determine which server the request should be routed to. If its value does not match any server name, or the request does not contain this header field at all, then nginx will route the request to the default server for this port. In the configuration above, the default server is the first one — which is nginx’s standard default behaviour.

So your temporary solution seems to be the right solution.

Guido Vaccarella
  • 1,418
  • 14
  • 13