Nginx rewrite死循环是引发CPU 100%的隐蔽主因,不报错但持续重写URI并重新匹配location,10次后返回500;可通过access.log高频路径、500响应及$request_id重复出现识别,结合rewrite_log定位循环起点,修复需依意图选用break、精确location匹配或return替代redirect。

rewrite死循环是Nginx中引发CPU 100%最隐蔽也最典型的原因之一——它不报错、不写error.log,却让worker进程在内部反复重写URI、重新匹配location,10次后直接返回500,而在此之前已持续高强度运算。
看access.log快速识别循环特征
执行以下命令抓取高频路径和IP:
-
tail -n 5000 /var/log/nginx/access.log | awk '{print $7}' | sort | uniq -c | sort -nr | head —— 若同一URI(如
/old/xxx)出现上万次,极可能是rewrite无条件触发 - tail -n 5000 /var/log/nginx/access.log | awk '$9 ~ /^500$/ {print $7}' | sort | uniq -c | sort -nr —— 筛出大量500响应的路径,重点检查对应location块
- 留意
$request_id字段(需log_format中启用),同一request_id反复出现在多行日志中,说明单请求被多次处理
定位问题rewrite指令的三个关键点
重点检查满足以下任一条件的location块:
- 使用
rewrite ... last;但目标URI仍能命中当前location(例如location /太宽泛,重写后仍落入其中) - 缺少
if前置判断,或if写在location外(Nginx官方明确不推荐在server级用if做URI判断) - 混用
try_files与rewrite,比如try_files $uri @fallback后在@fallback里又写rewrite,且未加break
用rewrite_log精准追踪执行流(临时启用)
在nginx.conf的http或server块中加入:
rewrite_log on;error_log /var/log/nginx/rewrite.log notice;
然后重启Nginx并复现请求:
tail -f /var/log/nginx/rewrite.log 会实时打印每次rewrite动作,看到类似"rewritten data:" "/new/abc" using "^/old/(.*)$"重复出现3–5次以上,即可确认循环起点。
修复方案要匹配实际意图
不是所有rewrite都要删,关键是选对终止方式:
- 若只是内部路径改写(如SPA history模式兜底),用
break而非last,避免重新匹配 - 若需跳转到新location,改用更精确的匹配:把
location /old/换成location ^~ /old/或location ~ ^/old/,确保/new/不落入其中 - 对外重定向(301/302)务必用
return代替rewrite ... redirect,更安全高效 - 临时加
limit_req zone=loopburst=1 nodelay;防循环放大影响


















