反向代理 Telegram, 解决在国内的连接问题

很长一段时间以来,网页版 Telegram 在国内都遭到了异常严重的封锁.时至今日,已经到了挂上梯子仍不能连接的地步.因此,搭建一个 Telegram 反向代理网页客户端就显得十分必要了.


TL;DR

我自己的服务器 (位于日本) 已经部署好了 Telegram 反向代理,你可以直接使用: https://web.telegrammy.ml

2019 年 7 月 11 日更新

上述反向代理已关闭,原因见我是如何隐藏服务器 IP 地址的?一文.

当然,如果你觉得通过别人的服务器访问 Telegram 并不安全,或者只是想体会下折腾的乐趣,也可以选择自行搭建.那么,请继续阅读.

目前, web.telegram.org 网站和官方提供的 Chrome 扩展都不能连接到 Telegram 的消息服务器(即 Telegram API), 替换 hosts 或使用 Shadowsocks 后依然如此.具体的表现是, web.telegram.org 可以打开,但始终显示为 Connecting... (已登录时)或 Generating keys... (未登录时).使用 Chrome 抓包发现, 问题似乎在于发往 flora.web.telegram.org 的请求总是超时. telegram.org 的其他子域名并没有出现这种超时现象. 并且在我的网络环境下 flora.web.telegram.org 是可以 ping 通的, 解析到的是正确的 IP 地址 (149.154.164.225). 这是一种非常奇怪的现象,原因未知,我在 GitHub 提问后也没有得到一个很好的解释.至于桌面版 Telegram 则要好很多,在设置了网络代理后即可正常使用.(但就我个人而言,喜欢使用 webapp 更甚于本地应用,所以就有了这篇文章.)

在开始实际的操作前,有必要了解一下 Telegram 的架构.网页版 Telegram 由相对独立的两部分组成:前端和后端.后端部分,包含 10 个消息服务器,分别是:

149.154.175.16	pluto.web.telegram.org
149.154.175.16	pluto-1.web.telegram.org
149.154.167.25	venus.web.telegram.org
149.154.167.25	venus-1.web.telegram.org
149.154.175.115	aurora.web.telegram.org
149.154.175.115	aurora-1.web.telegram.org
149.154.167.124	vesta.web.telegram.org
149.154.167.124	vesta-1.web.telegram.org
149.154.164.225	flora.web.telegram.org
149.154.164.225	flora-1.web.telegram.org

所有的 Telegram 客户端(官方或是第三方)都需要与这 10 个 API 地址通信.前端部分,是一个开源的纯静态 webapp, 被称为 webogram. 它可以被部署到任何地方,比如 Telegram 官方提供的 https://web.telegram.org/, 比如 Telegram 官方搭建在 GitHub 上的 https://zhukov.github.io/webogram/,比如你自己的服务器.它也可以被打包成 Chrome 扩展,甚至可以在本地离线使用.

你应该可以发现,由于 Telegram 的前端与后端高度解耦合,使得对于 GFW 来说,单纯地封禁 https://web.telegram.org/ 这一个网站毫无意义——任何人,只要拥有自己的服务器,花 5 分钟时间就能又搭建一个新的 Telegram 前端出来.真正可行的是直接对那 10 个消息服务器动手.如上所述,他们也确实是这么干的.所以,对于我们来说,需要反向代理的也就是那 10 个消息服务器.

有两种反代方案:多域名和单域名.多域名方案,即:

用 pluto.web.example.com 代理 pluto.web.telegram.org
用 venus.web.example.com 代理 venus.web.telegram.org
用 aurora.web.example.com 代理 aurora.web.telegram.org
............

单域名方案,即:

用 web.example.com/pluto 代理 pluto.web.telegram.org
用 web.example.com/venus 代理 venus.web.telegram.org
用 web.example.com/aurora 代理 aurora.web.telegram.org
............

显然,当我们要代理大量 API 地址时,单域名方案更易于管理.但使用单域名方案需要服务器支持正则表达式之类的高级语法.例如在 nginx 中可以这样写:

