Nginx:上游“主机未找到”错误的特殊行为?

Nginx:上游“主机未找到”错误的特殊行为?

当 nginxproxy_pass返回 502 时,原因可能多种多样。我想要的是能够检测何时由于未找到上游主机(即解析失败)而返回 502。

我知道proxy_intercept_errors,但对我的情况来说它似乎没有帮助。

我拥有的

我有一个在 Kubernetes pod 上运行的 nginx 网关服务器。它配置为根据主机名的第一部分(第一个点之前的单词,例如service-name.example.com应路由到名为 的服务service-name)将请求路由到适当的 Kubernetes 服务。

以下是负责此逻辑的简化配置部分:

server {
  listen 80;
  resolver 172.16.2.3; // Pod IP address
  server_name "~^(?<svc>[\w-]+)\.";

  location / {
    # Each Kubernetes service has an internal domain name matching the following pattern
    proxy_pass "http://$svc.default.svc.cluster.local";
    proxy_set_header Host $host;
    # Proxy `X-Forwarded` headers sent by ELB: http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/x-forwarded-headers.html
    proxy_set_header X-Forwarded-For $http_x_forwarded_for;
    proxy_set_header X-Forwarded-Port $http_x_forwarded_port;
    proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
  }
}

问题

无论上游为何无法访问(如果它拒绝连接、内部失败或根本不存在),nginx 都会返回 502。只有在 nginx 错误日志中才能看到实际原因。

由于网关通过 AWS ELB 公开可用,因此它经常通过 IP 或随机名称进行访问,这会在针对 5XX 错误峰值做出反应的监视器中产生噪音。

我想做的事

设置 nginx 以返回一些不太严重的错误(例如,404),以防服务的主机名无法被 Kubernetes 解析器解析。

例如我发送以下请求:

curl -H "Host: non-existent-service.example.com" http://gateway.example.com

我希望 nginx 能够检测到服务对应的主机名无法内部解析,然后返回 404 而不是 502。

当前日志如下所示:

  • 错误日志:

    2017/11/10 16:03:58 [error] 22#22: *482894 non-existent-service.default.svc.cluster.local could not be resolved (3: Host not found), client: 172.16.1.2, server: ~^(?<svc>[\w-]+)\., request: "GET / HTTP/1.1", host: "non-existent-service.example.com"
    
  • 访问日志:

    172.16.1.2 - - [10/Nov/2017:16:03:58 +0000] "non-existent-service.example.com" "GET / HTTP/1.1" 502 173 "-" "curl/7.43.0" "194.126.122.250" "EE"
    

更新

应该首先提到这一点。首先要尝试的是“catch-all”默认服务器块。结果发现这个块从未被达到,因为实际上任何主机名都与正则表达式匹配。

答案1

只需重新启用默认虚拟主机并忽略任何命中的内容(因为此类请求直接查询 IP,或为恶意请求)。

例如,在 nginx 1.12.x 中看到nginx.conf

    server {
        listen       80 default_server;
        listen       [::]:80 default_server;
        server_name  _;
        root         /usr/share/nginx/html;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        location / {
        }

        error_page 404 /404.html;
            location = /40x.html {
        }

        error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }
    }

相关内容