CF-Workers-TGProxy README

The project's README from github.com/ToiCF/CF-Workers-TGProxy. As one markdown file: README.md.

CF-Workers-TGProxy

Cloudflare Workers 的 Telegram Web/MTProto WebSocket 代理中继(KWS Lanes)。

telegram_webproxy.js 是一个单文件 Cloudflare Workers 实现:它扮演 Telegram 官方 Web Proxy(td web-proxy)后端,把客户端(Desktop / Android)在隔离 webview 里发起的 WebSocket lanes,直接转接到 Telegram Web K 自己的 KWS 通道(kws{dc}[-1].web.telegram.org/apiws)。

它不再依赖一套独立的 MTProxy / middle proxy 后端:Worker 在本地解开客户端 MTProto 传输层的 obfuscation,再用自己生成的随机密钥重新封一层,拨 Telegram 官方的 Web K 入口。内层 MTProto 载荷始终由客户端端到端加密,Worker 不接触、也不做 mtp 层加解密。

核心能力

当前代码主线包含:

代码主路径

flowchart LR
  TG["Telegram Desktop / Android"] -->|webview 加载 web-proxy 页面| P["Worker 页面 (nonce CSP)"]
  P -->|postMessage 端口| L["lanes: 每条流一条 WebSocket"]
  L -->|"tproxy-lane-v1.token.sid"| WS["/api/v1/ws"]
  WS --> S["mkSession → mkStream"]
  S -->|"解 obfuscation (AES-CTR)"| RK["mkHead 重新封层"]
  RK -->|"dial wss://kwsN[-1].web.telegram.org/apiws"| KWS["Telegram Web K / KWS"]
webview 页面
  → 建立 /api/v1/session(POST,带 bootstrap)
  → 拿到 session token + X-Carrier-Mode: websocket-lanes
  → 按流开 lane:/api/v1/ws + 子协议 tproxy-lane-v1.<token>.<sid>
  → Worker: 解 obfuscation → 重新封头 → 拨 KWS → 中继

为什么从官方 MTProto 转向 KWS 转换

Telegram 官方的 web-proxy 模型(tproxy)需要一套独立后端:客户端连到本地/自建的服务,再经它转发到远端 MTProxy,链路里多一跳、多一套需要自己运维的加解密中转。

本实现把这一整套换掉:

维度 经 middle/MTProxy 的官方 web-proxy 路径 本实现(KWS 转换)
后端 需自建 MTProxy / middle proxy 无,Worker 即后端
传输面加密 代理侧承担 mtp 层与 obfuscation 只落一层 obfuscation(AES-CTR)重签
出站目标 自建中转服务器 Telegram 官方 kws*.web.telegram.org
内层 MTProto 载荷 端到端(客户端) 端到端(客户端,Worker 不接触)

也就是说,转向 KWS 的关键点是:Worker 只处理传输层,不处理 mtp 层。客户端 MTProto 载荷原样透传,Worker 只对 64 字节 obfuscation 头做一次解、一次重签,再走 Telegram Web K 用的同一入口,边缘可达性与线路质量都直接吃官方域名。

性能理论上提升多少倍

以下为基于当前代码路径的理论模型(标记 [推断]),不是本仓库的实测基准。

综合到瓶颈场景,理论提升从 约 2x 起(仅算加解密 + 去跳),小包风暴场景在汇聚部分叠加后可更高。[推断]

设计重点

1. 多 lane 直接替代 Durable Object

公开的 Workers web-proxy 实现大多用 Durable Object 来维持"单条长连接 / 单份状态"。DO 是单线程且需要路由到固定实例,上限和排队都集中在那个对象上。

本实现改为按流拆 lane:

TG 客户端本身就有多流、并且会自动分流,所以 lanes 让每条流各自背压、各自排队,而不是把整条会话压进一个单线程对象。这正是"不需要 DO、TG 侧也感觉不到单连接限流"的设计依据。

2. 小包汇聚

上下行各自把连续小块先收进一颗薄核,再尽量并成更少的实际写入:

上传: collect -> bundle -> peer.write()
下载: collect -> bundle -> dnPack 门控 -> ws.send()

目的都是削减高频小 frame 带来的固定调度成本,而不是再造一层重型队列。

3. 鉴权与租约

4. 页面隔离

5. 禁用 WebSocket 压缩协商

握手响应里显式把 Sec-WebSocket-Extensions 置空。relay 主线传的是原始 TCP 字节流(内部多为 TLS/HTTP2 等高熵数据),在 Worker 这层再做 WS 压缩换不来稳定收益,反而抬高热路径 CPU,因此按负优化处理。

当前配置

