宛如仙境的城堡

金光闪闪的新代理协议:XHTTP

三个月之前,词元发布了一则非常详细的 VLESS、WebSocket、TLS 加上 CDN 的代理搭建指南(搭建自己的代理服务器),给出了词元当时认为最安全的方案。

事实证明,这个方案确实很安全,元旦期间词元用的 Cloudflare Anycast IP 被封了,但词元的服务器 IP 依然坚挺,可以正常访问(改 hosts 可以继续使用 CDN)。而这个安全性,主要就来自于 CDN 的加持,这样可以最大限度地防止 IP 泄露,将自己的流量隐藏在 CDN 边缘服务器的巨量吞吐中,被封也就无从谈起了。

上个月,词元又在 XTLS/Xray-core 的讨论中看到维护者 RPRX 提供了一种他十分自豪的方案:XHTTP。光是从他宣传 XHTTP 的力度(超长“简”介、写进个人主页)上来看,这个协议很牛。

之前词元嫌麻烦,原本的“三驾马车”协议也很够用,而且词元也不能确定这个协议抗封锁的有效性。(词元并不是科学上网领域的专家!)但是最近看到不良林也发布了搭建这种协议节点的视频,说实话有点心动了。借着 L 站上白嫖的节点,词元删掉了原本搭建使用的脚本,来试试这个金光闪闪的新协议!

“……这下又开启了一个崭新的时代……”——RPRX

✨ 这是什么

词元与上一篇文章相反,先来讲讲 XHTTP 的原理。因为,来这儿看先进技术的您估计已经有了能用的代理节点,看这则博客的目的大概是改进一下安全性,肯定要先知道凭什么做出改变嘛。

🫣 永不被封的 meek 协议

故事的开端是一个叫作 meek 的协议。这个协议原本是 TOR 的一种混淆处理方式,在 TOR 的实现中模仿了 Azure 的流量,用以防止封禁。

image-20250120193401001

TOR 浏览器中也提到,这种方法虽然能在“重度”审查地区使用,但是会非常缓慢。

半年之前,Xray 的维护者在内核中实现了 meek 协议。其关键,就在于将 VLESS 节点信息伪装成普通 HTTP 流量,采用标准格式。正常的 HTTP 流量中,服务端在没有客户端的请求的情况下,不能向其主动发送数据包。为了克服这一问题,meek 在发送请求之后,不能从服务端得到数据,而是会再次发送请求,获得服务端已经从客户端请求的地址中获取的数据。

绕晕了?列个表:

  • 浏览器:访问 hi.bug-barrel.top
  • 客户端代理:拦截请求,先用 VLESS 加密,然后包进正常 HTTP 数据包中,发送给服务端代理。
  • 过墙(内到外),检测到正常 HTTP 数据包。
  • 服务端代理:收到 HTTP 数据包,解包;里面是 VLESS 数据包,解包;哦,原来是 hi.bug-barrel.top,发送给目标服务器。
  • 目标服务器:对服务端代理慢慢发包,正在传输。
  • 客户端代理:过一段时间,发包问服务端代理“好没好啊”,包装方式相同。
  • 过墙(内到外),检测到正常 HTTP 数据包。
  • 服务端代理:还没有收到目标服务器发的包,回复一个空数据包,包装方式相同。
  • 重复以上三步,直到服务端代理收到目标服务器的数据包,服务端代理回复有内容的数据包。

就这样,客户端反复发包,服务端反复回复(还得严格按照顺序),直到数据传输完成。

优点是全部都是标准的 HTTP 数据包,以往 GFW 依赖的那些特征通通不存在(VLESS 数据本身加密,加上 HTTPS 加密,不大可能泄露),而且还能用 CDN(标准 HTTP 嘛);缺点就是,慢!这方法本身就浪费时间,发挥一下优势,加个 CDN——更慢。

根据不良林的实测,即使是很好的线路(CN2 GIA),给 meek 这么一搞,速度能上到 200 Kbps 就算好的了。因为其不会被封的特性,当个备用节点传送“千金家书”还是不错的,但是日常使用……还是算了。

