使用 Nginx 反向代理 Jenkins

安装 jenkins 并启动后,此时访问地址是:http://localhost:8080

默认占用的是8080端口,且启动的是 http 服务,出于安全考虑,我打算改成 https。

采用的方案是:使用已经配置好 https 的 Ngixn 反向代理 Jenkins 服务。

下面是配置步骤:

修改 Jenkins 端口和根目录

修改配置文件中的下面两项配置即可

#启动端口修改为8899
JENKINS_PORT = "8899"
#根目录修改为/jenkins
JENKINS_ARGS="--prefix=/jenkins"

重启 Jenkins,此时 Jenkins 的访问地址是:http://localhost:8899/jenkins

配置 Nginx 代理

server {
	listen       443 ssl;
	server_name  YOU_DOMAIN_NAME;
	charset utf-8;
    ssl_certificate      YOU_CA;
    ssl_certificate_key  YOU_CA_KEY;
    location /jenkins/ {
    	proxy_pass http://localhost:8899;
    	proxy_http_version 1.1;
    	http2_push_preload on; # Enable http2 push
    	
    	proxy_set_header   X-Forwarded-Proto  $scheme;
    	proxy_set_header   X-Forwarded-For    $remote_addr;
    	proxy_set_header   X-Real-IP          $remote_addr;
    }
}

重启 Nginx,此时直接访问 https://localhost/jenkins 也可以访问到 Jenkins 了。

ok,正常情况下到这里就配置完成了。但是我却多踩了两个坑。。。

因为我的Nginx 和 Jenkins 是部署在家里的电脑上(有公网ip),运营商80和443端口是关闭的,没法用!所以只能用路由器的端口转发功能。

路由器端口映射如下:

nginx监听端口 路由器转发端口
443 2443

所以此时我访问 Jenkins 的地址就变成了:https://xxx.com:2443/jenkins/ ,请求转发的路线如下图所示:

graph LR
A[用户] -->|https://xxx.com:2443/jenkins/ | B[路由器]
B -->|https://xxx.com/jenkins/ | C[Nginx]
C -->|http://localhost:8899/jenkins/| D[Jenkins]

第一个坑:

直接访问 https://xxx.com:2443/jenkins/ 也没问题,也能访问到,但是!

一但 Jenkins 向前端返回302重定向,Nginx 会把重定向的地址设置成:https://xxx.com/jenkins/

端口没了,,,

首先想到的是这个配置:proxy_redirect 。

这个配置项的官方文档地址是:
Module ngx_http_proxy_module

这个配置的默认值是:proxy_redirect default,默认行为是:将后端返回的重定向 host 地址修改为 Nginx 服务器的 host 地址,端口变成 Nginx 的端口,所以重定向的地址是不带端口号的。

所以,解决思路也很简单了,就是在 Jenkins 返回重定向的时候要把 2443 端口号带上,修改 location 配置如下:

location /jenkins/ {
    proxy_pass http://localhost:8001/jenkins/;
    proxy_http_version 1.1;
    http2_push_preload on; # Enable http2 push

    proxy_set_header   X-Real-IP        $remote_addr;
    proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
#    proxy_set_header   X-Forwarded-Proto $scheme;#这个加上的话,jenkins返回的重定向地址会变成https://localhost:8001

    #下面是解决重定向问题的配置
    proxy_redirect http://localhost:8001 https://$http_host;
}

重新访问 https://xxx.com:2443/jenkins/ ,登录后跳转没问题了!但是。。

第二个坑

但是,在管理台会有一个“反向代理设置有误”的提示。

打开浏览器控制台也会看到有请求报错,点击提示框中的“更多信息”按钮,会跳转到一个 Jenkins 文档地址:

原来,Jenkins 会自动识别 X-Forwarded-Proto、X-Forwarded-Host、X-Forwarded-Port 这些请求头,返回 302 重定向的时候会自动重定向到正确地址。

所以我参考 Jenkins 的 文档,修改 location 配置如下:

location /jenkins/ {
    access_log logs/access.log;
    proxy_pass http://localhost:8001/jenkins/;
    proxy_http_version 1.1;
    http2_push_preload on; # Enable http2 push

    proxy_set_header   X-Real-IP        $remote_addr;
    proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
    proxy_set_header   X-Forwarded-Proto $scheme;

    #下面是解决重定向问题的配置
#    proxy_redirect http://localhost:8001 https://$http_host;
    proxy_set_header   X-Forwarded-Host $http_host;#这里用$http_host,$http_host包含端口,就不用了设置X-Forwarded-Port
}      

重启 Nginx 后访问:https://xxx.com:2443/jenkins/ ,登录成功。但是,控制台“反向代理设置有误”的提示依然存在。。。

面向搜索引擎一番之后,终于明白了这个问题的所在:

在 Jenkins 的管理台的 Configure System 配置模块中有一项 Jenkins URL 配置:

默认配置是什么我忘了,我之前已经顺手把它改成了:https://xxx.com:2443/jenkins/ ,也就是我的 Jenkins 外网访问的根目录。

jenkins判断“反向代理设置有误”的依据就是:向这个 Jenkins URL 配置的地址发送一个请求,请求的末尾会携带 Jenkins 控制台的地址。完整请求示例如下:

https://xxx.com:2443/jenkins/administrativeMonitor/hudson.diagnosis.ReverseProxySetupMonitor/testForReverseProxySetup/https%3A%2F%2Fxxx.com%3A2443%2Fjenkins%2Fmanage/

后端接到请求会对比请求的 host 和参数中控制台地址,如果一样就返回200,不一样就返回404错误,前端就根据返回结果是不是200来控制“反向代理设置有误”的提示框是否显示。所以 Jenkins URL 如果配置的不正确,也是会有“反向代理设置有误”的提示框的。

可是我配置的 Jenkins URL 是正确的,为什么也会有提示框?查看浏览器控制台的请求结果如下:

仔细看这个红框中的地址,原来 Jenkins 接收到的参数中少了个斜线,https://xxx.com:2443/jenkins/manager/ 变成了 https:/xxx.com:2443/jenkins/manager/ 。。。

造成斜线丢失的原因就是 当 proxy_pass 以 / 结尾时,Nginx 会对 request_url 进行处理,默认会合并 request_url 中相连的多个斜线为一个。

解决方案就是把 proxy_pass http://localhost:8001/jenkins/ 修改为 proxy_pass http://localhost:8001

重启 Nginx 后,刷新页面,提示框消失。

另外我还根据 Jenkins Reverse proxy - Nginx 文档 增加了下面的配置:

    #其他配置
    proxy_max_temp_file_size 0;

    #this is the maximum upload size
    client_max_body_size       10m;
    client_body_buffer_size    128k;

    proxy_connect_timeout      90;
    proxy_send_timeout         90;
    proxy_read_timeout         90;
    proxy_buffering            off;
    proxy_request_buffering    off; # Required for HTTP CLI commands
    proxy_set_header Connection ""; # Clear for keepalive

第三个坑

第三个坑同样是因为路由器端口映射造成的,也跟重定向有关。

现象是这样的,访问 http://xxx.com:2443/jenkins/ 没问题,但是访问 http://xxx.com:2443/jenkins 的时候后 Nginx 发现没有匹配的文件 location 但是有匹配的目录 /jenkins/。此时 Nginx 会返回一个301 重定向,重定向的地址是:http://xxx.com/jenkins/。端口又没了。。。

解决方案是在 server 中增加这条配置:absolute_redirect off; 加完后重定向的地址会变成相对地址:/jenkins/

可以用 curl 测试下:curl -v https://xxx.com:9443/jenkins

如果不生效可能是浏览器缓存原因,清下缓存就行了。

具体逻辑不想写了,累。。。看下面三个配置项的文档就明白了。

absolute_redirect

server_name_in_redirect

port_in_redirect

理论上还可以通过增加这样一个 location 来解决:

location /jenkins {
	return 302 $scheme://$http_host/jenkins/;
}

没测试,不想试了。。。

总结

没有总结,累。


原文:使用 Nginx 反向代理 Jenkins | kun's blog