变量 意义 默认值
dnPack 下行聚合上限 32 * 1024
upPack 上行合包目标 20 * 1024
dnMs 下行 quiet-window 1(ms)
lane 上限 单会话并发 lane 数 128
laneMax / laneItems 单 lane 字节 / 条数上限 8MB / 1024
qMax / iMax 整会话字节 / 条数上限 32MB / 16384
bootstrap TTL 一次性接入 token 2 分钟
session TTL 会话 token 5 分钟
KWS 端点 Telegram Web K 出站 kws{1..5}[-1].web.telegram.org/apiws

密钥配置

绑定 意义 要求
SECRET 代理密钥:AES-CTR 传输密钥派生 + ?bridge= 能力签名 32 位 hex,或 dd / ee / ef 前缀 + 32 位 hex(共 34);字符集 0-9a-f;大小写不敏感,建议小写
BOOT bootstrap token:签发 bootstrap / session,并内联进下发页面 仅要求非空,建议 ≥ 16 字符随机串

生成命令:

目标 命令 输出
SECRET openssl rand -hex 16 32 位 hex
SECRET(带前缀) printf 'dd%s\n' "$(openssl rand -hex 16)" 34 位 hex
BOOT openssl rand -hex 24 48 位 hex

openssl rand 走系统 CSPRNG,是真随机。任一绑定缺失,mkCfg 直接抛错,/health 会返回 500 而不是 {"ok":true}。

路由

路径 方法 说明
/ GET / HEAD 校验 bridge 签名后下发 web-proxy 页面
/health GET {"ok":true}
/api/v1/session POST 建会话,返回 session token
/api/v1/session DELETE 注销会话
/api/v1/ws GET lane WebSocket(需 Upgrade 与正确子协议)

文件

文件 说明
telegram_webproxy.js Worker 主实现:页面 / session / lane / obfuscation / KWS 中继

访问优化(CNAME / SaaS 优选)

相关链接

Stargazers over time

Stargazers over time

CF-Workers-TGProxy (ToiCF/CF-Workers-TGProxy)

Searching Database…

这是什么?一个单文件的 Cloudflare Workers 脚本,充当 Telegram 自带的 Web Proxy(td web-proxy)后端,把 Telegram Desktop/Android 内嵌 webview 打开的 WebSocket 通道直接中继到 Telegram 自家的 Web K(KWS)信道。
这是一个完整的 MTProxy 服务器,还是别的东西?它不是需要你自己运行的传统 MTProxy/中间代理后端;它只是解包并重新签名客户端的 MTProto 传输层混淆,然后把连接直接转发到 Telegram 官方的 KWS WebSocket 端点。
怎么把它跑起来?把单文件 'telegramwebproxy.js' 部署为 Cloudflare Worker,并配置两个密钥绑定:SECRET(一个 AES-CTR 密钥,32 个十六进制字符)和 BOOT(一个引导签名令牌);两者缺一不可,否则健康检查会失败。
用它需要自己的域名或 Cloudflare 账号吗?部署它需要一个 Cloudflare Workers 账号;README 建议通过 CNAME 指向你自己的域名,或使用 Cloudflare SaaS 自定义主机名,以获得到 Telegram 边缘节点更好的路由质量。
这些性能说法是实际测得的基准数据吗?不是。文中声称的提速(约 2 倍及以上)被明确标注为基于相关微基准测试(GrainTCP)的理论推断,而不是对这个仓库本身的实测。
为什么使用多条 WebSocket 通道而不是 Durable Object?Durable Object 是单线程的,会把整个会话固定在一个实例上,形成瓶颈。本项目改为让每个 Telegram 流拥有自己的 WebSocket 通道(每个会话最多 128 条),因此每条通道都在同一个 isolate 内独立排队和施加背压。
引导/会话令牌的鉴权流程是怎么工作的?页面会签发一次性 nonce 和短时效的引导令牌(2 分钟);客户端通过 POST /api/v1/session 用它换取一个会话令牌(5 分钟),该令牌绑定到一个跟踪活跃通道的每会话租约上,而 DELETE /api/v1/session 可以立即吊销它。
为什么从官方 MTProxy 模式切换到 KWS 路由?直连 Telegram 自家的 Web K(KWS)端点省去了额外的一跳中继,也无需再运行单独的 MTProxy/中间代理后端,把每个包的加密工作量缩减为一次混淆重签,而不是完整的 mtp 层中继。
它如何处理突发的小帧?小的出站和入站帧会在写入前被合并:上游每批最多 20KB,下游最多 32KB,并带有 1ms 静默窗口刷新,从而削减了每帧固定的调度开销。
Creator
ToiCF
Size
<0.1 MB
Stars
907
Updated
CommitOct 11
Age
9d
Commits · 90 Days