[nginx] Why is nginx responding to any domain name?

I have nginx up and running with a Ruby/Sinatra app and all is well. However, I'm now trying to have a second application running from the same server and I noticed something weird. First, here's my nginx.conf:

pid /tmp/nginx.pid;
error_log /tmp/nginx.error.log;

events {
  worker_connections 1024;
  accept_mutex off;
}

http {
  default_type application/octet-stream;
  access_log /tmp/nginx.access.log combined;

  sendfile on;
  tcp_nopush on;
  tcp_nodelay off;

  gzip on;
  gzip_http_version 1.0;
  gzip_proxied any;
  gzip_min_length 500;
  gzip_disable "MSIE [1-6]\.";
  gzip_types text/plain text/xml text/css
             text/comma-separated-values
             text/javascript application/x-javascript
             application/atom+xml;

  upstream app {
    server unix:/var/www/app/tmp/sockets/unicorn.sock fail_timeout=0;
  }

  server {
    listen 80;
    client_max_body_size 4G;
    server_name FAKE.COM;

    keepalive_timeout 5;

    root /var/www/app/public;

    location / {
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $http_host;
      proxy_redirect off;

      if (!-f $request_filename) {
        proxy_pass http://app;
        break;
      }
    }

    error_page 500 502 503 504 /500.html;
    location = /500.html {
      root /var/www/app/public;
    }
  }
}
                                                          68,0-1        B

Notice how server_name is set to FAKE.COM yet the server is responding to all hosts that hit that server via other domain names. How can I make that particular server respond only to requests for FAKE.COM?

This question is related to nginx

The answer is


I was unable to resolve my problem with any of the other answers. I resolved the issue by checking to see if the host matched and returning a 403 if it did not. (I had some random website pointing to my web servers content. I'm guessing to hijack search rank)

server {
    listen 443;
    server_name example.com;

    if ($host != "example.com") {
        return 403;
    }

    ...
}

You should have a default server for catch-all, you can return 404 or better to not respond at all (will save some bandwidth) by returning 444 which is nginx specific HTTP response that simply close the connection and return nothing

server {
    listen       80  default_server;
    server_name  _; # some invalid name that won't match anything
    return       444;
}

To answer your question - nginx picks the first server if there's no match. See documentation:

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...

Now, if you wanted to have a default catch-all server that, say, responds with 404 to all requests, then here's how to do it:

server {
    listen 80 default_server;
    listen 443 ssl default_server;
    server_name _;
    ssl_certificate <path to cert>
    ssl_certificate_key <path to key>
    return 404;
}

Note that you need to specify certificate/key (that can be self-signed), otherwise all SSL connections will fail as nginx will try to accept connection using this default_server and won't find cert/key.


There are few ways to specify default server.

First way - Specify default server first in list, if you keep your server configurations in one config file, like Dayo showed above.

Second way (better) More flexible - provide default_server parameter for listen instruction, for example:

server {
    listen  *:80 default_server;
    root /www/project/public/;
}

More information here: Nginx doc / Listen

This way more useful when you keep server configurations in separate files and do not want to name those files alphabetically.


Little comment to answer:

if you have several virtual hosts on several IPs in several config files in sites-available/, than "default" domain for IP will be taken from first file by alphabetic order.

And as Pavel said, there is "default_server" argument for "listen" directive http://nginx.org/en/docs/http/ngx_http_core_module.html#listen