使用四层代理转发流量以复用 443,结果在浏览器地址栏暴露了转发后的端口

2023-03-21 23:01:30 +08:00
 icaolei

请教一下大佬们,设置的四层代理如下:

stream {
    map $ssl_preread_server_name $name {
        www.example.com     home;    # Home Page

        default     defaultpage;
    }

    upstream home {
        server 127.0.0.1:44301;
    }

    upstream defaultpage {
        server 127.0.0.1:44300;
    }

    server {
        listen  443 reuseport;
        listen  [::]:443 reuseport;
        proxy_pass	$name;
        ssl_preread on;
    }
}

在七层代理的 server 里监听 44301 ,使用 location /home/ 来指向部署的服务。 实际访问时,如果访问 https://www.example.com/home/ 可以正常访问。 但访问 https://www.example.com/home 就会跳转到 https://www.example.com:44301/home/

由于部署的项目本身不支持自定义路径,修改源码工程量太大,已放弃通过 locaion 来指向服务的方式。

不过我还是很想知道,为啥会暴露 44301 的端口,原理是啥,是在哪个环节暴露的,应该怎么避免这个问题?

2070 次点击
所在节点    NGINX
13 条回复
phpfpm
2023-03-21 23:28:54 +08:00
敌人在内部
deorth
2023-03-22 00:18:00 +08:00
站点本身有 301 ,你这种情况只能放弃 tcp 反代改用 http 反代
icaolei
2023-03-22 01:24:00 +08:00
@deorth #2 有点疑惑,站点本身应该不知道我在 nginx 监听的端口是多少啊,站点的 301 应该也是发送到 443 端口,最多也是发送到站点本身部署端口(例如使用 docker 将站点容器部署在 8000 ),讲道理的话站点的 301 应该还是会走到四层代理去,然后再走七层代理,最多也是走到 8000 去,为啥会直接 301 到 44301 端口呢?
NewYear
2023-03-22 08:53:44 +08:00
你想歪了,跳转行为有 2 个发起方,一个是通过浏览器,相对路径,另一个是通过服务器,绝对路径。

如果你只考虑转发流量,不替换服务器发给客户端的内容,就是现在的结果。

解决办法就是要替换内容,涉及到 HTTPS ,这个就麻烦了,自己研究一下吧
koloonps
2023-03-22 09:01:47 +08:00
nginx 只是一个 http clent 。服务监听到自己的端口为 44301 直接发起重定向
Judoon
2023-03-22 09:29:00 +08:00
我测了一下,nginx 的规则中,location 后面跟的 path 末尾如果加 / ,则在访问 https://www.example.com/home 时 nginx 本身会写一个 301 到 https://www.example.com/home/ 和后端服务无关。

把这个路径后面的 / 去掉大概率就好了。如果不是这个原因,应该也可以通过其他方式解决 301 后的端口问题
winglight2016
2023-03-22 10:22:05 +08:00
不了解四层转发,不过,SSL 只跟最前端设置有关,内部服务使用 http 就可以了。

lz 这个问题,应该是把反向代理设置成了 301 重定向导致的,统一使用 proxypass 就可以了——切记上游服务不要使用 https
coolloves
2023-03-22 10:59:49 +08:00
@icaolei proxy_redirect http://upstream-server:44301/ https://example.com/; 更改重定向地址试试
icaolei
2023-03-22 18:09:26 +08:00
@coolloves #8 谢谢,这个是打补丁的做法,肯定是可以的。类似的做法还有不用 location ,直接用三级域名。但是我更想了解原理和如何避免这个问题,所以还是要研究下。
icaolei
2023-03-22 19:36:37 +08:00
@koloonps #5 请教一下,服务在 docker 容器里面,容器内外都是 8000 端口,这样容器化了它也能监听到流量是从 44301 来的吗?
icaolei
2023-03-22 19:39:04 +08:00
@winglight2016 #7 七层代理里面已经是用的 proxypass 了,感觉不像是 proxypass 导致的问题。
yinmin
2023-03-23 12:17:15 +08:00
正解是:监听 44301 网站配置的问题,加下面一行即可解决问题。
absolute_redirect off;

另外,你的 nginx 配置还有 2 个优化的地方。

1.网站程序无法获得浏览器的 IP 地址,解决的方法是启用 proxy_protocol 协议。调整如下:

server {
listen 443 reuseport;
listen [::]:443 reuseport;
proxy_pass $name;
proxy_protocol on;
ssl_preread on;
}

然后监听 44301 的 listen 改成:
listen 44301 ssl http2 proxy_protocol;

2.建议去掉 map 的 default 行,提升 tls 安全。客户端必须提供正确域名才会建立 tls 连接,能抵御网络盲扫后攻击。
yinmin
2023-03-23 12:30:23 +08:00
@icaolei 服务在容器里,有 3 种配置方法:
(1) bridge 网络,-p 127.0.0.1:8000:8000 ,容器内的服务绑定到 0.0.0.0:8000, docker 映射到主机 127.0.0.1:8000 ,nginx 直接 proxy 到 127.0.0.1:8000
(2) host 网络,不设-p 参数,容器内服务绑定到 127.0.0.1:8000 ,nginx 直接 proxy 到 127.0.0.1:8000
(3) 建立 docker 虚拟内网,容器使用虚拟内网固定 ip 地址,不设-p 参数,容器内服务绑定到内网 ip:8000 ,nginx 直接 proxy 到内网 ip:8000

方式一:比较常见,但在超大流量下会有性能问题
方式二:高性能,适合超大流量使用
方式三:如果部署多个容器联动(程序容器、数据库容器、redis 容器等),所有容器都使用虚拟内网固定 ip ,都不设-p 参数,部署方便且安全。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/926010

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX