Why is nginx responding to any domain name?

Martin picture Martin · Mar 22, 2012 · Viewed 110.2k times · Source

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?

Answer

Dayo picture Dayo · Mar 22, 2012

The first server block in the nginx config is the default for all requests that hit the server for which there is no specific server block.

So in your config, assuming your real domain is REAL.COM, when a user types that in, it will resolve to your server, and since there is no server block for this setup, the server block for FAKE.COM, being the first server block (only server block in your case), will process that request.

This is why proper Nginx configs have a specific server block for defaults before following with others for specific domains.

# Default server
server {
    return 404;
}

server {
    server_name domain_1;
    [...]
}

server {
    server_name domain_2;
    [...]
}

etc

** EDIT **

It seems some users are a bit confused by this example and think it is limited to a single conf file etc.

Please note that the above is a simple example for the OP to develop as required.

I personally use separate vhost conf files with this as so (CentOS/RHEL):

http {
    [...]
    # Default server
    server {
        return 404;
    }
    # Other servers
    include /etc/nginx/conf.d/*.conf;
}

/etc/nginx/conf.d/ will contain domain_1.conf, domain_2.conf... domain_n.conf which will be included after the server block in the main nginx.conf file which will always be the first and will always be the default unless it is overridden it with the default_server directive elsewhere.

The alphabetical order of the file names of the conf files for the other servers becomes irrelevant in this case.

In addition, this arrangement gives a lot of flexibility in that it is possible to define multiple defaults.

In my specific case, I have Apache listening on Port 8080 on the internal interface only and I proxy PHP and Perl scripts to Apache.

However, I run two separate applications that both return links with ":8080" in the output html attached as they detect that Apache is not running on the standard Port 80 and try to "help" me out.

This causes an issue in that the links become invalid as Apache cannot be reached from the external interface and the links should point at Port 80.

I resolve this by creating a default server for Port 8080 to redirect such requests.

http {
    [...]
    # Default server block for undefined domains
    server {
        listen 80;
        return 404;
    }
    # Default server block to redirect Port 8080 for all domains
    server {
        listen my.external.ip.addr:8080;
        return 301 http://$host$request_uri;
    }
    # Other servers
    include /etc/nginx/conf.d/*.conf;
}

As nothing in the regular server blocks listens on Port 8080, the redirect default server block transparently handles such requests by virtue of its position in nginx.conf.

I actually have four of such server blocks and this is a simplified use case.