proxy_redirect默认不支持变量插值,需通过proxy_redirect default、正则捕获配合$scheme/$host变量重写,或用map预定义规则实现动态路径修正。

在 Nginx 静态反向代理场景中,proxy_redirect 默认只支持静态重写规则,无法直接处理动态路径(如带变量的 location 或上游响应头中的 Location/Refresh 跳转)。但通过结合 $scheme、$host、$request_uri 等内置变量,配合正则匹配与重写逻辑,可以实现全路径自动修正 —— 关键在于**用变量构造目标跳转地址,并让 proxy_redirect 动态适配**。
理解 proxy_redirect 的变量限制
Nginx 官方文档明确说明:proxy_redirect 指令本身**不支持变量插值**(即不能写成 proxy_redirect http://old/ $scheme://$host/;)。它只接受字面量或正则表达式。因此“变量驱动”的核心思路不是在 proxy_redirect 中直接用变量,而是:
- 用
proxy_redirect default;启用智能默认重写(基于proxy_pass和当前请求上下文) - 当 default 不够用时,用
proxy_redirect regex+$1/$2捕获组 + 变量拼接(在return或rewrite中完成最终跳转) - 必要时用
map提前定义动态重写规则,再引用到proxy_redirect
方案一:启用 default + 正确设置 proxy_pass
这是最简洁且覆盖 80% 场景的方式。只要 proxy_pass 使用带路径的 URI(末尾有斜杠),Nginx 就能自动计算相对跳转:
location /static/ {
proxy_pass https://origin.example.com/static/;
proxy_redirect default;
}
此时若上游返回 Location: /static/css/app.css,Nginx 自动转为 Location: /static/css/app.css(保持原路径);若返回 Location: /api/user,则不会被改写(因不匹配 /static/ 前缀)。关键点:
-
proxy_pass末尾必须加/,否则default无法正确剥离前缀 - 确保
server_name和listen配置正确,使$scheme和$host可被内部重写逻辑识别 - 如需强制 HTTPS 跳转,单独用
return 301 https://$host$request_uri;处理,不要混进 proxy_redirect
方案二:正则 proxy_redirect + return 构造动态跳转
当上游返回的 Location 是绝对地址(如 http://origin.example.com/login),且你希望统一改为当前域名+协议时,可结合正则捕获与 return:
location /app/ {
proxy_pass https://www.php.cn/link/59ff461e9d87fd02300ac1b7abf19f69;
proxy_redirect ~^http://[^/]+(/.*)$ $scheme://$host$1;
<pre class="brush:php;toolbar:false;"># 更稳妥:捕获路径后用 return 302 强制重定向(绕过 proxy_redirect 变量限制)
proxy_intercept_errors on;
error_page 301 302 307 = @handle_redirect;}
安装并运行 Aperture(Lightning Labs 的 L402 闪电反向代理),用于创建 L402 付费墙、配置付费 API 端点、为其他代理托管付费内容或测试 L402 认证流程。
location @handle_redirect { proxy_pass https://www.php.cn/link/59ff461e9d87fd02300ac1b7abf19f69; proxy_redirect off;
读取上游响应头中的 Location
if ($upstream_http_location ~ "^https?://[^/]+(?<redir_path>/.*)$") {
return 302 $scheme://$host$redir_path;
}
return 500;</redir_path>}
说明:
-
proxy_redirect正则中虽不能直接写$scheme,但右侧重写值支持变量(Nginx 1.19.0+),所以$scheme://$host$1是合法的 -
error_page拦截跳转响应,再用if + return精确控制,更灵活可靠 - 注意
if在 location 中使用是安全的(仅用于 header 匹配)
方案三:用 map 预定义动态重写规则
适用于多环境(dev/staging/prod)共用一份配置,需根据 $host 或 $http_x_forwarded_host 动态生成重写目标:
map $host $redirect_host {
dev.example.com "https://dev-backend";
staging.example.com "https://staging-backend";
default "https://prod-backend";
}
<p>server {
location /api/ {
proxy_pass $redirect_host/api/;
proxy_redirect ~^($redirect_host)(/.*)$ $scheme://$host$2;
}
}</p>
要点:
-
map必须定义在http块顶层,不能在 server 内 -
proxy_redirect右侧仍支持变量,左侧正则中也可引用$redirect_host(需确保 map 已生效) - 该方式适合运维侧集中管控,避免重复写死配置
不复杂但容易忽略:所有变量生效的前提是请求已进入对应 location 上下文,且 upstream 响应头真实存在 Location 字段。建议用 curl -I 验证上游原始响应,再观察 Nginx 日志中的 upstream_http_location 变量值,逐步调试。










