nginx proxy_pass转发规则解读

 更新时间:2024年01月23日 10:05:11   作者:shuxiaohua  
这篇文章主要介绍了nginx proxy_pass转发规则,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

综述

nginx官方网站讲解proxy_pass时,只给了规则的说明,并没有给出具体的示例辅助理解。

对于英语不太好的人,理解起来真的很头痛,只能通过测试来验证对英文意思的猜测。

nginx对proxy_pass的官方说明见http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass

其将proxy_pass的转发规则分为3类:

  • location为简单配置(非正则表达式),proxy_pass的url带path路径
  • location为简单配置(非正则表达式),proxy_pass的url不带path路径
  • nginx无法确认url的替换规则

url中带path路径

判断条件

如果域名后面带了“/”,则认为是url中带了path路径。比如:

  • proxy_pass http://127.0.0.1/
  • proxy_pass http://127.0.0.1/aaa
  • proxy_pass http://127.0.0.1/aaa/

转发规则

nginx官网原文如下:

If the proxy_pass directive is specified with a URI, then when a request is passed to the server, the part of a normalized request URI matching the location is replaced by a URI specified in the directive:

location /name/ {
proxy_pass http://127.0.0.1/remote/;
}

个人理解如下:

使用proxy_pass配置的url去替换location指定的部分。

如下图就是使用http://127.0.0.1/remote/去替换path中/name/这一段

url中不带path路径

判断条件

与第一点相反,proxy_pass指定url中只有域名,比如ttp://127.0.0.1

转发规则

If proxy_pass is specified without a URI, the request URI is passed to the server in the same form as sent by a client when the original request is processed, or the full normalized request URI is passed when processing the changed URI:

location /some/path/ {
proxy_pass http://127.0.0.1;
}

个人理解如下:

转发url=proxy_pass配置的url+原始url中path部分

nginx无法确认url的替换规则

这种场景nginx又细分成3类

location指定的是正则表达式

nginx官方要求配置proxy_pass时,不能带path路径。

When location is specified using a regular expression, and also inside named locations.
In these cases, proxy_pass should be specified without a URI.

path路径在location中使用rewrite重写了

比如

location /name/ {
rewrite /name/([^/]+) /users?name=$1 break;
proxy_pass http://127.0.0.1/test;
}

In this case, the URI specified in the directive is ignored and the full changed request URI is passed to the server.

这种场景,nginx会忽略proxy_pass中配置的path路径,然后使用proxy_pass中指定的域名加上rewrite中指定的path路径即为转发后的url。

proxy_pass配置的url中带变量

比如

location /name/ {
proxy_pass http://127.0.0.1$request_uri;
}

In this case, if URI is specified in the directive, it is passed to the server as is, replacing the original request URI.

这种场景,如果proxy_pass配置的url经过变量转换后带path路径,则直接使用该url。

其他

实际上,“nginx无法确认url的替换规则”3个细分类可能存在交叉的地方,这个nginx没有提到,大家只能动手自己去测试nginx的混合场景的规则了。

比如我们系统后端服务是没有context-path的,后面为了容器化需要添加context-path,详细背景见之前的博客。

为了对前端屏蔽变化,因此需要修改nginx的转发规则。

如下图所示,这样就涉及到“location指定的是正则表达式”和“proxy_pass配置的url中带变量”混合场景了。

If the location is given by regular expression, can not be a URI part in proxy_pass directive, unless there are variables in the directive

如果location使用正则表达式,proxy_pass中不能指定path,除非proxy_pass中包含变量。

补充说明

当时分析nginx转发规则,是为了解决转发时,url增加公共前缀,当时不理解为啥在正则表达场景下不能通过在proxy_pass中配置公共前缀,达到增加公共前缀的目的(像简单模式那样,使用proxy_pass替换掉url中正则表达式匹配上的那部分)。

后面在定位我们灰度分流配置时,顿悟nginx转发规则这样设计的目的。

我们需要通过url中的租户id进行分流,nginx配置如下

    location ~ /tenants/(租户id)/ {
        proxy_pass https://$gray;
    }
    location ~ / {
        proxy_pass https://$production;
    }

当时第一眼看到这个配置时,感觉灰度分流不会生效,只会走正式边。因为我们的url是/api/tenants开头,location配置中少了“/api”,结果测试发现分流正常。

初步分析,nignx中的正则表达式与我们自己写代表中的正则表达一样,它是对整个url进行匹配。

并不像普通模式那样从url起始位置开始进行匹配(当然如果需要从起始位置开始匹配,也可以通过指定"^")。

因此正则表达式匹配上的部分,可能是url中间的一部分,这样就不好实用proxy_pass替换掉location中指定的部分。

所以nignx要求,正则表达式场景下,配置proxy_pass时不能带path路径,除非proxy_pass指定的就是完整的url,这样nginx要么直接使用proxy_pass中指定的url,要么使用原始url中的path+proxy_pass中指定的域名。

