一、背景

有时候想在不使用科学上网的环境下使用 telegram,经过研究了解,发现通过自建基于 matrix协议 的服务可以满足要求。

它可以通过插件桥接到 telegram 上,获取 telegram 的消息,这样我在外网部署 matrix 服务并桥接 telegram,之后在我手机或 PC 上直接登录 matrix 客户端,就可以直接访问 telegram 里的消息了。

matrix 协议介绍(ChatGPT)。

Matrix 协议是一种开放标准的通信协议,用于实现即时通讯和实时通信的应用程序。它旨在提供一个去中心化的网络通信框架,允许不同的即时通讯服务之间进行互操作,类似于电子邮件中的 SMTP 协议。

Matrix 协议的设计目标是建立一个开放的、互操作的通信平台,使用户能够通过不同的即时通讯应用程序进行跨平台、跨服务提供商的通信。它提供了一套标准的 API 和数据格式,用于传输消息、音频、视频和其他类型的数据。

Matrix 协议的核心概念是 " 房间 “(rooms)和 " 事件 “(events)。房间是用户可以加入的通信空间,类似于聊天室或群组,在房间中,用户可以发送消息、共享文件和进行语音/视频通话。事件是在房间中发生的操作或消息,可以是文本消息、图片、音频或其他类型的数据。

Matrix 协议的一个重要特点是去中心化。它使用了分布式的服务器架构,不依赖于任何单一的服务提供商或中央服务器。这意味着用户可以选择他们喜欢的服务器和服务提供商,而不会受到限制。这也增加了数据的安全性和可靠性。

Matrix 协议得到了广泛的应用和支持,并且有许多基于该协议开发的即时通讯应用程序和服务。其中比较知名的包括 Element、Riot.im 等。

总而言之,Matrix 协议是一个开放标准的通信协议,旨在实现去中心化、互操作性的即时通讯和实时通信。它提供了一种开放、安全和灵活的方式,使用户可以跨平台、跨服务提供商进行通信。

二、服务部署

matrix 的服务端有多个,基于稳定性考虑,这里直接使用官方稳定版的服务端 Synapse

为了简单,这里使用 docker 的方法进行部署。

2.1 生成配置文件

首先创建一个目录 matrix,用于存储 matrix 服务的配置、数据等文件。

使用以下 docker 命令生成 matrix 的配置。

1
2
3
4
5
docker run -it --rm \
    -v matrix:/data \     # 目录映射
    -e SYNAPSE_SERVER_NAME=my.matrix.host \  # 这里指定自己的域名
    -e SYNAPSE_REPORT_STATS=no \            # 是否上报使用数据
    matrixdotorg/synapse:latest generate

执行完毕后,将会在 matrix 目录下生成 homeserver.yaml 等配置,下面是一个配置示例。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
server_name: "my.matrix.host"      # 域名,改成自己的
pid_file: /data/homeserver.pid
listeners:
  - port: 8008
    tls: false
    type: http                    # 这里直接用http,外面加反代
    x_forwarded: true
    resources:
      - names: [client, federation]
        compress: false
database:
  # 数据库,默认是sqlite3,对性能有要求可以用postgres
  name: sqlite3                  
  args:
    database: "/data/homeserver.db"
  # 如果用postgres,下面是一个示例
  # database:
  #   name: psycopg2
  #   args:
  #       user: synapse_user
  #       password: 6HE8WNLAzqRQyLkhZaTF
  #       database: synapse
  #       host: 169.254.37.1
  #       cp_min: 5
  #       cp_max: 10
  #       keepalives_idle: 30
  #       keepalives_interval: 10
  #       keepalives_count: 3
            
log_config: "/data/my.matrix.host.log.config"
media_store_path: /data/media_store
registration_shared_secret: ""  # 注册共享密钥,自动会生成,拥有该密钥的任何人都可以注册普通或管理员用户
enable_registration: true       # 是否允许注册
registration_requires_token: true  # 注册是否需要token
report_stats: false
macaroon_secret_key: ""        # 自动生成,不用管
form_secret: ""                # 自动生成,不用管
signing_key_path: "/data/my.matrix.host.signing.key"  
trusted_key_servers:
  - server_name: "matrix.org"  # 信任的其他matrix服务

