Nginx可通过正则捕获+rewrite+proxy_pass变量实现动态反向代理:server_name或location正则提取服务名存入变量,proxy_pass配合rewrite安全引用(后缀带/或不带URI),并需配置Host、X-Real-IP等头信息。

直接用 proxy_pass 本身不支持变量插值(比如 http://$host:8000),但通过 Nginx 的正则匹配 + 命名捕获 + rewrite 或 proxy_pass 后缀拼接,就能实现高度灵活的动态反代寻址。核心是让 URL 路径或 Host 头里的特征自动映射到后端地址,无需为每个子服务单独写 location。
用 server_name 正则提取 Host 变量
适用于按子域名区分后端的场景(如 a.example.com → http://a:8000):
- 在
server块中用命名捕获组提取前缀:server_name ~^(?<service>[a-z]+)\.example\.com$;</service> - 该配置会把
a、b等存入变量$service,后续可直接引用 - 注意:变量只在当前
server块内有效,且必须在location之前定义
用 location 正则匹配路径并重写 URI
适用于路径中含服务标识(如 /api-v1/users → http://api-v1:3000/users):
- 先匹配并提取关键段:
location ~ ^/([^/]+)/(.*)$ { - 用
rewrite把路径拆开,同时设变量(可选):set $backend $1;<br>rewrite ^/[^/]+/(.*)$ /$1 break;
- 这样原始请求
/auth/login中的auth就进了$backend,/login进了 URI
proxy_pass 引用变量的两种安全写法
变量不能直接出现在 proxy_pass 的协议部分(如 https://$backend 会报错),但有可靠替代方案:
-
方案一:proxy_pass 后不带 URI,靠 rewrite 改写路径
location ~ ^/([a-z]+)/ {<br> set $upstream $1;<br> rewrite ^/[a-z]+/(.*)$ /$1 break;<br> proxy_pass http://$upstream:8000;<br>}
此时proxy_pass后无路径,Nginx 会把原始 URI(经 rewrite 后)完整转发 -
方案二:proxy_pass 后带斜杠,URI 由 rewrite 提前处理好
location ~ ^/([a-z]+)/ {<br> set $upstream $1;<br> rewrite ^/([a-z]+)/(.*)$ /$2 break;<br> proxy_pass http://$upstream:8000/;<br>}
注意末尾的/,它会丢弃匹配的/[a-z]+/部分,只转发/$2
必须加的关键配套指令
动态代理容易出问题的地方往往不在变量本身,而在头信息和路径处理:
- 始终设置
proxy_set_header Host $host;,避免后端因 Host 不匹配拒绝请求 - 加上
proxy_set_header X-Real-IP $remote_addr;和X-Forwarded-For,保留真实客户端 IP - 若后端依赖原始路径前缀(比如前端路由),需用
proxy_redirect off;关闭自动重写 Location 头 - 测试时用
curl -H "Host: a.example.com" http://localhost/path模拟子域名请求,验证变量是否生效

















