基于 SNI 的 Nginx 选择性 TLS 直通反向代理

基于 SNI 的 Nginx 选择性 TLS 直通反向代理

我的 IoT 设备系统位于 NAT 后面,因此无法从公共互联网访问它们(尽管这是理想的情况)。为了解决这个问题,我将它们绑定到 VPN 中,其中一个成员暴露在公共互联网中,充当网关。VPN 设置了一个内部域,网络的每个成员都有一个基于唯一 ID(我们以 MAC 地址为例)的子域,如下所示:12a4f81ead4e.vpn.example.com

我希望在Gatway代理请求上创建一个运行 nginx 的反向代理。

计划是为网关创建一个 DNS 记录,*.gateway.com并将往返于 的流量路由(代理)12a4f81ead4e.gateway.com12a4f81ead4e.vpn.example.com。这样最终用户只需12a4f81ead4e.gateway.com在浏览器中输入即可访问他们的设备。我想使用 nginx,因为网关已经在为其他目的运行 nginx。

我希望 HTTP 请求很简单,并且可以通过精心设计的 nginxproxy_pass指令来完成。

但是 HTTPS 请求怎么办?据我所知,基于 SNI 的 TLS 直通现在已由 nginx 实现,但到目前为止我看到的所有示例都创建了一个静态映射……很好地将传入的 SNI 映射到目标上游:

stream {
  map $ssl_preread_server_name $selected_upstream {
    example.org upstream_1;
    example.net upstream_2;
    example.com upstream_3;
    default upstream_4;
  }
  upstream upstream_1 { server 10.0.0.1:443; }
  upstream upstream_2 { server 10.0.0.2:443; }
  upstream upstream_3 { server 10.0.0.3:443; }
  upstream upstream_4 { server 10.0.0.4:443; }
  server {
    listen 10.0.0.5:443;
    proxy_pass $selected_upstream;
    ssl_preread on;
  }
}

问题是设备是从 VPN 动态添加/删除的,我不想一直重写 nginx 配置文件。如果可以从文件中读取地图,那么这是朝着正确方向迈出的一步,尽管我认为每次更改时都需要重新加载 nginx,这会引发权限问题,当然可以使用 sudo 规则来规避,但不是最好的解决方案。

此外,我只想代理进入的请求*.gateway.com,并正常将其他 https 请求发送到现有虚拟主机。如果可能的话,我想避免终止 SSL 连接。这其实并不是一个硬性要求,但如果技术上可行,我想以这种方式实现它。也只是为了好玩。

我可以在内部监听其他虚拟主机的备用端口,当我想设置“全局”位置时,我对 HTTP 做了类似的事情,并将所有 HTTP 虚拟主机移动到端口 81,并在端口 80 上实现了一个捕获所有虚拟主机,为“全局”位置提供服务,并将其他所有内容代理到端口 81。:)

所以...我需要的是类似这样的东西(显然不起作用):

stream {
  map $ssl_preread_server_name $selected_upstream {
    (.*).gateway.com $1.vpn.example.com;
    default normal_serve;
  }

  upstream normal_serve { server 127.0.0.1:8443; }

  server {
    listen 0.0.0.0:443;
    proxy_pass $selected_upstream;
    ssl_preread on;
  }

  server {
    listen 127.0.0.1:8443;
    server_name other.website.com;

    (...)
  }
}

答案1

这是诀窍:

stream {
  resolver 8.8.8.8;

  map $ssl_preread_server_name $selected_upstream {
    ~(.*).gateway.example.com $1.vpn.example.com:443;
    default 127.0.0.1:8443;
  }

  server {
    listen 0.0.0.0;
    proxy_pass $selected_upstream;
    ssl_preread on;
  }
}

http {
  resolver 8.8.8.8;
  server {
    listen 127.0.0.1:8443 ssl;
    (...)
  }
}

相关内容