nginx ip_hash 本身不导致死循环,但 cdn 节点 ip 固定且 proxy_pass 配置错误(如回指自身或同名域名)会引发「cdn→nginx a→nginx b→nginx a」闭环;排查需查 access.log 中同一 $remote_addr 或 $request_id 短时高频重复、error.log 的连接失败日志,并通过调试日志确认 $upstream_addr 是否在集群内网地址间循环转发;解决关键在于 proxy_set_header host 显式指定后端域名、upstream 使用真实 ip 而非域名、隔离泛域名匹配。

Nginx 的 ip_hash 本身不会引发死循环,但当 CDN 节点固定、且后端 Nginx 配置不当(如 proxy_pass 回指自身或同名域名),就容易形成「CDN → Nginx A → Nginx B → Nginx A」这类闭环转发。排查关键不是看 ip_hash 是否启用,而是确认请求是否被错误地反复打回同一集群。
先确认是否真有死循环
- 查看 access.log 中同一
$request_id或相同$remote_addr(即 CDN 节点 IP)在极短时间内重复出现多次,且响应状态码多为301/302/502/503 - 用
curl -v http://yourdomain.com观察跳转链路,看 Location 头是否在两个域名或路径间来回切换 - 检查 error.log 是否频繁报
connect() failed (111: Connection refused)或no live upstreams,说明请求卡在内部转发环节
重点查 CDN 透传与 Host 头处理
CDN 通常只透传一个真实客户端 IP(如通过 CF-Connecting-IP 或 X-Real-IP),但它的出口 IP 是固定的(比如 198.51.100.10)。这个 IP 一旦被 ip_hash 计算,所有经该 CDN 节点的请求都会落到同一台后端 Nginx —— 如果这台 Nginx 又把请求 proxy_pass 给了本集群其他节点(甚至自己),死循环就埋下了。
- 在
http块顶部加调试日志:log_format loop_debug '$remote_addr | $http_cf_connecting_ip | $http_x_forwarded_for | "$request" > $upstream_addr $status'; access_log /var/log/nginx/loop-debug.log loop_debug;
- 重启后发起请求,观察日志中:
-
$remote_addr是否稳定为某个 CDN 出口 IP(如198.51.100.10) -
$upstream_addr是否反复出现在集群内网地址之间(如10.0.1.10:80→10.0.1.11:80→10.0.1.10:80)
-
切断回环的关键配置
- 所有
proxy_pass指令前必须显式设置目标 Host,禁止继承原始$host:proxy_set_header Host "api.internal.example.com"; proxy_redirect off;
- 确保
upstream定义的是后端服务真实地址(如10.0.2.5:8080),而不是域名(如api.example.com)——后者极易被 DNS 解析回本集群。 - 若使用泛域名代理(如
server_name ~^.*$),务必加if ($host = "api.example.com") { ... }显式隔离,避免误匹配。
验证 CDN 是否干扰 ip_hash 行为
-
ip_hash只认$remote_addr,而 CDN 后$remote_addr就是 CDN 节点 IP。这不是 bug,是设计使然。 - 如果你发现大量请求都落在同一台后端,且该后端又承担了反向代理职责(比如同时做 API 网关和静态资源服务),就要检查它有没有把
/auth请求又proxy_pass给了/的 upstream,从而触发自调用。 - 临时停掉某台疑似“中转节点”的后端,看死循环是否消失;若消失,说明它就是闭环中的关键一环。
不复杂但容易忽略。