# vim:ft=yaml

对其中几个参数进行说明。

  • server_name, 域名名称。
  • database,数据库。我自己使用的是 sqlite3,两三个人用还行。如果想稳定长期使用,建议还是用 postgres。自己有尝试用 postgres,但要求 postgres 版本在 15.0 以上,自己服务器上的还是 9.x,升级比较麻烦,懒得搞了。
  • enable_registration,是否允许注册。因为要给其他人用,所以就开放注册了,自己手动创建账户对他人不是很友好。
  • registration_requires_token,注册时是否需要 token。为了避免机器人等工具恶意注册,这里要求在注册时需要填入 token 值,只有填入正确的值才能注册成功。后面会详细说明。

2.2 启动服务

调整完配置后,就可以启动服务了,使用以下命令启动。

1
2
3
4
docker run -d --name synapse \
    -v matrix:/data \
    -p 8008:8008 \
    matrixdotorg/synapse:latest

启动完毕后,可以使用 docker logs synapse 命令查看服务的执行日志,是否存在异常。若不存在异常,那么本地访问 http://localhost:8008 即可看到有响应。

2.3 配置反向代理

为了安全性,在访问 matrix 服务端的时候,一定要使用 https,我个人是通过云服务商申请的免费证书,然后使用的 nginx 作为反向代理访问的。

为了降低使用证书的成本,可以使用 caddy 作为反代服务器,能够自动申请证书走 https。

一个参考的配置如下。

1
2
3
4
my.matrix.host {
    tls <email>
    reverse_proxy localhost:8008
}

三、使用

3.1 创建用户

这里首先我们需要创建一个属于自己的用户,执行以下命令进行查看创建用户命令的帮助信息。

1
docker exec -it synapse register_new_matrix_user http://localhost:8008 -c /data/homeserver.yaml --help

创建一个管理员用户。

1
2
# 执行这条命令后,将会提示输入用户名,密码等
docker exec -it synapse register_new_matrix_user http://localhost:8008 -c /data/homeserver.yaml -a

在创建完管理员用户后,我们就可以直接使用这个账户登录了。

3.2 用户注册

首先要保证 homeserver.yaml 配置中开启了这两个选项。

1
2
enable_registration: true       # 是否允许注册
registration_requires_token: true  # 注册是否需要token

之后我们需要生成一个 token,以便其他用户注册时作为校验。synapse 服务端提供了一个 admin api 用来生成 token,但实际使用上略微麻烦。经过查找发现已经有人将 admin api 封装成了页面管理端 synapse-admin

这个管理端只是一个前端,其已经部署了一个到 GitHub Pages 上,我们在填入我们的管理员用户名、密码以及我们服务的地址后就可以直接使用了。

|300

在 Registration tokens 部分,我们可以创建一个新的 token。

|800

这里对创建 token 的几个参数进行说明。

  • Token,这里填入我们想创建的 token 内容,允许为空。
  • Length,在 Token 字段为空的情况下,需要填入 Length,会自动生成一个指定长度的随机 token 值。
  • Uses allowed,允许 token 使用多少次,填 null(不填)则是无限次。
  • Expiry time,token 的过期时间,填 null(不填)则是没有过期时间。 |300

创建好 token 后,把这个 token 给到你的朋友,让他们注册时填入即可。

3.3 客户端登录

基于 matrix 协议的 客户端 有多个,这里最为常用的是 element 等,其他客户端见官网说明。

当用户第一次注册并登录后,客户端会提示备份密钥。这里非常建议将密钥导出并备份下来。

基于 matrix 协议的通信是端对端加密的,即除了你和对方外,整个链路上的所有人都无法看到你们交流的消息。要解密消息便需要这个密钥,如果这个密钥丢失,那么新登录的客户端将无法解密历史的所有消息数据。同样,如果这个密钥泄露,掌握服务器的人也可以通过这个密钥解密你的所有消息。

