【进阶向】Cloudflare 自定义主机名单域名优选与 Nginx SNI 分流详解

【进阶向】Cloudflare 自定义主机名单域名优选与 Nginx SNI 分流详解
卡友通信一、背景
(一)前言
很多人买了 VPS,也用 Cloudflare 大善人提供的服务,同时 Nginx 是一个比较容易上手的高性能 Web 服务器,用它来进行反向代理配置,而且还有更好用的 Nginx Proxy Manager 配置更是简单(虽然我不用),今天只是通过 Nginx 来讲解原理,其他的 Web 服务器参考原理来进行配置。
用到 Cloudflare 和 Nginx 常常会有很多需求,譬如:
- 隐藏机器 IP 防止被打;
- 加速境内访问自建站点的速度;
- 其他用途(各位应该都懂,具体就不展开说了)。
(二)开始今天的教程之前,需要做好以下准备
准备条件:
- 拥有一个在 Cloudflare 进行解析的开启了小黄云 CDN 的域名作为源站域名(下文用自有域名
test.isakura.in来演示)。 - 已经使用源站域名在自己的服务器通过 Nginx 部署了一个网站(最好配置了有效证书)。
- 拥有一个提供给别人访问的外部域名(因为我没有多余的域名,我将在 Cloudflare 解析
abcd.isakura.in作为我的外部域名,如果有条件的也可以用其他服务商托管解析的域名)。
也因此本文是单域名优选教程。
(三)最终达成效果
最终效果:
- 浏览器访问
https://abcd.isakura.in,最终显示网站的内容; - 浏览器访问
https://test.isakura.in,最终返回 404; - 优选 IP 或者域名,加速网站的访问。
(四)通过这次实战你会了解
通过这次实战你会了解:
- CDN 数据流向过程;
- Nginx 中实现的 SNI 分流;
- 数据包传递中请求头 host 和 SNI 的作用。
二、引入的前置知识
(一)Nginx 的配置文件(每一行代码都有注释)
1. Nginx 的配置文件主要是以代码块的形式存在,主要有全局代码、events 块、stream 块和 http 块。这些块里面又可以含有其他代码块,其中我们需要用的是 stream 块和 http 块的代码:
1 | # 配置文件总览 |
2. 部署一个普通网站的代码块,仅用到 http 块就好了(已省略不必要参数):
1 | http { |
3. 通过 stream 模块来进行域名 SNI 分流,分流后将请求网站的流量送回 http 块(已省略不必要参数):
1 | stream { |
(二)自定义主机名功能(来自 SaaS,此功能的开通需要验证支付方式)
自定义主机名功能中,可以自行定义一个主机名 A,当 Cloudflare 接收到访问 A 的请求时,将这个访问请求回退到一个自定义源服务器 B。注意,B 的域名必须有托管在 Cloudflare,进行了解析并开启了小黄云的 A 记录、AAAA 记录、CNAME 记录。
上面这句话要注意几个点:
- B 已经是在 Cloudflare 进行了小黄云解析的了,因此 B 已经隐藏了其真实 IP;
- 需要的是 Cloudflare 接收到访问 A 主机名的请求,也就是 Cloudflare 的 CDN 收到了访问 A 主机名的请求;
- 在收到 Cloudflare 的 CDN 收到请求后,进行回退到源服务器的操作,并且会根据选择的自定义源服务器,回退数据包的 SNI 值。
(三)关于数据包的 SNI 值和 host 值
- 访问网站的数据包在到达服务器时,在传输层使用 TCP 协议,在应用层使用的是 HTTP 协议。
- SNI(Server Name Indication)是 TLS 协议的扩展字段,在 HTTPS 连接的 TLS 握手阶段发送,目的是让服务器在建立加密连接前,就知道客户端想要访问的具体主机名。但如果没有加密连接场景,SNI 值则不会存在(此处不考虑该情况)。
- host 值是 HTTP 协议的请求头之一,用于在应用层指定客户端想要访问的网站域名。
- 服务器会先在 TLS 握手时解析 SNI 值来确立加密连接,随后才会解密 HTTP 数据,读取 host 值来处理具体的网页请求。所以从时间顺序上来说,SNI 应该是优先被处理,而后续根据 HTTP 请求头中的 host 值来访问具体网站内容,因此 SNI 也充当了路由的功能。这两个值一般来说是一致的,但在优选场景下 SNI 值出现了变更。
优选场景下的数据流向:
1 | graph LR |
正常访问时 SNI 和 host 一致,但经过自定义主机名 + 优选配置后,SNI 变为源服务器域名,host 保持为自定义主机名。这就是 SNI 分流的基础。
(四)优选 IP / 域名
其实就是在中国大陆访问延迟低、速度快、相对稳定的 Cloudflare CDN 的 IP / 解析到 Cloudflare CDN 的 IP 的域名 / 甚至是反代了 Cloudflare CDN 的 IP(譬如 Reality 的 IP)。
(五)实战前我的基础配置
Cloudflare 配置:


Nginx 配置(已部署证书,并略去多余配置):
1 | stream { |
网站文件配置:
我的主机在 /usr/local/testdir 下存放了一个 index.html:

它的代码如下(AI 写的),访问的时候会在页面中间显示当前 host 值:
1 |
|
访问效果如下:

三、实战操作(含 Cloudflare 优选、Nginx 分流配置、保护源域名)
(一)添加自定义主机名,设置回退到源服务器
原理: 这一步的意义是让 Cloudflare 知道,如果我们的访问自定义主机名请求给到 Cloudflare,那么 Cloudflare 知道要访问哪个源去获取资源。
1. 添加一个默认回退源服务器
此处我将 test.isakura.in 作为回退源服务器添加进去,如果 B 满足上述条件,应该添加进去几秒钟后刷新就有效。

2. 添加自定义主机名
此处是 abcd.isakura.in,自定义源服务器必须选「自定义源服务器」且需要填回退的源服务器 test.isakura.in。




关于自定义源服务器:
- 默认源服务器: 回退到默认源服务器,且 SNI 值会被设定为「自定义主机名 host 值」
- 自定义源服务器: 回退到自定义源服务器,且 SNI 值会被设定为「自定义源服务器」
注意: 想要为同为 Cloudflare 的域名优选,如果选择默认源服务器,则当回退时,Cloudflare 会检测到你的自定义主机名所在域是 Cloudflare 管理的域,同时会根据 SNI 将请求再次返回自定义主机名,会造成 Error 1000,因此如果是在 Cloudflare 中进行优选,则不能选择默认源服务器。
关于主机名状态:
如果这个主机名是在 Cloudflare 的顶级域归属 Cloudflare 解析,那么主机名状态会自动变为「有效」,否则需要在解析商添加 TXT 验证。
关于证书验证方法:
- HTTP 验证: 是一种自动验证方式,要满足几个条件。首先要满足不是泛域名,然后这个主机名要么是归属 Cloudflare 的,要么它已经由 Cloudflare 来代理流量了。
- TXT 验证: 上述 HTTP 验证方法不行的情况下,都需要使用 TXT 验证,就是在主机名的解析商添加解析记录进行验证。
3. TXT 方式验证证书(有条件的建议使用 HTTP 验证,此处仅演示)


过一会刷新状态,证书变为有效:

(二)为自定义主机名添加 DNS 解析,解析到 Cloudflare 的 CDN 上(优选的重要步骤)
原理: 虽然 Cloudflare 知道如果它接收到这个访问自定义主机名的请求时,需要访问源服务器获取资源,但这个请求从哪里来呢?因此这一步就是为这个自定义主机名进行解析,让自定义主机名的请求能解析到 Cloudflare 的 CDN 上。这一步也是优选的关键步骤,落到哪个 CDN 上是由你来定。
附: 此步骤可以在其他域名解析服务商里面进行,如果在国内的服务商还可以实现国内外线路分流。
1. 找一个优选的 IP / 域名
这个你们自己去找,网上应该很多,我直接就用一个域名了(*.cloudflare.182682.xyz),它含三线解析。
2. 为自定义主机名添加解析,解析到优选 IP / 域名上

小技巧: 如果是优选的域名,也可以添加一个 CNAME 记录 cdn.isakura.in 指向 abcd.cloudflare.182682.xyz,这样以后如果再需要为自定义添加优选域名的话,就可以直接添加 CNAME 记录到 cdn.isakura.in,也方便后续更改优选域名,只要更改 cdn.isakura.in 的 CNAME 记录即可。

至此,优选已经完成! 但是我们访问 abcd.isakura.in 和 test.isakura.in 均能访问。为了我们的服务器安全,还需要做几步。
(三)在 Nginx 上配置 SNI 分流,过滤大部分无效请求
原理: 正常访问的 HTTP 数据包,默认的 SNI 字段和 HTTP 请求头中的 host 是一样的。但经过上面的设置后,访问自定义主机名的请求,最终到达服务器时,host 值不改变,SNI 值变为源服务器域名。
上面已经设置了自定义主机名是 abcd.isakura.in,源服务器是 test.isakura.in,因此访问 https://abcd.isakura.in 时,当请求来到我的服务器,这个数据的 host 值为 abcd.isakura.in,SNI 值为 test.isakura.in。
因此进行分流需要设置 stream 块的值,我之前的默认设置已经是配好了,不需要改动。
分流的关键设置是在 stream 中的 map 块,对需要预读的 SNI 进行限定,这样 server 块对其进行反向代理时,不属于 map 块中出现的 SNI 将会被拒绝。
1 | stream { |
(四)让 Nginx 只接受访问自定义主机名的请求,拒绝其他请求
原理: 第(三)步已经通过 SNI 筛选了大部分请求,但是并没有根据 host 筛选请求。现在需要在 http 块中设置根据 host 值判断是否返回内容,如果 host 值为自定义主机名,则返回内容,否则不返回。
根据 host 值来进行判断,就是应用层的事情了,在 Nginx 配置的就是 http 块,需要在 location 中添加一段 if 判断条件的配置,当 host 不等于 abcd.isakura.in 时,返回 404。
1 | http { |
经过以上设置,只有 host 为 abcd.isakura.in 的请求能被响应,**test.isakura.in 的请求失效**:
源域名保护完成!现在直接访问 test.isakura.in 会返回 404,只有通过自定义主机名 abcd.isakura.in 才能访问网站。

(五)检查 Cloudflare 加密配置
原理: 这里的加密配置主要指的是 Cloudflare 请求我们的网站时是否需要加密(实际上这一步在开启小黄云时就可以设置),有 4 个选项:

| 模式 | 用户 ↔ Cloudflare | Cloudflare ↔ 源站 | 说明 |
|---|---|---|---|
| 完全严格(Full Strict) | Cloudflare 证书加密 | SSL 加密 + 证书验证 | 建议用这个,网站有证书就选它 |
| 完全(Full) | Cloudflare 证书加密 | SSL 加密,证书不验证 | 证书过期/不匹配也能通过 |
| 灵活(Flexible) | Cloudflare 证书加密 | HTTP 明文,无加密 | 不建议,不安全 |
| 关闭 | 无加密 | 无加密 | 全链路无加密 |
这里要根据服务器部署网站的方式来选择,我个人是选择第一种的,但我建议最起码都要选择第二种。
最后在 ITDOG 查看优选前后的测速状态:
未优选前的状态:

优选后的状态:

四、结语
本人作为一个非计算机从业者,上述的原理均为本人自身借助网站资料和 AI 学习理解,可能真实理解会有偏差,如有错误请纠正指出。
这篇文章,其实是用 Cloudflare 单域名优选的方式,抛砖引玉地说明了 CDN 和 Web 服务器是如何搭配使用的,这不仅仅是在网站 CDN 部署上,在其他可以发掘的场景也有借鉴之处,希望能帮到有需要的人,也是给我自己留下一个学习记录。
本文内容整理自 NodeSeek 社区,原文作者分享了 Cloudflare 单域名优选的完整实操流程与原理。如有疑问欢迎评论区交流。


