1. 说明

我的目的是,图床的域名,国内依旧使用七牛云 CDN,境外的请求使用 Cloudflare 代理。Cloudflare 能帮我们拦截一些高危的 IP 地址,能避免海外肉鸡刷你的图床服务。

如果你用过 Cloudflare,其在 SSL/TLS 模块提供了一个自定义主机名的服务,可以让用户在不将域名改成 Cloudflare 的 DNS 的情况下,使用 Cloudflare 的代理功能。

这个功能是 Cloudflare for SAAS 的一部分,你应该能在网上找到很多教程。

简单说来,想使用这个功能,需要如下几个条件

  • 实际使用的域名:对于我而言是 musnow.top
  • 用于指定回退源的域名:这是第二个域名,名字无所谓,可以直接去 EU.org 申请一个免费的。该域名需要接入 Cloudflare 的 DNS,这里用 example.com 举例子(对于用户来说,这个域名是感受不到的);
  • 一个云服务器:IP 用 1.1.1.1 举例子;

当你配置好了之后,请求网站的路径变成了如下模样

plaintext
1
2
配置前:域名musnow.top->A记录->云服务器1.1.1.1
配置后:域名musnow.top->CNAME记录->回退源域名example.com->Cloudflare->云服务器1.1.1.1

使用自定义主机名功能,可以让 Cloudflare 在请求你源站的时候,使用原有域名(实际使用的域名),而不是回退源域名。假设你需要回源的云服务器是国内的服务器。

  1. 回退源域名 example.com 没有备案 -> 请求国内服务器会被服务商拦截
  2. 配置自定义主机名 musnow.top 后;
  3. Cloudflare 在回源到服务器的时候,采用自定义主机名的域名,即 musnow.top
  4. 由于实际使用的域名 musnow.top 已备案 -> 请求国内服务器不再被拦截;

整个过程中,回退源域名 example.com 对于用户是无感知的!我们实现了在原有域名 musnow.top 的 DNS 没有接入 Cloudflare 的情况下,使用了 Cloudflare 的防护服务。

目前免费版本的自定义主机名有如下要求:

  • Cloudflare 必须要验证你的支付方式,不会扣你钱的(paypal 或者银联信用卡,当时为此我还专门去办了个没有额度的学生信用卡,后来发现压根不需要,直接用 paypal 绑定个银联储蓄卡 / 借记卡就可以了)
  • 免费版本的回退源只能指定一个,即只能回源到一个 IP 地址的服务。

当然你也可以去多弄几个域名,每一个域名都可以设置一个回退源。白嫖嘛,不寒掺。

2. 配置

2.1. 回退源

首先是设置回退源域名的 DNS,将其接入 Cloudflare。随后是在 DNS 记录中添加一个 A 记录,指向你的源站服务器 IP。

image.png

这里我使用的名称是 back.回退源域名,在 SSL/TLS 模块的自定义主机名中开通 Cloudflare SAAS 服务,并添加回退源域名

image.png

添加回退源域名并验证成功后,就可以点击蓝色添加自定义主机名按钮,添加你需要代理的原始域名了。

这里我添加了我的图床域名 img.musnow.top,首先是在腾讯云的 DNS 中设置 CNAME 解析,将境外线路设置为回退源的域名,默认线路还是七牛云 CDN 的 CNAME。

image.png

添加了域名解析之后,你还需要在 musnow.top 的 DNS 解析里面添加两个 TXT 记录来验证回退源,参考 Cloudflare 给出的 txt 记录提示就可以。界面类似下图

image.png

添加了之后点击刷新,直到自定义主机名的状态显示为有效,即配置成功。

image.png

使用海外服务器测试,配置前,解析到七牛云 CDN;配置后,解析到回退源域名,即 Cloudflare

image.png

2.2. 反向代理

但这里只是配置好了域名解析而已,还需要用反代才能让境外访问图床域名能访问出图片来。

2.2.1. 反代原有七牛云 CDN 的 CNAME 不起作用

但是这个反代要怎么配置呢?因为只是解析线路不同,直接把 img.musnow.top 反向代理到 img.musnow.top 肯定不行,试试反代到七牛云的 CNMAE

测试发现,直接通过七牛云 CDN 里面的 CNAME 访问这个图片会 403(不管是浏览器访问还是使用 curl 访问),而反代过后,curl 和 wget 的结果都变成了 526,无法访问图片