登录 element 客户端后,通过以下方式生成密钥。

四、桥接应用

基于 matrix 协议的工具允许与其他聊天应用进行桥接,实现互联。比如可以在 matrix 客户端中与 telegram 中的用户、群组聊天。而这也正是我的目的。

4.1 telegram 桥接

我们依旧使用 docker 的方式来部署桥接服务。

首先我们在 matrix 目录下创建 bridges/telegram 目录,之后执行以下命令生成配置。

1
docker run --rm -v matrix/bridges/telegram:/data:z dock.mau.dev/mautrix/telegram:latest

执行完毕后,将会在 matrix/bridges/telegram 目录下生成 config.yaml 配置文件,该配置文件内容较多,这里只列出要修改的部分。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
homeserver:
    # synapse的地址,bridges可以通过这个地址连接到synapse
    address: https://my.matrix.host
    # 域名
    domain: my.matrix.host

appservice:
    # 这个桥接服务的地址,假设这个桥接容器名是 matrixtelegram,那么地址如下
    # 注意,这个容器名中间不能要下划线等特殊字符,测试时加了个下划线会有问题
    address: http://matrixtelegram:29317
    # 数据库这里依旧使用了sqlite
    # postgres这样配置:postgres://username:password@hostname/dbname
    databaes: sqlite:/data/matrix-telegrm.db

permissions:
	# 所有用户只能通过中继机器人使用该桥接服务,无法使用命令
	'*': relaybot
	# public.example.com服务上的用户在relaybot的基础上可以使用命令
	public.example.com: user
	# my.matrix.host服务上的用户拥有该桥接的所有权限,
	my.matrix.host: full
	# 该用户拥有管理员权限,除了所有权限外还可以使用一些管理命令
	'@admin: my.matrix.host': admin

telegram:
    # 在 https://my.telegram.org/apps 上申请API key
    api_id: <id>
    api_hash: <hash>

已经在注释中对各个字段进行了说明,基于实际的使用情况进行修改。

这里注意一点,telegram 的 API KEY 在申请的时候可能报错 ERROR,这种情况下可能需要换个代理进行申请。

在修改完毕配置后,我们再次执行以下命令,用来生成 registration.yaml 配置。

1
docker run --rm -v matrix/bridges/telegram:/data:z dock.mau.dev/mautrix/telegram:latest

生成 registration.yaml 配置后,修改 synapse 的 homeserver.yaml 配置,在尾部增加以下部分。

1
2
3
app_service_config_files:
  # 注意这个是容器中 registration.yaml 配置的路径
  - /data/bridges/telegram/registration.yaml

之后,使用以下命令创建一个虚拟的网络 matrix

1
docker network create matrix

将之前的 synapse 容器绑定在 matrix 网络上。

1
docker network connect matrix synapse

接下来,创建 telegram 桥接容器。

1
docker run --restart unless-stopped --name matrixtelegram -v matrix/bridges/telegram:/data:z dock.mau.dev/mautrix/telegram:latest

在创建桥接应用的时候,我们需要通过 --name 参数指定该容器的名字为 matrixtelegram,与我们之前的配置相对应。

创建完容器后,使用 docker logs matrixtelegram 命令查看下是否有异常,若无异常。重新启动 synapse 容器。

1
docker restart synapse

之后在 element 客户端中,向 @telegrambot:my.matrix.host 发起聊天,输出 login 命令登录自己的 telegram 账户,之后所有的消息就会同步到 matrix 中了。

这里略蛋疼的是,在我成功同步后,很快我的 telegram 账户便被封禁了😭。在 issue 878 中提到,使用虚拟手机注册的账户就容易被封禁,而我账户正是使用 Google Voice 账户注册的,已经在申诉的路上了,希望可以将账号还给我。

五、参考资料

  1. synapse docker镜像说明
  2. synapse 配置说明
  3. synapse admin API接口说明
  4. Registration Tokens说明
  5. telegram bridge安装说明
  6. NerChat的安全密钥说明
  7. 自建聊天服务器、机器人与多平台桥接