By Martin


2012-03-22 14:31:33 8 Comments

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?

6 comments

@Dayo 2012-03-22 16:37:37

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.

@Capaj 2013-02-25 08:28:40

Nginx requires case sensitivity-"Server" should be server and "Return" should be return. Hope this saves a few troubles when copying this code.

@static 2013-10-12 19:30:17

doesn't work for me. after nginx restart still responding to all domain names...

@jwhitlock 2013-12-12 21:10:07

static, see Oleg Neumyvkin's answer - if you have multiple config files in sites-available, then the first server in the first file by alphabetical order is your default. I suspect this might be an issue. Also, many distributions run an 'nginx -t' to test the config before restarting - you may have an error preventing a restart.

@Ben 2014-09-10 00:02:25

This is incomplete and should not be the accepted answer. For this to work you would also have to remove default_server from any listen directives.

@Dayo 2014-09-11 20:24:16

@ben Firstly, the OP did not have "default_server" in his problem example and the answer is tailored to the specifics of that question. Secondly, why anyone would define default_server on a separate server location when following instructions to make the first defined server the default is beyond me. In any case, if a default_server has been specifically defined, then this Q/A set is not what should be looked at to resolve whatever issues they may be having.

@Ben 2014-09-11 21:01:18

@Dayo You are correct that you addressed the specific config posted by the OP. But for a complete answer of question asked, I think it is necessary to mention the default_server. It's very possible to read your answer and not realize how default_server would interfere with it. It's even more likely because some distros shipping with default_server defined in a file that may not be obvious to the user.

@Dayo 2014-09-12 00:30:09

@ben Lets agree to disagree on the point of whether an answer that directly and correctly addresses a question should be accepted or not based on how it addresses the use case of an unrelated third party.

@Industrial Control Freak 2015-03-30 06:00:31

Hi guys! I've just spent two hours pulling my hair. A moment I add an IP address or a hostname to the listen directive (listen 192.168.1.10:80;), nginx responds to any server name. Is it intended?

@Dayo 2015-03-30 16:31:37

You might want to generate a new question explaining your issue in detail by using the "Ask A Question" button on the top right corner of this page in order to get a proper answer.

@Parthian Shot 2015-04-24 17:20:53

It's worth noting that leaving 8080 open through the firewall is a security flaw, unless you implement a relatively complex firewall / user permission setup. Leaving a high-numbered port open means that, if the application bound to it ever crashes, a non-privileged user can bind to that port and transparently proxy traffic intended for the main site, nabbing e-mails, passwords, CCNs... Additionally, of course, providing a redirect for every single request means twice the effort per user and twice the latency (because now it's two RTT per request). Helpful answer otherwise, though.

@ydaniv 2015-04-29 11:06:01

Note that a 444 response is preferred in this case, like noted below by @iTech

@AndreyT 2017-03-30 20:57:46

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.

@mmc 2018-11-20 18:06:40

I have no idea why this answer is so far down the list. This is the one that answers the question without getting distracted by shiny things along the way.

@endyourif 2019-02-07 00:58:07

This helped me solve a problem where I was trying a redirect from non-www to www that I had to include my ssl certificate in this redirect route otherwise is was trying to grab my default ssl cert which was a for a different domain.

@mpowered 2019-02-08 04:18:36

This seems like the best answer for most configurations... not sure who's using nginx without SSL these days, but the fact that this is the only one that covers SSL is extremely telling.

@Pavel 2014-02-12 21:29:53

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.

@Ben 2014-09-10 00:00:47

This should be the correct answer. The accepted answer is misleading. Simply adding another server to the config will not solve the problem if another server is configured to be the default server.

@Dayo 2014-09-11 11:53:07

@Pavel there is no reason why the provided answer cannot work with multiple separate vhost files. Also, with this, I know that my default server is always in the main nginx.conf file and do not have to remember which one of my many separate vhost files contains this.

@Constantinos 2018-07-25 08:10:46

Don't forget to listen to 443 as well for ssl (see @AndreyT's response below).

@iTech 2014-11-24 09:03:33

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;
}

@lostcitizen 2015-10-09 22:11:59

this worked for me.

@daniel 2015-10-31 19:31:05

Worked for me for nginx 1.8.0. The server_name _; I did not have in earlier versions for nginx, but it worked. Now for the newer nginx versions it seems that you need the server_name _;. Thanks

@Pedro Leal 2016-01-30 17:44:32

Had the same problem. this solved it.

@user1201917 2016-07-04 15:13:40

Solved. I forgot a semicolon ;_;

@Divick 2017-11-05 06:49:47

@iTech: For some reason it is returning 444 for all requests. Any clues?

@qqilihq 2017-11-14 12:34:48

Great tip about the 444, and imho a much cleaner solution than returning an error code.

@Mark Fletcher 2018-01-25 02:43:59

It's important to specify a certificate/key, else all SSL connections will match and fail, as pointed out by @AndreyT in his answer below.

@Impulse The Fox 2018-05-23 18:59:24

Beware of this! I get very weird behaviour on 444. I would prefer to use an official HTTP status code like 400.

@Constantinos 2018-07-25 08:10:39

Don't forget to listen to 443 as well for ssl (see @AndreyT's response below).

@Matt Carrier 2014-08-13 07:15:38

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;
    }

    ...
}

@Shiji.J 2015-03-18 02:33:09

works perfect for me

@Esolitos 2017-10-07 12:56:47

@Edward 2018-05-02 16:06:04

There are cases where you simply cannot avoid using an if, for example, if you need to test a variable which has no equivalent directive.

@mpowered 2019-02-08 04:22:49

@Esolitos Literally the third line of that article says that this use case is okay. I understand the need to be cautious, but let's not wag fingers at reasonable use cases.

@Oleg Neumyvakin 2013-08-24 11:08:35

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

Related Questions

Sponsored Content

11 Answered Questions

[SOLVED] Node.js + Nginx - What now?

  • 2011-02-15 20:49:02
  • Van Coding
  • 323832 View
  • 913 Score
  • 11 Answer
  • Tags:   node.js nginx concept

3 Answered Questions

[SOLVED] Share Nginx server configuration

  • 2014-06-11 04:04:32
  • Anam
  • 1360 View
  • 3 Score
  • 3 Answer
  • Tags:   php nginx

0 Answered Questions

Nginx erorr 404 Not Found

  • 2018-12-13 18:21:54
  • Alex
  • 47 View
  • 0 Score
  • 0 Answer
  • Tags:   php nginx

2 Answered Questions

0 Answered Questions

GZIP on PHP and NGINX

1 Answered Questions

Wordpress constant redirect with nginx upstream

1 Answered Questions

[SOLVED] Ngnix Jsession changed redirection issue

  • 2015-06-30 11:09:34
  • Crazy Developer
  • 393 View
  • 2 Score
  • 1 Answer
  • Tags:   nginx

1 Answered Questions

[SOLVED] Nginx: cache only specific urls and named location

  • 2014-09-30 13:54:05
  • proton
  • 1711 View
  • 1 Score
  • 1 Answer
  • Tags:   nginx

1 Answered Questions

Can multi laravel based sites be accessed by folder not by port?

2 Answered Questions

nginx config for Drupal&Boost&ImageCache

Sponsored Content