为什么nginx会响应任何域名?

时间:2012-03-22 14:31:34

标签: nginx

我已经启动了nginx并运行了Ruby / Sinatra应用程序,一切都很顺利。但是,我现在正尝试从同一台服务器运行第二个应用程序,我注意到一些奇怪的东西。首先,这是我的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

注意server_name如何设置为FAKE.COM但服务器正在响应通过其他域名命中该服务器的所有主机。如何使该特定服务器仅响应FAKE.COM的请求?

7 个答案:

答案 0 :(得分:183)

nginx配置中的第一个服务器块是所有到达没有特定服务器块的服务器的请求的默认值。

因此,在您的配置中,假设您的真实域名是REAL.COM,当用户输入该域名时,它将解析到您的服务器,并且由于此设置没有服务器块,因此FAKE.COM的服务器块,作为第一个服务器块(在您的情况下只是服务器块),将处理该请求。

这就是为什么正确的Nginx配置具有特定服务器块的默认值,然后跟随特定域的其他服务器块。

# Default server
server {
    return 404;
}

server {
    server_name domain_1;
    [...]
}

server {
    server_name domain_2;
    [...]
}

**编辑**

似乎有些用户对此示例感到有点困惑,并认为它仅限于一个conf文件等。

请注意,以上是OP根据需要开发的简单示例。

我个人使用单独的vhost conf文件(CentOS / RHEL):

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

/etc/nginx/conf.d/将包含domain_1.conf,domain_2.conf ... domain_n.conf,它将包含在主nginx.conf文件中的服务器块之后,该文件始终是第一个,并且始终是默认值除非在其他地方使用default_server指令覆盖它。

在这种情况下,其他服务器的conf文件的文件名的字母顺序变得无关紧要。

此外,这种安排提供了很大的灵活性,因为可以定义多个默认值。

在我的特定情况下,我只在内部接口上监听端口8080上的Apache,并且我将PHP和Perl脚本代理到Apache。

但是,我运行了两个单独的应用程序,它们在附加的输出html中返回带有“:8080”的链接,因为它们检测到Apache没有在标准端口80上运行并尝试“帮助”我。

这会导致链接变得无效,因为无法从外部接口访问Apache,并且链接应指向端口80.

我通过为端口8080创建默认服务器来重定向此类请求来解决此问题。

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

由于常规服务器块中没有任何内容侦听端口8080,因此重定向默认服务器块凭借其在nginx.conf中的位置透明地处理此类请求。

我实际上有四个这样的服务器块,这是一个简化的用例。

答案 1 :(得分:56)

你应该拥有 catch-all 的默认服务器,你可以返回404或者更好的方式来回复444而不回复(会节省一些带宽)是nginx特定的HTTP响应,它只是关闭连接而不返回任何内容

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

答案 2 :(得分:31)

我无法用任何其他答案解决我的问题。我通过检查主机是否匹配来解决了这个问题,如果不匹配则返回403。 (我有一些随机网站指向我的网络服务器内容。我猜测劫持搜索排名)

server {
    listen 443;
    server_name example.com;

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

    ...
}

答案 3 :(得分:26)

指定默认服务器的方法很少。

第一种方式 - 如果您将服务器配置保存在一个配置文件中,请在列表中首先指定默认服务器,如上面显示的Dayo。

第二种方式(更好)更灵活 - 为default_server指令提供listen参数,例如:

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

此处提供更多信息:Nginx doc / Listen

当您将服务器配置保存在单独的文件中并且不想按字母顺序命名这些文件时,这种方式会更有用。

答案 4 :(得分:15)

要回答你的问题 - 如果没有匹配,nginx选择第一台服务器。见documentation

  

如果其值与任何服务器名称不匹配,或者请求不匹配   根本包含此标头字段,然后nginx将请求路由到   此端口的默认服务器。在上面的配置中,   默认服务器是第一个...

现在,如果你想拥有一个默认的全能服务器,比如用404响应所有请求,那么这里是如何做到的:

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

请注意,您需要指定证书/密钥(可以是自签名的),否则所有SSL连接都将失败,因为nginx将尝试使用此default_server接受连接,并且找不到证书/密钥。

答案 5 :(得分:8)

回答的评论很少:

如果您在sites-available /中的多个配置文件中的多个IP上有多个虚拟主机,则IP的“默认”域将按字母顺序从第一个文件中获取。

正如Pavel所说,“listen”指令http://nginx.org/en/docs/http/ngx_http_core_module.html#listen

有“default_server”参数

答案 6 :(得分:0)

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    listen 443 default_server;
    listen [::]:443 default_server;
    return 444;
}

如果您只想忽略此类带有不需要的 Host 或根本没有 Host 的请求,请创建每个可能的 address:port 对默认为的接收器服务器,然后执行 {{ 1}} 那里。

不要费心支持接收器的 HTTP/2、HTTP/3 或 SSL 连接。对于不支持的,服务器只会拒绝此类连接。

对于受支持类型的连接,它只是立即挂断连接而无需发送响应,这就是 return 444; 如此特别的原因。


来自文档

http://nginx.org/en/docs/http/request_processing.html

<块引用>

...NGINX 仅测试请求的头字段“return 444;”以确定请求应该路由到哪个服务器。如果它的值与任何服务器名称都不匹配,或者请求根本不包含此头字段,则 NGINX 会将请求路由到此端口的默认服务器。

https://nginx.org/en/docs/http/ngx_http_core_module.html#listen

<块引用>

... Host 参数(如果存在)将使服务器成为指定 default_server 对的默认服务器。