要在 OpenResty Edge 中配置 SNI 代理,需要创建一个 SNI Proxy 类型的 Stream 应用,为每个后端创建一个上游,再编写页面规则、按 SNI 服务器名变量把每个 TLS 连接路由到对应后端——全程无需解密。然后把一个 SNI Proxy 端口添加到网关分区并发布。本教程监听 4003 端口,把 www.google.comwww.ebay.com 路由到不同上游,并用 curl 和浏览器验证结果。

下面的步骤在 Admin Web 控制台中完整演示:创建 SNI Proxy 应用、定义上游与 SNI 服务器名页面规则、开放 4003 端口、测试路由。

OpenResty Edge SNI 代理监听 4003 端口、按 SNI 名将 TLS 连接路由到不同后端的示意图

创建一个 SNI Proxy 类型的 Stream 应用

首先让我们进入 OpenResty Edge 的 Admin Web 控制台。这是我们的控制台的样本部署。每个用户都有自己的本地部署。

OpenResty Edge Admin Web 控制台首页

我们将创建一个 Stream 类型的应用。

选择 Stream 应用列表页。

OpenResty Edge 控制台的 Stream 应用列表页

创建一个新的应用。

在 OpenResty Edge 中创建新的 Stream 应用

可以看到有两种类型的 Stream 应用: SNI Proxy 和 TCP。

在 SNI Proxy 与 TCP 两种 Stream 应用类型间选择

默认选择的是 SNI Proxy 类型,也就是今天的主题。

默认选中的 SNI Proxy 应用类型

TCP 应用在另一个教程中有介绍。

TCP Stream 应用类型选项

输入 “www.google.com” 作为域名。

输入 www.google.com 作为 SNI 代理域名

在这个视频中,我们要处理具有不同 SNI 名的请求。因此需要多个域名。

点击这个按钮,添加第二个域名:www.ebay.com。

为 SNI 代理应用添加第二个域名 www.ebay.com

包含 www.google.com 和 www.ebay.com 域名的 SNI 代理应用

创建这个应用。

创建 SNI Proxy Stream 应用

创建上游与 SNI 服务器名页面规则

这与在 OpenResty Edge 中搭建基础反向代理与负载均衡是同一套上游与页面规则流程;这里我们把路由决策建立在 SNI 域名上。

转到上游页面。

SNI 代理应用的上游页面

创建一个新的上游。

创建新的上游

给这个上游取一个名字,比如,“google”。

将第一个上游命名为 google

这里我们输入 google 的主机名。

为上游输入 google 的主机名

输入端口号 443。

为 google 后端设置上游端口 443

点击保存这个上游。

保存 google 上游

现在来创建第二个上游。

创建第二个上游

将这个上游命名为 “eBay”。

将第二个上游命名为 eBay

这里输入 eBay 的主机名。

为上游输入 eBay 的主机名

输入端口号 443。

为 eBay 后端设置上游端口 443

点击保存此上游。

保存 eBay 上游

可以看到这两个上游,“google” 和 “eBay” 已经出现在上游列表页。

显示 google 和 eBay 两个上游的上游列表

现在创建页面规则来使用这些上游。

SNI 代理应用的页面规则页面

创建第一个页面规则。

创建第一个页面规则

对于这个页面规则,我们需要指定一个条件。

为页面规则添加条件

可以在这里选择条件的变量名。

选择条件的变量名

我们将根据请求的 SNI 名选择代理的上游,所以变量名应该是 SNI 服务器名。

搜索 SNI。

搜索 SNI 服务器名变量

选择 SNI 服务器名。

选择 SNI 服务器名条件变量

操作符这里保持默认选择 String= 不要变。

为 SNI 条件保持 String= 操作符

值的类型应该是 String。

将条件值类型设为 String

输入 “www.google.com” 作为值。

输入 www.google.com 作为 SNI 服务器名的值

添加一个代理目标。

为页面规则添加代理目标

选择我们刚刚创建的第一个上游。

选择 google 上游作为代理目标

已选中 google 上游作为代理目标

这里有几个均衡策略可供选择。

代理目标的均衡策略选项

由于我们的上游只有一个服务器。所以选择什么均衡策略并不重要。

单服务器上游的轮询均衡策略

保持默认的轮询策略就好。

保持默认的轮询均衡策略

因为要通过公共网络访问这个上游。所以我们在这里将所有的超时时间设置为 60 秒。

将 google 上游所有超时设置为 60 秒

创建这个页面规则。

