V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
NGINX
NGINX Trac
3rd Party Modules
Security Advisories
CHANGES
OpenResty
ngx_lua
Tengine
在线学习资源
NGINX 开发从入门到精通
NGINX Modules
ngx_echo
icaolei
V2EX  ›  NGINX

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

  •  
  •   icaolei · 2023-03-21 23:01:30 +08:00 · 1855 次点击
    这是一个创建于 393 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    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 的端口,原理是啥,是在哪个环节暴露的,应该怎么避免这个问题?

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

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

    解决办法就是要替换内容,涉及到 HTTPS ,这个就麻烦了,自己研究一下吧
    koloonps
        5
    koloonps  
       2023-03-22 09:01:47 +08:00
    nginx 只是一个 http clent 。服务监听到自己的端口为 44301 直接发起重定向
    Judoon
        6
    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
        7
    winglight2016  
       2023-03-22 10:22:05 +08:00
    不了解四层转发,不过,SSL 只跟最前端设置有关,内部服务使用 http 就可以了。

    lz 这个问题,应该是把反向代理设置成了 301 重定向导致的,统一使用 proxypass 就可以了——切记上游服务不要使用 https
    coolloves
        8
    coolloves  
       2023-03-22 10:59:49 +08:00
    @icaolei proxy_redirect http://upstream-server:44301/ https://example.com/; 更改重定向地址试试
    icaolei
        9
    icaolei  
    OP
       2023-03-22 18:09:26 +08:00
    @coolloves #8 谢谢,这个是打补丁的做法,肯定是可以的。类似的做法还有不用 location ,直接用三级域名。但是我更想了解原理和如何避免这个问题,所以还是要研究下。
    icaolei
        10
    icaolei  
    OP
       2023-03-22 19:36:37 +08:00
    @koloonps #5 请教一下,服务在 docker 容器里面,容器内外都是 8000 端口,这样容器化了它也能监听到流量是从 44301 来的吗?
    icaolei
        11
    icaolei  
    OP
       2023-03-22 19:39:04 +08:00
    @winglight2016 #7 七层代理里面已经是用的 proxypass 了,感觉不像是 proxypass 导致的问题。
    yinmin
        12
    yinmin  
       2023-03-23 12:17:15 +08:00   ❤️ 1
    正解是:监听 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
        13
    yinmin  
       2023-03-23 12:30:23 +08:00   ❤️ 1
    @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 参数,部署方便且安全。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3208 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 13:43 · PVG 21:43 · LAX 06:43 · JFK 09:43
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.