server_name example.com;

location ~* ^/(pluto|venus|aurora|vesta|flora|pluto-1|venus-1|aurora-1|vesta-1|flora-1)/(.*)$ {
        proxy_buffering off;
        proxy_pass https://$1.web.telegram.org/$2;
    }

但我使用的却是不支持此类语法的 Caddy. (对的,我准备用 Caddy 做反代服务器,抱歉我一直没说如果你用的是其它服务器,可以跳到末尾读那几篇参考资料).虽然社区内一直有增加这个特性的呼声,但 Caddy 至今仍不支持.所以,没办法,我们只能用多域名方案.

准备好你的域名(下文以我一时脑抽想出的 telegrammy.ml 为例),把这些全部解析到你的服务器上:

TELEGRAMMY.ML
WEB.TELEGRAMMY.ML
WWW.TELEGRAMMY.ML
AURORA-1.WEB.TELEGRAMMY.ML
AURORA.WEB.TELEGRAMMY.ML
FLORA-1.WEB.TELEGRAMMY.ML
FLORA.WEB.TELEGRAMMY.ML
PLUTO-1.WEB.TELEGRAMMY.ML
PLUTO.WEB.TELEGRAMMY.ML
VENUS-1.WEB.TELEGRAMMY.ML
VENUS.WEB.TELEGRAMMY.ML
VESTA-1.WEB.TELEGRAMMY.ML
VESTA.WEB.TELEGRAMMY.ML

在你的 Caddyfile 中添加:

telegrammy.ml,
www.telegrammy.ml {
	redir https://web.telegrammy.ml{uri}
}

web.telegrammy.ml {
        root /var/www/webogram
        gzip
        log /var/www/log/web.telegrammy.ml.log
        errors /var/www/log/web.telegrammy.ml.log
        header / {
                #Strict-Transport-Security "max-age=31536000; includeSubDomains;"
                #注意!!!上面这一行用于开启 HSTS, 请在确认站点运行正常(特别是 HTTPS 运行正常)后再删掉注释符号
                X-XSS-Protection "1; mode=block"
                X-Content-Type-Options "nosniff"
                X-Frame-Options "SAMEORIGIN"
        }
}

flora.web.telegrammy.ml {
        header / {
                #Strict-Transport-Security "max-age=31536000;"
                #注意!!!上面这一行用于开启 HSTS, 请在确认站点运行正常(特别是 HTTPS 运行正常)后再删掉注释符号
                X-XSS-Protection "1; mode=block"
                X-Content-Type-Options "nosniff"
                X-Frame-Options "SAMEORIGIN"
                #这些 header 都是用于提升安全性的.下列各站点的 header 配置均与此站点相同,故省略
        }

        proxy / https://flora.web.telegram.org

}

flora-1.web.telegrammy.ml {
        header / {
                #省略
        }

        proxy / https://flora-1.web.telegram.org

}

venus.web.telegrammy.ml {
        header / {
                #省略
        }

        proxy / https://venus.web.telegram.org

}

venus-1.web.telegrammy.ml {
        header / {
                #省略
        }

        proxy / https://venus-1.web.telegram.org

}

pluto.web.telegrammy.ml {
        header / {
                #省略
        }

        proxy / https://pluto.web.telegram.org

}

pluto-1.web.telegrammy.ml {
        header / {
                #省略
        }

        proxy / https://pluto-1.web.telegram.org

}

vesta.web.telegrammy.ml {
        header / {
                #省略
        }

        proxy / https://vesta.web.telegram.org

}

vesta-1.web.telegrammy.ml {
        header / {
                #省略
        }

        proxy / https://vesta-1.web.telegram.org

}

aurora.web.telegrammy.ml {
        header / {
                #省略
        }

        proxy / https://aurora.web.telegram.org

}

aurora-1.web.telegrammy.ml {
        header / {
                #省略
        }

        proxy / https://aurora-1.web.telegram.org

}

