先看现象。nginx 1.24 上想给特定 UA 单独走一个后端,在 location 里写了 if ($http_user_agent ~* bot) { proxy_pass http://bot_pool; },reload 后这类请求全部 500,error.log 里是 rewrite or internal redirection cycle。
这类报错背后常见的原因有几处,逐个排除就行。if 块在 rewrite 阶段执行,里面的 proxy_pass 会打断正常的内容处理阶段。也可能是if 里只写了 proxy_pass,proxy_set_header 这些指令继承不到,后端收到空 Host。
另外,条件不匹配时没有兜底分支,请求落进一个没有内容处理器的 location。
少数情况下是if 和 try_files 叠在一起,内部重定向次数超过上限。
先看 error.log 的原文和请求路径
tail -50 /var/log/nginx/error.log
接着确认 if 块和 proxy_pass 的位置
nginx -T | grep -n -B3 -A8 'proxy_pass http://bot_pool'
然后改成 map 生成后端变量再统一代理
printf '%s
' 'map $http_user_agent $backend {' ' default app_pool;' ' ~*bot bot_pool;' '}' > /etc/nginx/conf.d/ua.conf
reload 后统计状态码分布
nginx -t && nginx -s reload && awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c
这次没动代码,只在配置和运行环境上找原因。
隔了一天再看,现象没变,说明不是偶发。
恢复的判定其实很直接。带 bot UA 的请求返回 200,access.log 里 5xx 归零,error.log 不再出现 internal redirection cycle。
提醒一点。if 放在 location 里只有配 return 和 rewrite 是安全的,带 proxy_pass 的 if 是官方文档点名的问题写法;分流一律用 map 加变量。拖得越久,排查成本越高,因为现场状态会被后续操作覆盖。