🛜 全能的 XHTTP

meek 的思想可以概括为“分包上行,流式下行”,而 XHTTP(原名SplitHTTP)解决的问题就是下行速率的问题。XHTTP 实现了不损失上行效率、流式地过 CDN,然后用不定长的包流式下行,且上下行分流,只要是标准 HTTP 包支持的,上下行都可以分别支持(可以完全不同)。

这确实是一个非常优雅的解决方案,把之前 WebSocket、gRPC、REALITY 等等的优势综合起来,而且特征非常低。具体实现的特别之处,可以看看维护者的夹叙夹议的讨论,这小介绍搞得 😄

image-20250120201927872

讨论里对于 XHTTP 的技术细节介绍得非常详尽,如果您有一些网络基础,就会发现这玩意儿确实挺牛。春节马上就要到了,您做好准备开工了吗?

⚙️ 搭建 XHTTP 代理

本节参考不良林的视频撰写,综合了词元的个人经验,也很建议您去看看原视频,有些东西词元在上一篇文章里已经讲过了,就不仔细介绍。

词元在自己研究的基础上,决定按照视频里的指导,选择这样的协议组合:VLESS、XHTTP、Reality,以及 CDN 保护,上下行流量分裂。

💡 其实原视频建议下行不使用 CDN,因为 gRPC 流式下行用 CDN 会比较慢。但是这里为了安全,词元还是决定全部使用 CDN。

这是快速迭代的科学上网技术中最先进、最安全的方案(尤其是在 XHTTP 的参与下,“最先进”可以确定了 😁)。相应地,由于功能多,配置也很复杂,但是按照维护者的说法,大多数保持默认即可。

🏃‍♂️ 准备

首先,您需要有一部线路还不错的服务器,有钱就去 BandwagonHost 上 CN2 GIA,没钱就到 RackNerd 买部也还凑合的洛杉矶 MC 机房的 VPS,实在不行服务端上 WARP 去解锁吧。

服务器的基本配置,您可以看词元的往期博客,重点要设置一下 SSH 密钥登录,防止服务器密码暴力破解。

然后,千万别忘了,要断开(如果有的话)您正在使用的那部服务器提供的代理,并另找一个不错的代理,不然 SSH 断联或者 YouTube 视频放不了就老实了。

然后,无论您之前拿什么玩意儿搭的代理,一律移除,为 XHTTP 驾到做好准备 😁 如果您之前采用词元推荐的脚本安装了 caddy,也建议您使用 dnf 重新安装一次,以保证它能随系统更新。

🔧 安装 3X-UI 面板

3X-UI 面板此前拒绝按照 Xray 的推荐,强制要求用户开启 HTTPS 或使用 SSH 端口转发,因此被维护者从 Xray 推荐面板的名单中移除。但是毕竟 3X-UI 是开源的,只要我们自己开启了这些功能,大概是没啥问题的,而且它作为 X-UI 的后继者,目前还在积极开发,功能和安全性上更完善。

按照 3X-UI 仓库文档的说明,直接在 root 权限下使用一键脚本安装。

⚠️ 对于比较信任的脚本,可以直接执行一键脚本;但是还是建议您先看看脚本的内容,如果有什么奇怪的东西,就别着急拿着 sudo 去跑了。

1
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)

稍候一会儿,等待命令自动执行完成,然后我们用 Caddy 进行反向代理,顺便获取一个 SSL 证书,这样连接更加安全。X-UI 面板因为 HTTP 明文连接的原因,很容易被 FOFA 这类的网络空间测绘的搜索引擎查到,因此非常不建议您直接使用 HTTP 连接,也很推荐您安装 fail2ban 这种封禁工具。

1
2
sudo dnf install fail2ban && sudo systemctl enable --now fail2ban
sudo dnf install caddy && sudo systemctl enable --now caddy

然后添加反向代理:

1
2
3
4
5
6
7
8
sudo vim /etc/caddy/Caddyfile.d/3x-ui.caddyfile
# 在 Vim 中输入
“面板域名” {
    reverse_proxy http://127.0.0.1:端口号 # 端口号在刚刚安装完展示过
    # 用 `sudo x-ui settings` 可以再次查看
}
# 结束 Vim 输入
sudo systemctl restart caddy

