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 (td web-proxy): пробрасывает WebSocket-каналы, которые открывает встроенный webview в Telegram Desktop/Android, напрямую в канал Web K (KWS) самого Telegram.
Это полноценный MTProxy-сервер или что-то другое?Это не традиционный бэкенд MTProxy/middle-proxy, который нужно запускать самому; скрипт лишь распаковывает и заново подписывает транспортную обфускацию MTProto у клиента и направляет соединение напрямую в официальный KWS WebSocket-эндпоинт Telegram.
Как его запустить?Разверните файл 'telegramwebproxy.js' как Cloudflare Worker и настройте две секретные привязки: SECRET (ключ AES-CTR из 32 hex-символов) и BOOT (токен подписи для начальной загрузки); без обеих проверка работоспособности не проходит.
Нужен ли мне свой домен или аккаунт Cloudflare?Для развёртывания нужен аккаунт Cloudflare Workers, а в README рекомендуется привязать свой домен через CNAME или использовать кастомные хостнеймы Cloudflare SaaS — так качество маршрутизации до граничных узлов Telegram будет лучше.
Заявленная производительность — это реальные замеры?Нет: заявленное ускорение (примерно от 2x и выше) прямо помечено как теоретический вывод на основе смежного микробенчмарка (GrainTCP), а не измерений самого этого репозитория.
Зачем несколько WebSocket-каналов вместо Durable Object?Durable Object однопоточный и привязывает всю сессию к одному инстансу, создавая узкое место. Здесь же каждый поток Telegram получает свой WebSocket-канал (до 128 на сессию), и каждый канал независимо держит очередь и backpressure внутри одного isolate.
Как устроена авторизация по bootstrap/сессионным токенам?Страница выдаёт одноразовый nonce и короткоживущий bootstrap-токен (2 минуты); клиент обменивает его через POST /api/v1/session на сессионный токен (5 минут), привязанный к lease конкретной сессии, который отслеживает активные каналы, а DELETE /api/v1/session отзывает его немедленно.
Зачем уходить от официальной схемы MTProxy к маршрутизации через KWS?Прямое подключение к собственному эндпоинту Web K (KWS) Telegram убирает лишний релейный хоп и необходимость держать отдельный бэкенд MTProxy/middle-proxy, сводя криптографическую работу с каждым пакетом к одной переподписи обфускации вместо полного проброса на уровне mtp.
Как он справляется с потоками мелких фреймов?Мелкие исходящие и входящие фреймы объединяются перед записью: до 20KB на батч вверх и до 32KB вниз, со сбросом по «тихому окну» в 1 мс — это снижает фиксированные накладные расходы на планирование каждого фрейма.
Creator
ToiCF
Size
<0.1 MB
Stars
925
Updated
CommitOct 11
Age
10d
Commits · 90 Days