plaintext
1
2
3
4
5
6
7
8
9
╰─ curl https://img.musnow.top/i/2023/05/647563ddab0fb.gif
error code: 526%

╰─ wget https://img.musnow.top/i/2023/05/647563ddab0fb.gif
--2023-12-16 18:48:21-- https://img.musnow.top/i/2023/05/647563ddab0fb.gif
Resolving img.musnow.top (img.musnow.top)... 172.67.157.61, 104.21.56.251, 2606:4700:3035::ac43:9d3d, ...
Connecting to img.musnow.top (img.musnow.top)|172.67.157.61|:443... connected.
HTTP request sent, awaiting response... 526
2023-12-16 18:48:21 ERROR 526: (no description).

image.png

即便在反代里面设置了后端请求的域名为 img.musnow.top,访问依旧会是 526

image.png

也就是说,我们不能直接把反代地址设置成七牛云的 CDN 地址。

2.2.2. 未设置 Cloudflare 时能成功解析

作为对比,在没有配置解析到 Cloudflare 的时候,使用 wget 是能访问出图片来的

image.png

将 wget 的这个图片通过 sftp 下载下来,能看到它是正常的 gif,图片访问没有问题。

image.png

2.2.3. 解决方案

我能想到的解决办法,是白嫖一下七牛云免费的 10GB HTTP 流量,新建一个 HTTP 回源的 CDN,绑定到图床的 bucket 上即可。

image.png

注意,只要你的回源地址是国内的 bucket,那么 域名就必须要备案才能配置 CDN。

因为现在是通过云服务器反代来访问这个 CDN,此时反代的 proxy 设置为 http,在添加 img.musnow.top 的 cert 证书到反代设置里面,就能实现 https。

plaintext
1
https://img.musnow.top 反代 http://img-cloudflare.musnow.top

image.png

注意,反代中的后端域名也需要设置为新的 CDN 域名,否则访问会因为域名不匹配而 403 拒绝访问。

image.png

随后就是添加 img.musnow.top 的 SSL 证书

image.png

测试一下,新建的这个 cdn 域名可以通过 http 访问到 bucket 里面的图片

image.png

再测试一下反代后的域名,也可以访问到图片了,这里访问的 IP 地址 104.21.56.251 也已经是 Cloudflare 的 IP 了。配置成功!

image.png

此时海外访问我的图床,解析变成了如下过程

plaintext
1
2
3
img.musnow.top -> CNAME回退源域名 -> cloudflare(https) 
-> 云服务器反代(https) -> img-cloudflare.musnow.top(http)
-> 七牛云CDN -> 七牛云bucket

因为最终访问的 CDN 是通过 HTTP 回源 bucket 的,能白嫖七牛云 10G 的免费流量!

当然,如果真有人在海外打你,刷完 10G 流量也不是不可能…… 所以在 cloudflare 里面最好再配置一下单 IP 访问的频次限制!

比如下图,我设置访问 URL 为图床开头 /i 时进行速率监看,如果单 IP 访问速率超过 60 次 / 10 秒,那么就会触发 cloudflare 的速率限制响应,持续 10 秒。

因为我的博客已经设置了懒加载,所以一次性加载 60 个图片的场景是不存在的!这种规模的请求肯定是攻击了!再加上我的博客理论上不会有几个海外用户阅读,所以这个配置不会对国内用户产生影响。

如果你使用了代理,请把 musnow.top 所有子域名加入代理白名单。

image.png

2.2.4. 进一步优化,IP 白名单

进一步优化,就是把新创建的这个 HTTP CDN 里面设置 IP 白名单,只允许我们设置反代的服务器的那个 IP 地址访问,这样就保证了其他人不能直接刷我新建的这个 HTTP 的 CDN 域名。

image.png

在七牛云的 CDN 配置界面可以看到 IP 黑白名单,添加服务器 IP 地址为白名单即可

image.png

配置后需要过一段时间才会生效,会有个进度条。完成后,再次本地测试一下,发现已经 403 不允许访问了。

image.png

此时在海外服务器尝试反代域名访问,依旧是 OK 的,访问的 IP 地址 172.67.157.61 也依旧是 Cloudflare 的 IP。

image.png

3. The end

至此,配置完成!