注意,重启 Caddy 之前要在域名托管商那边设置这个域名(咱就称为“面板域名”好了)的解析,Cloudflare 用户暂时不要开启小黄云(申请证书的时候需要直接访问)。这样,我们就将面板的端口转发到了 443 端口上,实现了 HTTPS 访问。

可以用 sudo systemctl status caddy 看看证书申请得怎么样了,如果出现 error 字样,像这样:

image-20250120213936719

说明配置有问题,需要修改。尤其注意防火墙需要开放 80 和 443 端口,或者如果您使用 firewalld,那就启用 httphttps 两个服务。

如果像这样:

image-20250120214144475

则说明申请成功,可以打开小黄云,然后从您的浏览器用 3X-UI 给出的路径访问了!Caddy 的配置惊人地简单,下文不再赘述添加域名的方法了。

image-20250120214500280

输入您看到的用户名和密码,登录进管理界面。由于我们没有采用面板内置的申请 SSL,在查看密码的时候可能会提示没有启用 SSL:

image-20250120214651054

忽略即可,在网页端这个警告已经消失了。首先,我们来修改一下随机生成的用户名和密码。

image-20250120214946472

按您自己的习惯和需要设置即可,也可以在这一页的下面开启 Token 登录,这样更安全。

🧙‍♂️ VLESS、XHTTP、Reality 入站规则

然后,在“入站列表”中按以下配置建立一个入站规则:

  • 启用:那当然,备注:随意。
  • 协议:vless
  • 监听:留空,监听所有地址。
  • 端口:4432053 或者 8443 这类广泛受 CDN 支持的 HTTPS 端口。
  • 总流量:0(无限,自己限制自己干嘛),到期时间:不填。
  • 客户:保持默认。
  • 传输:XHTTP
  • 主机:留空。
  • 路径:随便生成一个 UUID,可以用在线工具
  • 下面直到“安全”都保持默认。
  • 安全:Reality。
  • Dest 和 SNI 保持默认的 yahoo.com 即可,目前看来不会触发连接重置,尚且可用。
  • 其他保持默认。
  • 点击“Get New Cert”生成一个密钥。

然后便可添加节点,这样我们的节点就添加完成了。选择菜单可以导出节点链接,这时候可以先导入客户端试试能不能用,不着急连接。

image-20250120220921655

Linux 用户注意:常用的 v2rayA 使用 v2ray 内核,不支持 XHTTP 节点,需要使用 v2rayN,现在后者也有 Linux 版本了。

可以注意到,这个节点的地址就是我们的“面板域名”,端口就是我们设置的、可用于 CDN 的端口,开启了 HTTPS(Caddy 自动申请的),且拥有完全的加密协议。现在,您可以打开它的小黄云了。

这个节点就搭建完毕,接下来设置上行、下行的规则。

⬆️ 上下行分流

在 Cloudflare 面板里,添加两条解析记录,分别称为“上行域名”和“下行域名”,暂时不要开启小黄云。然后前往域名设置中,打开 gRPC 支持:

image-20250120235323570

回到 3X-UI 面板,创建一个新的进站规则:

  • 启用、备注就不说了。
  • 端口:随便选择一个,大于 1024 就好。
  • 传输:XHTTP
  • 路径:还是随机生成一个 UUID。
  • 安全:无。
  • 其他保持默认。

如果您之前拿 X-UI 搭建过 WebSocket 节点,就会发现这玩意儿除了协议是 XHTTP,其他简直和 WebSocket 一模一样。只不过,WebSocket 是使用专门的隧道和帧数据来传输,只有一小部分 CDN 支持(但是包括 Cloudflare),而 XHTTP 就是标准的 HTTP 流量。

然后,我们在 Cloudflare 那边再添加两条解析记录(“上行域名”和“下行域名”),将其解析到服务器,然后在 Caddy 那边,配置如下:

