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

想请教大家如何将 http 请求反代到 https 服务

  •  
  •   GogoGo666 · 2022-12-22 14:44:02 +08:00 · 3367 次点击
    这是一个创建于 462 天前的主题,其中的信息可能已经有所发展或是发生改变。
    目前有个需求,我们的业务场景是,客户流量->nginx(卸载 ssl ,https 转为 http)->流量处理(类似防火墙,但是有很多处理的过程)->nginx(将处理过的 http 重新加密为 https)->客户服务器,然后要求客户端和服务端都无感知,想请教大家,第二个 nginx(将处理过的 http 重新加密为 https)如何处理?
    31 条回复    2023-01-10 14:15:48 +08:00
    ProProPro
        1
    ProProPro  
       2022-12-22 14:52:48 +08:00
    直接 301 跳转?
    Lax
        2
    Lax  
       2022-12-22 14:56:29 +08:00
    简单来说可以: “proxy_pass https://backend.example.com;”
    复杂来说的话,有一些关于证书的配置,去文档里看看 proxy_ssl_ 开头的
    zhanlanhuizhang
        3
    zhanlanhuizhang  
       2022-12-22 15:00:03 +08:00
    直接加个代理配置就可以了。很简单的配置。
    Lax
        4
    Lax  
       2022-12-22 15:00:16 +08:00
    另外建议先看看现有成熟的方案,一般的需求不需要搞两个 nginx 。
    大部分预处理需求都可以在读请求体这个阶段实现。
    zhanlanhuizhang
        5
    zhanlanhuizhang  
       2022-12-22 15:00:54 +08:00
    简单来说,就是 nginx 配置 https ,你的服务不配置 https 。然后通过 proxy_pass 设置一下。
    defunct9
        6
    defunct9  
       2022-12-22 15:05:25 +08:00   ❤️ 2
    开 ssh ,让我上去试试
    kaedeair
        7
    kaedeair  
       2022-12-22 15:30:02 +08:00
    这个应该是要 nginx 管理证书,nginx 我用得比较少
    我用过的 traefik 可以实现,网关后面的服务都是 http ,但是进到网关强制 https
    storyxc
        8
    storyxc  
       2022-12-22 15:32:45 +08:00   ❤️ 7
    #6 ssh 哥 虽迟但到
    darkengine
        9
    darkengine  
       2022-12-22 16:31:55 +08:00
    nginx 配置文件最后加一个

    server {
    listen 80;
    server_name <your-domain-name>;
    return 307 https://$host$request_uri;
    }
    Xusually
        10
    Xusually  
       2022-12-22 17:10:44 +08:00 via iPhone
    就最简单的 proxy_pass 就行了
    sss15
        11
    sss15  
       2022-12-22 17:13:39 +08:00
    server {
    listen 443;
    server_name example.com;

    location / {
    proxy_pass http://localhost:8000;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    }
    监听 443 端口,返回出去的也是 443 端口,所有的请求,都会代理到 localhost:8000 端口,且是 http 的,就是这样子简单,无需 2 台 nginx 转来转去,想复杂了
    xwayway
        12
    xwayway  
       2022-12-22 17:33:18 +08:00
    看了下,你服务端就是一个流量处理的过程,拓扑图不用这么复杂
    用户请求 --> 贵司 nginx --> 贵司服务 --> 调用三方服务
    至于 nginx 配置可以参考

    server {
    listen 443 ssl;
    server_name abc.com;
    client_max_body_size 10m;

    ssl_certificate conf.d/ssl/abc.com.pem;
    ssl_certificate_key conf.d/ssl/abc.com.key;
    ssl_session_timeout 5m;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
    ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;

    location / {
    proxy_pass http://127.0.0.1:8080;
    proxy_set_header Host $host:$server_port;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Port $server_port;
    proxy_set_header Via "nginx";
    }
    }
    GogoGo666
        13
    GogoGo666  
    OP
       2022-12-22 17:36:04 +08:00
    @darkengine #9 感谢回复,我尝试了你的配置,结果是会重定向,我的目的是使用 nginx 启动 httpserver ,并将 http 数据加密,然后将生成的 https 数据给服务器
    @kaedeair #7 感谢回复,我研究下 traefik
    @zhanlanhuizhang #5 感谢回复,被代理的服务器是 https 服务,我们的业务时先将流量解密,进行安全处理,然后加密回去,再到服务器,我是在不知道怎么办了
    @ProProPro #1 感谢回复,直接 301 不可行,会重定向
    @Lax #4 感谢回复,我尝试了直接使用 proxy_pass 配置,也查看了相关的配置,感觉没有能实现我的目标的配置,我查了相关配置后,感觉 nginx 好像不能对接收到的 http 请求转为 https 请求到服务器,感觉其中难点应该是不使用重定向,直接将 https 的响应解密成 http 在返回给流量处理层。
    500
        14
    500  
       2022-12-22 17:45:12 +08:00
    用户-----( https)-----nginx_a
    nginx_a-----( http)-----nginx_b
    nginx_b-----( https)-----服务器

    这样看的话比较清楚:
    1. ( https)-----nginx_a-----( http)
    2. ( http)-----nginx_b-----( https)


    假设:
    用户访问的地址是: https://a.nginx.org
    nginx_b 的地址是: http://b.nginx.org
    服务器的地址是:server.org


    nginx_a 做升级代理,需要证书

    ```
    server {
    listen 443 ssl;
    listen [::]:443 ssl;

    ssl_certificate cert.pem;
    ssl_certificate_key key.pem;
    ssl_client_certificate ca.cer;
    ssl_verify_client optional;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers HIGH:!aNULL:!MD5;

    server_name a.nginx.org;

    root /var/www/a.nginx.org;
    index index.html;

    location = / {
    proxy_pass http://b.nginx.org:80;
    proxy_set_header Host $http_host;

    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    }
    }
    ```

    nginx_b 做降级代理,不需要证书

    ```
    server {
    listen 80;
    listen [::]:80;

    server_name b.nginx.org;

    root /var/www/b.nginx.org;
    index index.html;

    location = / {
    proxy_pass http://server.org:443;
    proxy_set_header Host $http_host;

    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    }
    }
    ```

    其实这个完全可以一次代理完成,用两次代理是需要劫持流量?
    GogoGo666
        15
    GogoGo666  
    OP
       2022-12-22 18:20:53 +08:00
    @500 #14 感谢回复,我马上尝试您的配置,您说的劫持流量,我们的业务应该就是这个意思,我们是与安全厂商合作,中间流量处理会有多个防火墙和 waf ,整体流量调度使用 vswitch 实现的。我是负责做安全厂商 api 对接和镜像制作的工作,所以这个 nginx 镜像的工作交到我这里了,我自己折腾 3 天没搞定。
    crab
        16
    crab  
       2022-12-22 18:46:02 +08:00
    o00o
        17
    o00o  
       2022-12-22 18:51:45 +08:00
    这是要作恶?
    GogoGo666
        18
    GogoGo666  
    OP
       2022-12-22 19:14:36 +08:00
    @o00o #17 感谢回复,不是的,中间的流量处理是安全厂商提供的,最终客户一般是地方 zf 单位
    darkengine
        19
    darkengine  
       2022-12-22 19:29:22 +08:00
    我明白你的需求了。根据我当前对后端的理解(本人菜鸡),你还是写个代码吧。例如跑个 go 服务,nginx 的所有 http 请求都到它那里,然后它负责请求目标机( https),将响应作为进来的 http 请求的响应返回去。
    GogoGo666
        20
    GogoGo666  
    OP
       2022-12-22 19:54:58 +08:00
    @darkengine #19 感谢,这也是个方法,但是无法保证性能,为了提高性能我们在服务器加了 QAT 卡,用来加速证书加密解密,用 go 不确定性能是否足够,我会想办法试试
    Lax
        21
    Lax  
       2022-12-22 21:31:02 +08:00
    @GogoGo666 https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass 仔细看看 Syntax proxy_pass 的第一段内容,第二层 nginx 接收 http 协议请求,回源采用 https 协议,有什么问题吗?
    另外,既然要求性能,楼主的这个方案是一定程度上来说是不太靠谱了。如果是串联的方式来做,可以使用 auth_request 或者 nginx-lua-module 。如果是 nginx 流量镜像,是有 ngx_http_mirror_module 可以做到的。
    honhon
        22
    honhon  
       2022-12-22 23:24:25 +08:00
    开 ssh ,让我上去试试
    honhon
        23
    honhon  
       2022-12-22 23:32:30 +08:00
    流量处理(类似防火墙,但是有很多处理的过程) 这一个阶段也类似反向代理,但是不支持 https ,但是客户服务器只支持 https ,是这个意思么
    EminemW
        24
    EminemW  
       2022-12-23 00:09:33 +08:00
    建议直接从交换机镜像流量出来,别搞这种串联的
    yikyo
        25
    yikyo  
       2022-12-23 00:16:01 +08:00 via iPhone
    是要对流量进行修改?
    如果仅记录,可以尝试镜像,traefik 也有该功能
    GogoGo666
        26
    GogoGo666  
    OP
       2022-12-23 09:39:30 +08:00
    @Lax #21 感谢回复,关于您提到的文档中 proxy_pass 的第一段内容,我是查阅了的,也在本地做了测试,结果依然是重定向实现的。关于方案的问题,其实流量调度是 vswitch 实现的,我只需要在 nginx 配置即可,所以才有了这个方案。我会尝试 nginx-lua-module
    GogoGo666
        27
    GogoGo666  
    OP
       2022-12-23 09:45:00 +08:00
    @honhon #23 其实客户服务本身是 https 服务,只是在流量到达客户服务之前,需要过我们业务串联的防火墙,但是 https 需要加密解密,会影响性能,所以才有第一个 nginx 来卸载流量的 ssl ,https 流量卸载 ssl 后变为 http 流量,然后开始由防火墙处理,处理完成后需要重新加密为 https 以请求真实的客户服务,所有才有了第二个 nginx
    @EminemW #24 这种旁路的方式我们也有,只是现在需要实现串联的业务
    @yikyo #25 是的,仅记录的话就简单了
    eryajf
        28
    eryajf  
       2022-12-23 17:50:55 +08:00
    @storyxc #8 如果真开了,那就是两个 2 的问题😂
    lazyfighter
        29
    lazyfighter  
       2022-12-23 18:09:45 +08:00
    目前能想到的只能是 body_fitler_by_lua, 通过 lua 在将 body 请求转发到 nginx 上面 ,由 nginx 转发到你们的服务器 ,拿到结果 lua 覆盖原始 body , 最终在进行 proxy_pass , 看了一下 nginx 提供的 7 个钩子,基本不可能在 proxy_passs 就是 rewrite 阶段之后在进行 rewrite 。
    lazyfighter
        30
    lazyfighter  
       2022-12-23 18:12:20 +08:00
    @lazyfighter 抱歉错了, 应该是在 rewrite 阶段转发到你们的服务上面
    GogoGo666
        31
    GogoGo666  
    OP
       2023-01-10 14:15:48 +08:00
    感谢诸位 v 友回复,给了我很大帮助,我不再一一 @回复了,我会把我的配置放到之后的内容
    ————————————————————————————————————————————————————————
    nginx 最终使用了 headers_more 模块,qat_zip 模块,qat 模块
    以下为相关配置

    http {
    ..........................
    map $upstream_http_Location $location {
    ~https://$IP/(?<param>.*) http://$IP/$param;
    default $upstream_http_Location;
    }

    map $sent_http_set_cookie $resp_cookie {
    ~*(?<CK_WITHOUT_SECURE>.+)Secure $CK_WITHOUT_SECURE;
    }

    server {
    listen 80;
    server_name $Name;
    location / {
    proxy_pass https://$IP;
    proxy_ssl_asynch on;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header REMOTE-HOST $remote_addr;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_redirect off;
    more_set_headers -s '301 302' 'Location $location';
    more_set_headers 'Set-Cookie: $resp_cookie';
    }
    }
    }
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2635 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 15:50 · PVG 23:50 · LAX 08:50 · JFK 11:50
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.