创建 www.google.com 的页面规则

现在来创建另一个页面规则。

创建第二个页面规则

为这个规则也指定一个条件。

为第二个页面规则添加条件

条件的变量名仍然是 SNI 服务器名。

为第二个页面规则条件选择 SNI 服务器名

eBay 页面规则的 SNI 服务器名条件变量

配置 eBay 页面规则条件

输入 “www.ebay.com” 作为值。

输入 www.ebay.com 作为 SNI 服务器名的值

添加一个代理目标。

为 eBay 页面规则添加代理目标

选择我们刚刚创建的第二个上游。

选择 eBay 上游作为代理目标

已选中 eBay 上游作为代理目标

将所有超时时间改为 60 秒。

将 eBay 代理目标的超时设置为 60 秒

创建这个页面规则。

创建 www.ebay.com 的页面规则

可以看到代理页面规则已经出现在页面规则列表页。

显示 google 和 eBay SNI 路由规则的页面规则列表

最后一步是做一个新配置的发布。把我们刚才的改动推送到所有的网关服务器上。

待发布的改动已就绪

点击这个按钮做一个新的发布。

发起一次新的配置发布

发布。

确认配置发布

改动现在已经同步到所有的网关服务器上了。可以看到,这个样本部署在网关网络中有 14 台服务器。

配置已同步到 14 台网关服务器

我们在整个网络中进行增量的配置同步。

网关网络中的增量配置同步(画面 1)

网关网络中的增量配置同步(画面 2)

网关网络中的增量配置同步(画面 3)

我们在请求粒度上实时更新配置。应用级别的配置更改都不需要服务器重载、重启或二进制升级。所以,即使你有很多不同的用户进行频繁的发布,它的可扩展性也很强。

请求粒度的实时配置更新,无需服务器重载或重启

为网关分区添加 SNI Proxy 端口

如图所示,我们将使用 4003 作为监听端口。先把这个端口添加到该应用的分区中。

OpenResty Edge SNI 代理监听 4003 端口、按 SNI 名将 TLS 连接路由到不同后端的示意图

跳转到网关分区页面。

跳转到网关分区页面

打开网关分区页面。我们现在是在分区列表页。可以看到已经有很多分区存在。

网关分区列表页

我们将在分区 “default” 中添加一个 SNI Proxy 类型的端口。

打开 default 网关分区以添加端口

点击这个按钮。

向 default 分区添加端口

来添加端口。

分区设置中的添加端口按钮

可以看到列表顶部出现了新的一行。

分区中新增的端口行

输入 4003 作为端口号。

输入 4003 作为 SNI 代理端口号

类型选择 SNI Proxy。

将端口类型选择为 SNI Proxy

点击保存。

保存 SNI Proxy 端口

可以看到,新的端口已经成功地被添加到默认分区中。

端口 4003 已添加到 default 网关分区

关闭这个面板。

关闭分区设置面板

用 curl 和浏览器测试 SNI 代理

现在让我们转到网关集群页面,选择一个 Edge 服务器来做测试。

用于选择 Edge 测试服务器的网关集群页

选择一个位于美国的节点,注意其 IP 地址是以 .84 结尾的。

选择 IP 以 .84 结尾的美国 Edge 服务器进行测试

我们将使用这个服务器测试刚才添加的页面规则。

用 SNI 名 www.google.com,发送一个 curl 请求。

curl -I --resolve www.google.com:4003:3.131.85.84 https://www.google.com:4003

使用 SNI 名 www.google.com 向 4003 端口发送的 curl 请求

可以看到,服务器确实是 google。这意味着我们刚刚添加的页面规则生效了。SNI 名为 “www.google.com” 的请求被代理到了正确的上游。

curl 响应显示 google 后端应答了该 SNI 请求

现在来发送另一个 SNI 名为 “www.ebay.com” 的 curl 请求。

curl -I --resolve www.ebay.com:4003:3.131.85.84 https://www.ebay.com:4003

使用 SNI 名 www.ebay.com 向 4003 端口发送的 curl 请求

可以看到服务器是 ebay。第二个页面规则也生效了。

curl 响应显示 eBay 后端应答了该 SNI 请求

现在用浏览器来做测试。首先来看一下机器上的 Host 绑定。

cat /etc/hosts

cat /etc/hosts 显示用于浏览器测试的 Host 绑定

可以看到 Host 绑定是正确的。

已确认 www.google.com 和 www.ebay.com 的 /etc/hosts 绑定

