用心打造
VPS知识分享网站

Nginx出现rewrite or internal redirection cycle是什么原因?

网站突然返回500,Nginx错误日志反复出现 rewrite or internal redirection cycle while internally redirecting,通常不是浏览器301或302跳转太多,而是请求在Nginx内部被多次改写,最终触发循环保护。

解决重点是还原URI在location之间的内部流向,找到哪条fallback又回到了原规则。 盲目提高循环次数没有意义,也可能把清晰的500变成更高的CPU和磁盘开销。

Nginx重定向循环

区分内部重定向和浏览器跳转

外部跳转会向客户端返回301、302、307或308,浏览器地址栏可能变化,开发者工具能看到多次HTTP请求。内部重定向则发生在Nginx进程内部,客户端往往只收到最终500,看不到中间URI。

先采集一次请求和日志:

curl -vkI https://example.com/problem-path
sudo tail -n 100 /var/log/nginx/error.log

日志中的 internally redirecting to 会给出某个中间URI,例如 /index.php/error/404.html如果curl只收到一次500,而错误日志显示同一URI反复出现,优先检查内部配置闭环。

导出Nginx实际加载的完整配置

不要只查看当前编辑的站点文件。include可能引入面板模板、公共rewrite和多个虚拟主机,真正生效的配置应以 nginx -T 为准:

sudo nginx -T > /tmp/nginx-effective.conf 2>&1
grep -nE 'server_name|location|try_files|rewrite|error_page|index' \
  /tmp/nginx-effective.conf

同时确认请求命中了哪个server块,包括80与443、IPv4与IPv6监听,以及默认站点。若SNI或Host不匹配,流量可能进入完全不同的规则。

修改前先执行 sudo nginx -t 保存当前结果。排错必须基于展开后的有效配置,否则很容易修错文件或漏掉上层include。

try_files的最后一个参数最容易形成闭环

try_files 会按顺序检查文件,最后一个参数可以是状态码、命名location或用于内部重定向的URI。常见前端控制器配置如下:

location / {
    try_files $uri $uri/ /index.php?$query_string;
}

/index.php 不存在,或者新的location处理后又回到相同的 try_files,就可能继续内部跳转。修复时应保证fallback有明确终点,例如让PHP脚本由单独location处理:

location ~ \.php$ {
    try_files $uri =404;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_pass unix:/run/php/php-fpm.sock;
}

先确认目标文件真实存在,再确认fallback会被另一个终止型location接住。

检查index与目录URI的相互跳转

访问 /app/ 时,index index.php index.html; 可能触发到index文件的内部重定向。如果处理index的location又把它回退到 /app/,目录和文件之间便会循环。

逐项核对root与文件:

sudo nginx -T | grep -nE '^[[:space:]]*(root|alias|index) '
namei -l /var/www/example/app/index.php

特别注意 aliasroot 的路径拼接逻辑不同,location尾部斜杠也会影响结果。可暂时把fallback改为 =404,若循环消失,就能证明问题在内部回退链而不是上游应用。

不要用创建空index文件掩盖路径错误;文件可访问、location匹配和FastCGI脚本路径必须同时成立。

排查rewrite规则是否重新命中自身

last 的rewrite会使用新URI重新搜索location,若新URI仍匹配原正则,规则就可能再次执行。示例风险配置:

location /download/ {
    rewrite ^/download/(.*)$ /download/$1 last;
}

替换前后没有实质变化,必然可能重复。对于只返回外部跳转的场景,优先使用 return 301;需要在当前location继续处理时,应理解 breaklast 的差异,并让匹配条件在执行后不再成立。

修改后用多组边界URL测试,包括带斜杠、不带斜杠、空路径和查询参数。一条rewrite必须让请求向终点前进,而不是把同一个URI重新交给自己。

error_page也可能把错误再次送回原规则

内部错误页配置可以这样工作:

error_page 404 /404.html;
location = /404.html {
    internal;
    root /var/www/errors;
}

如果 /404.html 不存在,且它再次触发同一个404内部错误页,便会形成循环。403、500等错误也存在类似风险。确认错误页文件存在,并使用精确匹配location,让它不再经过通用 try_files 或rewrite。

还要检查反向代理上游返回的错误是否启用了 proxy_intercept_errors on自定义错误页本身必须是一个可靠终点,不能依赖正在故障的应用路由。

用最小化配置逐层恢复规则

先备份站点配置,把有疑问的rewrite、error_page和复杂try_files暂时注释,仅保留静态文件或明确的上游转发。每次只恢复一组规则,并执行:

sudo nginx -t && sudo systemctl reload nginx
curl -sS -o /dev/null -w '%{http_code}\n' https://example.com/problem-path

使用reload而不是无条件restart,可减少连接中断;但配置测试通过不代表业务逻辑正确,仍要观察错误日志和实际响应。将改动范围缩到单个server块和单个URL,能更快定位引入闭环的指令。

需要复现面板模板或多站点include时,可在 萤光云 创建同版本测试机,或用 LightNode 部署临时节点。只复制脱敏配置,不要上传证书私钥和生产环境变量。

完成后的验收标准

分别请求首页、故障路径、真实不存在的路径、静态文件、动态入口和自定义错误页。正常业务应返回预期状态,未知路径应稳定返回404,而不是500;错误日志中不再出现internal redirection cycle。

再执行一次 nginx -T 保存修复后的有效配置,并与修改前版本做diff。验收重点是每条内部跳转都有确定终点,即使目标文件缺失或上游失败,也不会重新落回原规则。

常见问题

把try_files最后一项改成=404为什么能止住循环?

因为状态码会直接结束处理,不再产生新的内部URI。它适合定位问题,但动态站点最终仍需配置正确的入口location。

浏览器提示重定向次数过多也是同一个问题吗?

不一定。浏览器提示通常是外部301/302循环;Nginx日志中的internal redirection cycle发生在服务端内部,两者应分别查看响应链和错误日志。

nginx -t通过为什么访问仍然500?

语法测试只验证配置是否合法,不能证明rewrite、try_files和error_page的运行路径没有逻辑闭环。

温馨提示

复杂站点应尽量让静态文件、动态入口和错误页由互不重叠的location处理。遇到循环时先把fallback改成明确失败,再逐层恢复路由,比反复调整正则更安全、更容易验证。

赞(0)
未经允许不得转载;国外VPS测评网 » Nginx出现rewrite or internal redirection cycle是什么原因?
分享到