Ok, API 地址的反向代理完成.下一步,我们需要在服务器上部署 webogram, 并把它连接的 API 地址改为我们反代的地址.

访问 https://my.telegram.org/, 申请 api_id 和 api_hash.

下载 webogram, 解压到 /var/www/webogram (这是 Caddyfile 中定义的根目录,你可以自行更改),并赋予适当权限.

修改 js/app.js ,搜索 {id:2496,hash:"8da85b0d5bfe62527e5b244c209159c3",version:"0.5.7",domains:["web.telegram.org","zhukov.github.io"]} ,将其中的 id, hash 和域名改为你自己的;搜索 https://"+l+".web.telegram.org/ ,把域名改为你自己的,如 https://"+l+".web.telegrammy.ml/ ,这样, webogram 就会连接反向代理的 API 地址了.

将 appcache 文件下载到 /var/www/webogram :

wget https://web.telegram.org/webogram.appcache

(这一步可选. appcache 这东西有人说并不好, MDN 也指出这是个被废弃的特性,不过 Telegram 仍然提供.取决于你自己吧)

完成上述操作后,我们就大功告成啦.访问你自己的域名,应该就可以免翻墙使用 Telegram 了.

然后,这是我的 Telegram: NotaStudio, 欢迎来找我吹水哦

(更新:这个链接已经失效了,但你可以用邮件和我交流!我的邮箱是 i[at]nota.moe)

(折腾完这些之后,突然发现 Telegram 桌面版好好用的样子,比网页版好用到哪里去了...我这是不是在白费力气?)

参考:
网页版 Telegram 无法连接
使用 nginx 反向代理 telegram 网页客户端 (单域名)
使用 nginx 反向代理 telegram 网页客户端 (多域名方式,较复杂已弃用)
Can I use regex in http.proxy 'from'/'to' syntax? - Help - Caddy Community
http.proxy - Caddy User Guide

以上.

14 thoughts on “反向代理 Telegram, 解决在国内的连接问题

  1. kuc says:

    我发现根据你的教程搭建的反代网站和你的telegrammy,都存在不会自动接收新信息的问题。。。最多只会显示xxx is typing....的字样,不知道你发现没有?

    • 谢谢提醒,最近没怎么用 Telegram, 这个问题我还真没发现.简单看了下,原因似乎是某些 XHR 请求返回 502 错误(控制台的错误信息似乎跟 CORS 有关).解决办法我还没找到.

      • kuc says:

        谢谢回复。。。我也在找解决方法。。。
        但是tg官方已经升级到0.7,放出的源码是0.5.7。。。不知道还会不会放新的源码了

      • kuc says:

        原来作者已经放出了代码,只是不再放在release里面了,需要直接git,那个app了么的代码就是以前的.zip里面的代码。config.js和mtproto.js需要按你之前的教程那样改。上线之后可以接收到最新的信息了,但是控制台依旧有报错。然后有点小bug,例如没有css,需要自己在官方的web.telegram.org偷出来,然后就是录音什么的用不了~~~~

        • 直接 git 拉下来的代码是未经"编译"的 js, 样式表用的是 less, (而且恐怕不带依赖,这估计是录音问题的原因), 这样的代码我想不应该作为静态网站的代码那样对待.既然 tg 官方不再释出已"编译"的可直接作为静态网站的代码,那么像 readme 里面说的那样用 node 来运行或自己用 gulp 来打包成可以作为静态网站的代码(也就是所谓的"编译")应该是更好的办法.

        • kuc says:

          按readme的操作完了还是缺少了css,还是得在官网偷下来。可能是缓存的原因,当时刚放上去录音用不了,但是清了缓存就可以正常使用了,你可以试试哦~需要修改的部分就是config.js和mtproto.js。ngnix按你提供的操作就可以了。效果很棒,和官网的一样了。

        • 在你的服务器的配置文件里(比如说 Caddy 的 Caddyfile), 加在 HTTP 报文头部里.我只对 0.5.7 版本试过这个方法,不过最新版应该也适用.

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注