然后用浏览器访问 google。

浏览器通过 SNI 代理加载 Google

访问 eBay。

浏览器通过 SNI 代理加载 eBay

常见问题

SNI 代理如何在不解密的情况下路由 TLS 流量?

SNI 代理从 TLS 握手中未加密的 ClientHello 里读取 SNI 域名,据此选择后端,再原样转发加密的字节流。在 OpenResty Edge 中,你用页面规则匹配 SNI 服务器名变量,网关便把每个连接路由到正确的上游,全程不终止、也不解密 TLS。

如何在 OpenResty Edge 中把不同的 SNI 域名路由到不同后端?

为每个后端创建一个上游,再为每个域名添加一条页面规则:条件把 SNI 服务器名变量设为该域名(例如 www.google.comwww.ebay.com),代理目标指向对应上游。请求到达时,网关将其 SNI 名与规则比对,代理到相应上游。

SNI 代理监听哪个端口?

端口是你在网关分区中添加的 SNI Proxy 类型端口。本教程添加 4003 端口,于是 Edge 服务器在 4003 上监听并按 SNI 名路由入站 TLS 连接。你可以选择任意空闲端口。

配置更改需要重启网关吗?

不需要。OpenResty Edge 做增量配置同步,并在请求粒度上实时更新配置。应用级别的更改都不需要服务器重载、重启或二进制升级,因此即使很多用户频繁发布,扩展性依然很强。

OpenResty Edge 能代理 SNI TLS 以外的协议吗?

可以。除 SNI Proxy Stream 应用外,Edge 还支持 TCP Stream 应用和七层代理——例如面向 HTTP/2 后端可参见如何在 OpenResty Edge 中配置 gRPC 代理

如何测试 SNI 代理是否生效?

发送一个带特定 SNI 名的 TLS 请求,确认由哪个后端应答。本教程使用 curl -I --resolve www.google.com:4003:<edge-ip> https://www.google.com:4003www.ebay.com 同理),再通过 /etc/hosts 绑定在浏览器中复验。

关于 OpenResty Edge

OpenResty Edge 是一款专为微服务和分布式流量架构设计的全能型网关软件,由我们自主研发。它集流量管理、私有 CDN 构建、API 网关、安全防护等功能于一体,帮助您轻松构建、管理和保护现代应用程序。OpenResty Edge 拥有业界领先的性能和可扩展性,能够满足高并发、高负载场景下的苛刻需求。它支持调度 K8s 等容器应用流量,并可管理海量域名,轻松满足大型网站和复杂应用的需求。

→ SNI 代理属于平台四层工具箱的一部分。其余能力见 OpenResty Edge 平台总览,或与开源版做个对比

→ 相关阅读:如果你选择在网关上终止 TLS,可以用 OpenResty Edge 的 ACME 模块自动签发与续期 SSL 证书。

如果你喜欢这个教程,请订阅这个博客网站和我们的 YouTube 频道B 站频道。谢谢!

关于作者

章亦春是开源 OpenResty® 项目创始人兼 OpenResty Inc. 公司 CEO 和创始人。

章亦春(Github ID: agentzh),生于中国江苏,现定居美国湾区。他是中国早期开源技术和文化的倡导者和领军人物,曾供职于多家国际知名的高科技企业,如 Cloudflare、雅虎、阿里巴巴, 是 “边缘计算“、”动态追踪 “和 “机器编程 “的先驱,拥有超过 22 年的编程及 16 年的开源经验。作为拥有超过 4000 万全球域名用户的开源项目的领导者。他基于其 OpenResty® 开源项目打造的高科技企业 OpenResty Inc. 位于美国硅谷中心。其主打的两个产品 OpenResty XRay(利用动态追踪技术的非侵入式的故障剖析和排除工具)和 OpenResty Edge(最适合微服务和分布式流量的全能型网关软件),广受全球众多上市及大型企业青睐。在 OpenResty 以外,章亦春为多个开源项目贡献了累计超过百万行代码,其中包括,Linux 内核、Nginx、LuaJITGDBSystemTapLLVM、Perl 等,并编写过 60 多个开源软件库。

关注我们

如果您喜欢本文,欢迎关注我们 OpenResty Inc. 公司的博客网站 。也欢迎扫码关注我们的微信公众号:

我们的微信公众号

翻译

我们提供了英文版原文和中译版(本文)。我们也欢迎读者提供其他语言的翻译版本,只要是全文翻译不带省略,我们都将会考虑采用,非常感谢!