nginx 正向代理 https 4层代理、7层代理

文章介绍了在应用服务器受限于网络环境时,如何通过在前置机上使用Nginx进行四层和七层代理,以实现访问外网。详细讲解了两种方案,包括配置resolver、使用stream块和http块,以及处理多域名映射的情况。同时提到了正向和反向代理在443端口的限制问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题背景

因为网络环境受限,应用服务器无法直接访问外网,需要前置机上中转一下,这种情况可在应用服务器修改/etc/hosts文件指向前置机,在前置机上的nginx设置四层代理,从而出站。
在这里插入图片描述

方案

根据How to Use NGINX as an HTTPS Forward Proxy Server,nginx支持正向代理https,有L7(应用层,使用http connect)和L4(传输层)两种方式,L7和L4对客户端是有感知的,L7代理需要显式设置客户端的代理,L4要修改DNS解析(linux上/etc/hosts文件),

7层代理

7层代理即应用层代理,客户端使用http的connect方法与代理创建tunnel,代理与目标地址建立tcp连接,如此以来,代理与客户端、目标端分别建立了tcp链接,代理无脑转发TCP Stream,在此基础上客户端与目标端完成SSL握手。
在这里插入图片描述

4层代理

ngx_stream_core_module模块是实现L4代理的关键,使用nginx -V查看加载的模块,有以下几个参数,即表示支持4层代理。4层代理即运输层代理,https是运输层之上,所以对于运输层是透明的。

  • –with-stream
  • –with-stream_ssl_module
  • –with-stream_ssl_preread_module

经过考虑,选择了4层代理实现方式,这样只需要修改调用端所在机器的/etc/hosts,而代码不需要改动,对调用端而言相对透明。以下是实现4层代理的两种方式,本质而言是一样的,语法上有点差异。

解决方案一

博客中的写法

stream {
 # 注意,如果访问的是域名,则必须配置resolver;如果访问的是ip,则可以不用配resolver;
    resolver 114.114.114.114;
    server {
        listen 443;
        # 从SSL握手中的clientHello包中读出访问的域名
        ssl_preread on;
        proxy_connect_timeout 5s;
        proxy_pass $ssl_preread_server_name:$server_port;
    }
}

linux上可通过nslookup some.domain.com查看DNS;不配置resolver,访问域名时SSL握手失败,在error.log(nginx -V能看到--error-log-path选项)会有体现,
在这里插入图片描述
nginx在启动时会对域名解析一次,启动后不再解析,所以proxy_pass 中有变量时,必须配置resolver,以达到每次请求都可解析(nginx缓存了DNS解析结果,并不是每次请求都会实际DNS解析),可参考nginx中resolver参数配置解释Why does a variable not work in NGINX proxy_pass?;resolver指令还有valid选项用来控制DNS缓存时间;比如

resolver 127.0.0.1 [::1]:5353 valid=30s;

注意:stream块与http块是平级的,切勿嵌套;

解决方案二

如果只访问一个域名,可以写死;

http{
 //something else
}
stream {
    server {
        listen 443;
        ssl_preread on;
        proxy_pass www.baiducom:443;
    }
}

测试SSL时,可使用openssl s_client,详情可参考openssl s_client工具详解

openssl s_client -connect www.baidu.com:443 -debug

或者

openssl s_client -connect www.baidu.com:443 -msg

或者curl https://some.domain.com/some/path -v

上述解决方案只访问一个域名可以写死,如果访问多个域名该怎么办?老海给出了答案,也可参考官方文档Module ngx_stream_ssl_preread_module样例

stream {
  map $ssl_preread_server_name $target {
    a.com a-network;
    b.com b-network;
  }

  upstream a-network {
    server a.com:443;
  }
  upstream b-network {
    server b.com:443;
  }
  server {
    listen 443;
    ssl_preread on;
    proxy_pass $target;
  }

客户端访问a.com,经过map块映射,$target等于a.com:443,从而被server块中的proxy_pass代理到a.com:443。

总结

方案一和方案二都能满足需求,方案一相对简练,但要注意配置resolver;每次新增访问的域名,方案二都需要相应添加配置;

思考

经同事提醒,同一个nginx不能同时正向和反向代理443端口;想想为什么?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值