proxy_pass 通过 map 映射可信后端、resolver 动态解析域名、rewrite 重写路径实现安全动态路由,禁止用户输入拼接、禁用 if 判断,严格白名单校验与 SSRF 防护。

proxy_pass 本身不支持运行时拼接完整 URL,但通过组合 map、resolver、rewrite 和变量,就能安全适配微服务动态地址。核心是把“决策逻辑”提前或隔离,避免在 proxy_pass 中直接拼字符串。
用 map 映射可信后端地址
这是最推荐的方式:把请求特征(如 Host、Header、参数)映射成预定义的、人工审核过的后端地址,杜绝注入和空值风险。
- 在 http 块中统一配置,比如按子域路由:
map $host $upstream {<br> ~^(?<sub>[\w-]+)\.example\.com$ $sub;<br> default "default-service";<br>} - 每个映射值都必须是合法 URI,含协议和结尾斜杠,例如
"http://user-svc.internal/"或"https://order-v2.prod/" - location 中直接引用:
proxy_pass $upstream;,不加额外路径,靠 URI 统一处理
配合 resolver 实现域名动态解析
当后端是弹性 IP 的云服务或 Kubernetes Service 时,需要每次请求前查 DNS,而不是启动时缓存。
- resolver 必须和 set、proxy_pass 同级(建议写在 location 内),例如:
resolver 114.114.114.114 valid=15s; - set 变量只存纯域名(不含协议、端口、路径),如:
set $svc "auth-svc.default.svc.cluster.local"; - proxy_pass 显式写出协议:
proxy_pass https://$svc;,Nginx 会自动补默认端口并查 DNS - valid 时间设为 10–30 秒较平衡:太短增加 DNS 查询压力,太长影响故障切换时效
路径重写 + 无路径 proxy_pass
若需按租户、版本等动态调整后端路径前缀,不要在 proxy_pass 里硬编码路径,而是先 rewrite,再用干净的 upstream 名转发。
- 例如按请求路径提取租户:
rewrite ^/t-(\w+)/(.*)$ /$1/$2 break; - 或用 map 提取并构造前缀:
map $uri $prefix { ~^/t-(\w+)/ $1; default ""; },然后proxy_pass http://backend$prefix$request_uri; - 关键点:proxy_pass 后不带路径(即不以
/结尾),否则原始 URI 被丢弃;带/则保留原始路径结构
安全兜底:白名单校验与 SSRF 防护
所有变量来源必须可控,禁止用户输入直接参与拼接。
- 对 map 的 key 做正则约束,拒绝非法字符(如
..、://、空格) - 禁用 scheme 动态化,proxy_pass 只允许
http://或https://开头,不接受$scheme:// - 配合
add_header X-Debug-Backend $upstream;临时调试,上线前移除 - 生产环境禁用
if做复杂判断——易出作用域错误,优先用 map 或 OpenResty Lua


