proxy_pass中包含变量后,nginx这认为你指定了完整的url,因此交叉场景下,proxy_pass包含变量优先级更高。

淌坑指导-no resolver defined to resolve

当proxy_pass指定的url中带变量时,必须指定resolver。

具体解释见https://stackoverflow.com/questions/17685674/nginx-proxy-pass-with-remote-addr(这个解释也没给出细节,nginx官方也没给出具体解释)

比如:

set $originaddr http://origin.example.com;
proxy_pass $originaddr;

或者

proxy_pass http://origin.example.com$request_uri;

可以在server层级指定resolver,比如

server {
    resolver xx.xx.xx.xx;
     … …
}

具体resolver配置那个IP,可以查看系统默认配置的DNS服务器- cat /etc/resolv.conf

趟坑指导-“proxy_set_header Host $proxy_host”

背景同上

我们要将服务由虚拟机迁到公司的docker部署平台,这样可以自动部署,监控扩容啥的也更方便。

我们服务很多,nginx上面配置了很多转发规则,为了对前端屏蔽后端的组网变化,我们保留了nginx,通过nginx转发到ALB(docker通过ALB对外暴露服务)。

服务上了docker后,url要增加前缀(见背景文章),因此nginx转发规则要统一给转发后的url增加公共前缀,配置方式见上述“其他”章节。

配置后发现仍然报404(直接访问ALB是ok的)。

问题排查思路如下:

1.确认转发后的url是不是如自己期望的那样

首先想通过nginx日志打印转发后的规则,没有发现合适的参数;因此通过tcpdump工具dump报文,发现转发后的url正确,但是请求头中的Host并不是ALB对外暴露的域名,而是我们Nignx自己的域名,因此怀疑ALB的路由规则中会包含对域名的检测。(ALB也是一台Nginx,Nignx可以通过server_name将转发规则绑定到特定的域名,或者说给不同的域名指定不同的路由规则)。

2.google如何修改Host头,找到配置项"proxy_set_header Host $proxy_host",配置后验证ok。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 详解Nginx反向代理到Tomcat服务器

    详解Nginx反向代理到Tomcat服务器

    本篇文章主要介绍了详解Nginx反向代理到Tomcat服务器,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-02-02
  • nginx代理postgresql的实现示例

    nginx代理postgresql的实现示例

    本文主要介绍了nginx代理postgresql的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-10-10
  • 在Nginx用htpasswd对网站进行密码保护的设置方法

    在Nginx用htpasswd对网站进行密码保护的设置方法

    很多时候我们需要对一些网站进行密码保护,比如团队内部的站点、demo站点等等。这里所说的密码保护是服务器级的,并非网站应用层的注册登录那一套,而是利用服务器配置和htpasswd文件来实现访问的密码验证
    2013-06-06
  • nginx平滑重启和平滑升级的图文教程

    nginx平滑重启和平滑升级的图文教程

    如果改变了Nginx的配置文件(nginx.conf),想重启Nginx,可以发送系统信号给Nginx主进程的方式来进行,下面这篇文章主要给大家介绍了关于nginx平滑重启和平滑升级的相关资料,需要的朋友可以参考下
    2022-01-01
  • Nginx速查手册及常见问题

    Nginx速查手册及常见问题

    Nginx是一款轻量级的HTTP服务器,采用事件驱动的异步非阻塞处理方式框架,这让其具有极好的IO性能,时常用于服务端的反向代理和负载均衡,这篇文章主要介绍了Nginx速查手册及常见问题,,需要的朋友可以参考下
    2022-04-04
  • 关于Nginx中虚拟主机的一些冷门知识小结

    关于Nginx中虚拟主机的一些冷门知识小结

    这篇文章主要给大家介绍了关于Nginx中虚拟主机的一些冷门知识,文中通过图文以及实例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2022-03-03
  • nginx http 499错误码详解以及解决办法

    nginx http 499错误码详解以及解决办法

    HTTP状态码出现499错误有多种情况,499错误是什么?这篇文章主要给大家介绍了关于nginx http 499错误码以及解决办法的相关资料,文中介绍的非常详细,需要的朋友可以参考下
    2024-01-01
  • Nginx 服务器开启status页面检测服务状态的方法

    Nginx 服务器开启status页面检测服务状态的方法

    这篇文章主要介绍了Nginx 服务器开启status页面检测服务状态的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2024-01-01
  • nginx限制ip访问频率的实现示例

    nginx限制ip访问频率的实现示例

    Nginx通过limit_conn_zone 和 limit_req_zone对同一个IP地址进行限速限流,本文主要介绍了nginx限制ip访问频率的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07
  • 如何利用map实现Nginx允许多个域名跨域

    如何利用map实现Nginx允许多个域名跨域

    这篇文章主要给大家介绍了关于如何利用map实现Nginx允许多个域名跨域的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-10-10

最新评论