[问题记录]按url context path设置nginx反向代理禅道和Jenkins

来源:互联网 发布:淘宝退款多了会怎么样 编辑:程序博客网 时间:2024/05/17 08:26

问题
在公司同一台服务器上分别装了禅道的开源版(linux一键安装)和Jenkins(docker),觉得带端口号的链接给上头leader等使用有点难看……就想改成用二级url区别的方法,即目标是:

由 dev.server.com:8001 改成用 dev.server.com/zentao   访问禅道由 dev.server.com:8002 改成用 dev.server.com/jenkins  访问Jenkins

然后简单搜索了下、写出了下面的(有错误的)nginx配置:

 server {    listen 80;    server_name dev.server.com;      location /zentao {        proxy_pass http://localhost:8001;    }    location /jenkins {        proxy_pass http://localhost:8002;    }}

按上面/zentao、/jenkins这样的新路径,禅道一下子就打开了用户登录界面,但是Jenkins却是404。


原因
原本以为Jenkins不能用很奇怪,最后发现禅道能用只是碰巧……

为什么打不开Jenkins?
首先发现如果使用端口号访问的方式、浏览器会自动跳转至Jenkins登录界面、url发生了变化,于是联想到比较下不同的url访问,整理下是:

(1) GET http://dev.server.com/jenkins 跳转至 http://dev.server.com/login?from=%2Fjenkins 404 NOT FOUND(2) GET http://dev.server.com:8002 跳转至 http://dev.server.com:8002/login?from=%2F 200 OK 显示登录界面(3) GET http://dev.server.com:8002/login 直接 200 OK 显示登录界面(4) GET http://dev.server.com:8002/jenkins 跳转至 http://dev.server.com:8002/login?from=%2Fjenkins 200 OK 显示登录界面

于是可以知道Jenkins登录界面的访问url是ip:port/login,后面的from query string只是将请求url中的path贴在了后面(%2F/)。所以nginx配置不能用的原因也很明显,Jenkins监听的是8002端口,加了nginx proxy_pass后变成了请求默认的80端口,自然是找不到/找不对的。

为什么能打开禅道?
这个是几方面的巧合:
首先如果用最上面的请求链接http://dev.server.com/zentao、没有以/结尾,按前面的配置nginx会返回301重定向至http://dev.server.com/zentao/

In response to a request with URI equal to this string, but without the trailing slash, a permanent redirect with the code 301 will be returned to the requested URI with the slash appended

然后proxy_pass的目标url http://localhost:8001也没有以/结尾,nginx会将请求路径path拼至目标url的后面、即变成请求http://localhost:8001/zentao/

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

然而使用dev.server.com:8001访问时、其实显示的是禅道的欢迎界面、可以选“开源版”或“专业版 试用”;选开源版、用户登陆界面的url样子是:http://dev.server.com:8001/zentao/user-login.html;登录之后、所有的页面操作也都在http://dev.server.com:8001/zentao/的子级url下。

所以这个似乎上来就能用的nginx配置、其实是经过一些默认转换后、恰好符合了禅道开源版的url mapping规则。如果将nginx的map规则改成location /zbox,以http://dev.server.com/zbox访问时、转换出来的路径应该是http://localhost:8001/zbox/,那结果就应该是404(这里有问题、测试下来以http://dev.server.com/zbox访问并不会自动重定向、而是直接404=>其他1)。


解决方法:
比较一下正常使用时的jenkins页面和禅道页面,禅道自身的url、a标签href、script src、image src等都是在/zentao目录下,但jenkins/docker就没有这样的设计。所以禅道可以很方便的达到dev.server.com/zentao这样的反向代理,但Jenkins就需要另外的考虑。

Jenkins:
一种思路是使用nginx在jenkins返回的所有资源链接前面都加上/jenkins字段,这样用户接下来产生的GET请求都可以map到location /jenkins区块。要实现这个功能需要用到nginx的ngx_http_sub_module。参考Example,可以写出类似配置:

location /jenkins {    sub_filter '<a href="/'  '<a href="/jenkins/';    sub_filter '<img src="/' '<img src="/jenkins/';    # ...其他替换规则...    sub_filter_once off;  # 查找并替换多次    proxy_pass http://localhost:8002;}

但是这样做效率很低、且filter遗漏和出错可能性大(比如=>其他2),所以最后还是妥协、使用了重定向:

location /jenkins {    return 302 http://dev.server.com:8002; }

这样至少使http://dev.server.com/jenkins这个(间接)访问链接可用。

如果条件允许的话,应该是分配一个子域名比如jenkins.server.com会更合理和方便,这时nginx设置可以参考jenkins官方的wiki:Jenkins behind an NGinX reverse proxy。
再或者按官方wiki的提醒、直接使用jenkins.war放到web容器里跑,这样也就能保证有/jenkins context path。

禅道:
虽然开头写成那样也可以用、考虑了下还是写的更明确一点:

location /zentao/ {    proxy_pass http://localhost:8001/zentao/;}

其他:

  1. nginx location的匹配string最后要不要加斜杠/
    这里还是很搞不清楚。
    实测下来,Jenkins使用重定向时,nginx location的匹配字段如果是/jenkins/,则http://dev.server.com/jenkins的请求结果是404;然而禅道配置这边,nginx location和http请求里、似乎/zentao/zentao/任意组合使用都是可以的,但是换成/zbox/aaa等其他不存在的path、则连301重定向都没有、而是直接报404…有点混乱就先不管了,有空看看文档再说吧。

  2. Jenkins的“跳转”显示登录页面是怎么发生的?
    同时用postman GET jenkins测试例子里(3)以外的url,可以看到返回的http状态是403 FORBIDDEN,消息体html里有类似的:

    <head>    <meta http-equiv='refresh' content='1;url=/login?from=%2F'/>    <script>window.location.replace('/login?from=%2F');</script></head>

    location.replace引用MDN:

    The Location.replace() method replaces the current resource with the one at the provided URL. The difference from the assign() method is that after using replace() the current page will not be saved in session History, meaning the user won’t be able to use the back button to navigate to it.

    Chrome console的话要勾选preserve log才能抓到403的返回状态,但html还是看不到…

  3. context path?
    contextPath是java servlet的说法,一般就是指http://example.com/aaa/bbb/ccc.html/aaa这个字段。

原创粉丝点击