“上行域名”:端口 {
    reverse_proxy http://127.0.0.1:你刚刚设置的端口
}

“下行域名”:端口 {
    reverse_proxy http://127.0.0.1:还是那个端口
}

这两个端口号可以随意设置,甚至可以不一样,只要保证实际指向的本地端口相同即可。

发现没有?实际上,这两个解析实际上是一模一样的。至于为什么我们不直接使用面板的那个端口,那是因为 Caddy 的自动 HTTPS 证书申请很方便,将这个端口给 Cloudflare,域名就能开启 Full(Strict) 模式,全流程加密。

下面的一步,词元是跟着教程做的,其中的原理词元说实话——也不是很懂,但是没有这个操作是用不了的。大家先跟着做,词元要是悟出原因了再回来告诉大家吧……

到 Cloudflare 面板,来到 Rules 里的 Overview。

image-20250121092046815

点右侧的“Create Rules”,从“Products”里选择“Origin Rules”,添加一条。

image-20250121092228308

随便起个名字,然后关键是添加规则,如图:

image-20250121092325019

一路拉到最下面,填入刚刚你为“上行域名”选择的那个端口号:

image-20250121092522866

然后保存,再为你的“下行域名”也设置一样的规则。

规则很简单,就是把所有 80 端口的请求全部转发到服务器的实际端口(然后再被 Caddy 反代到本地端口),但是为什么这么做?词元暂时不清楚。

💡 后来词元想到的最合理的猜想就是:为了模仿 HTTP 流量,端口必须为常用的网页端口,而且只有访问 80 这样的通用端口的时候才能使用 Cloudflare 的 CDN。

🖥 客户端设置

最后,我们回到客户端。删除刚刚那个“面板域名”的那个节点,我们以后不会直接使用它;然后导入你刚刚创建的第二个节点链接,右键修改配置。

image-20250121093143382

按照图中的说明,有数字的部分无须修改,标文字的部分需要按照您的实际情况修改。这里以 v2rayN 为例,是因为目前似乎只有它提供了比较完整的 XHTTP 支持,Clash 系和使用 v2ray 内核的目前都没有支持。

然后,最重要的一步,我们刚刚设置了一个下行域名,现在我们需要添加相应的配置。

image-20250121094403432

在蹦出来的文本框内,输入以下配置:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
{
  "downloadSettings": {
    "address": "“下行域名”",
    "port": 之前第一个节点对应的端口号,
    "network": "xhttp",
    "security": "tls",
    "tlsSettings": {
      "serverName": "“下行域名”",
      "allowInsecure": false
    },
    "xhttpSettings": {
      "path": "第二个节点的路径,注意不要少了前面的斜杠",
      "mode": "auto"
    }
  }
}

这段配置的本质就是添加一个节点,作为我们正在修改的节点的下行。

好了!然后,测试一下真延迟和速度,如果正常的话,恭喜您,您赶上时代了!

🎆 下课

对抗审核的本质就是使封禁成本尽可能大。从某种意义上来说,我们使用 CDN 作为前置,实际上是对于 CDN 的滥用——CDN 不是用来传送静态资源的吗?但我们用它来作为中间部分,避免过墙地访问自己的服务器。

试想,现在的 GFW 是黑名单模式,也就一律放行,除了已知的需要屏蔽的域名。但是,如果未来的某一天,突然切换至白名单模式(就像伊朗试行过的那样),到时候如果有 Cloudflare 或者谁家的 CDN 在白名单内,又该不该使用呢?

词元为了使用 CDN,是每个月给 Cloudflare 付了使用费(Pro),但是免费的 CDN 也很好,很够用了。希望 Cloudflare 能多给一点机会,希望它晚些进入中国市场,因为这意味着它将不得不遵守政府的要求,很可能会屏蔽、封号代理的 IP。

😮‍💨 几天之后的幺蛾子:XHTTP 虽好,但是这个 gRPC 断流是什么鬼?连接 10 分钟,断流 5 分钟,尤其是对于词元这种垃圾线路,只要切断连接,原地立刻爆炸。还是“三驾马车”香啊……

Banner