Nginx以HTTP反向代理HTTPS的Exchange邮件服务
笔者使用Nginx反向代理时,上游服务强制启用了HTTPS访问,但我们的需求是以HTTP统一对外提供服务。
经过一些探索,发现问题主要来源于上游应用302跳转
、set-cookie响应头的secure
属性两方面,需要合理调整Nginx的站点配置文件来解决。
This post shows how to proxy HTTPS Exchange Mail service with HTTP protocol when using Nginx reverse proxy. The key point is to handle
302 redirect
andsecure
attribute in configuration of Nginx.
文章参考了 浅流 - Nginx以HTTP反向代理HTTPS服务 这篇文章,但其对Nginx的more_set_headers
属性设置有问题,导致set-cookie
头从secure
属性的后面截断,在具有多个set-cookie
响应头的登录场景中不适用。
问题发现
问题背景参考原文,用以下配置运行 Ngnix, 使其用 HTTP 协议在 9080 端口反向代理 19026 上的 HTTPS 服务。
1 | server { |
但是如果我们用浏览器访问 http://10.115.6.165:9080/databoard/login ,就会发现如下图所示的两问题:
后端服务使用 redirect 重定向导致的问题
浏览器地址栏上显示被重定向到了https://10.115.6.165/databoard/dataCmder .
这是因为后端Web应用
执行了redirect重定向语句,而重定向的协议、地址是基于web应用上下文的,而nginx并没有做特别的处理就转发给了浏览器,浏览器自然不能访问到这个地址。解决办法如下:
1 | map $upstream_http_Location $location { |
Cookie 携带 Secure 属性问题
Cookie的Secure
属性,意味着保持Cookie通信只限于加密传输,指示浏览器仅仅在通过安全/加密连接才能使用该Cookie,而我们的需求是以HTTP方式传送。如果不去掉,浏览器会提示不接受这个Cookie。
对于该问题,原文采用的方案是通过nginx的more_set_headers
模块,通过map
中正则表达式对Set-Cookie
进行改写。
但该方案会导致Set-Cookie
直接从secure
属性的前面截断,如果secure
属性在中间,或者是有多个Set-Cookie
属性时,就无法适用。
经过查阅 Nginx官方文档中的 Module ngx_http_proxy_module ,发现从nginx 1.19.3开始,加入了proxy_cookie_flags
的directive,恰好可以去掉secure
属性并且加入samesite
属性(如果不加入samesite属性,浏览器一样会拒绝)。
因此,完整配置如下:
1 | map $upstream_http_Location $location { |
成功去掉了secure
属性,加上了samesite
属性。
但是,需要注意的more_set_headers
仅在Nginx 1.19.3以上才支持,因此您需要升级Nginx版本,以使用该方案。
Ubuntu编译安装新版本Nginx并加入相关模块支持
如果不清楚如何升级自己的Nginx,可以参考以下。
执行 apt search nginx
会发现Ubuntu22.04的apt源中nginx版本太老,为1.18.0,不能满足我们的需求。
因此需要从源码编译安装,需要注意的是添加OpenSSL模块(不然无法代理HTTPS的服务)、并且添加 headers-more-nginx-module
这个附加模块。 (https://github.com/openresty/headers-more-nginx-module)
使用以下命令进行编译配置。
完成后 make && sudo make install
即可。
安装完毕之后, 默认路径在 /usr/local/nginx/sbin/nginx
,因此可以 sudo ln -s /usr/local/nginx/sbin/nginx /usr/bin/nginx
建立一个软链接。
编译安装的nginx默认没有sites-enabled
这个目录,可以手工在其conf目录新建一个,并且在nginx.conf
中引入:
1 | # nginx.conf |
随后将其注册为 systemd
服务,在 /etc/systemd/system
新建一个 nginx.service
:
1 | # /etc/systemd/system/nginx.service |
记得 sudo systemctl daemon-reload
重载服务,再 sudo systemctl start nginx
即可运行。
Nginx以HTTP反向代理HTTPS的Exchange邮件服务
https://www.catop.top/2024/01/17/nginx-proxy-exchange-mail-with-http/