Skip to main content

Matrix: 通讯协议的服务端与客户端

· 10 min read
Mo
Software Engineer

Matrix是一个开放、去中心化的实时通讯协议,旨在提供安全、去中心化的即时通讯和协作解决方案。它允许用户通过分布式网络进行消息传递和实时通信。

服务端组件

  1. Homeserver
  2. 身份服务器
  3. 媒体存储服务
  4. 应用服务

客户端功能

  1. 消息收发
  2. 用户认证
  3. 房间管理
  4. 端到端加密

通讯协议

  1. HTTP传输层
  2. WebSocket实时通道
  3. JSON数据格式
  4. 安全信道建立

安全机制

  1. 公钥加密
  2. 身份验证令牌
  3. 会话管理
  4. 访问控制

技术架构

  1. 分布式网络
  2. 去中心化设计
  3. 联邦协议
  4. 状态同步机制

性能优化

  1. 缓存策略
  2. 消息压缩
  3. 异步处理
  4. 负载均衡

准备工作

  1. 一台 x86/amd64 架构的 Linux 服务器

    • 性能要求:基本无性能要求,可用内存建议在 200M 以上。
  2. 安装 Docker

    curl -fsSL https://get.docker.com -o get-docker.sh
    sudo sh ./get-docker.sh
    • 说明:若未安装可使用上述命令安装。
  3. 一个域名

    • DNS 提供商:文中使用 Cloudflare,其他提供商也可。
  4. 一个邮箱

    • 用途:可使用 SMTP,用于设置发信,自建邮局/Outlook 等均可。
  5. 一个 Cloudflare 账户


搭建过程

1. 使用 Docker Compose 搭建 Synapse

  • 创建数据存储文件夹:在该文件夹下创建 docker-compose.yml,内容如下:
version: "3.3"

services:
synapse:
image: "matrixdotorg/synapse:latest"
container_name: "matrix_synapse"
restart: unless-stopped
dns:
- 8.8.8.8
- 1.1.1.1
healthcheck:
test: ["CMD", "curl", "-f", "https://chat.xxxx.de"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
ports:
- '9090:80'
volumes:
- "./data:/data"
environment:
VIRTUAL_HOST: "chat.xxxx.de"
VIRTUAL_PORT: "80"
LETSENCRYPT_HOST: "chat.内部使用.de"
SYNAPSE_SERVER_NAME: "chat.xxxxxx.de"
SYNAPSE_REPORT_STATS: "no"
networks:
- matrix_net

networks:
matrix_net:
driver: bridge
driver_opts:
com.docker.network.driver.mtu: 1450
ipam:
driver: default
config:
- subnet: 172.200.0.0/16
gateway: 172.200.0.1

  • 生成配置文件:使用如下命令在 ./data 中生成配置文件:
docker run -it --rm -v ./data/:/data/ -e SYNAPSE_SERVER_NAME=你的域名 -e SYNAPSE_REPORT_STATS=yes/no matrixdotorg/synapse:latest generate
  • 修改生成的配置文件:生成成功后,./data 中会出现 homeserver.yaml,将其修改,参照以下模板:
# Configuration file for Synapse.
#
# 这是一个 YAML 文件:请参阅 [1] 以获取快速介绍。注意缩进很重要:
# 列表或字典的所有元素应具有相同的缩进。
#
# [1] https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html
#
# 有关如何配置 Synapse 的更多信息,包括每个选项的完整说明,请访问:
# https://element-hq.github.io/synapse/latest/usage/configuration/config_documentation.html

server_name: "你的域名" # 服务器名称
pid_file: /data/homeserver.pid # PID 文件路径
listeners:
- port: 你的端口 # 监听端口
tls: false # 是否使用 TLS
type: http # 监听类型
x_forwarded: true # 启用 X-Forwarded-For
resources:
- names: [client, federation] # 资源名称
compress: false # 是否压缩

database: # 数据库配置
name: sqlite3 # 使用 SQLite 数据库
args:
database: /data/homeserver.db # 数据库文件路径

log_config: "/data/你的域名.log.config" # 日志配置文件路径
media_store_path: /data/media_store # 媒体存储路径
registration_shared_secret: "保留生成的 secret 即可" # 注册共享密钥
report_stats: false # 是否报告统计数据
macaroon_secret_key: "保留生成的 secret 即可" # Macaroon 密钥
form_secret: "保留生成的 secret 即可" # 表单密钥
signing_key_path: "/data/你的域名.signing.key" # 签名密钥路径
trusted_key_servers:
- server_name: "matrix.org" # 信任的密钥服务器

enable_registration: True # 是否启用注册
registrations_require_3pid: # 使用邮箱注册
- email
suppress_key_server_warning: True # 抑制密钥服务器警告
public_baseurl: https://你的域名 # 公共基础 URL
serve_server_wellknown: true # 启用 Well-Known 服务
block_non_admin_invites: false # 阻止非管理员邀请
allow_guest_access: false # 是否允许访客访问
email: # 邮件配置
smtp_host: 你的邮件服务器 # SMTP 服务器地址
smtp_port: 你的邮件服务器端口 # SMTP 服务器端口
smtp_user: "你的SMTP账户" # SMTP 用户名
smtp_pass: "你的SMTP密码" # SMTP 密码
enable_tls: true # 是否启用 TLS
require_transport_security: true # 是否要求传输安全
notif_from: "Matrix Notifications <notifications@yesterday.de>" # 验证邮件提示语
client_base_url: "https://你的element域名" # 客户端基础 URL
validation_token_lifetime: 15m # 验证邮件有效时长
invite_client_location: https://你的element域名 # 邀请客户端位置
subjects: # 提示消息主题
message_from_person_in_room: "%(person)s 在 %(room)s 聊天室中给你发送了一条消息"
message_from_person: "%(person)s 给你发送了一条消息"
messages_from_person: "%(person)s 给你发送了多条消息"
messages_in_room: "你有一条来自 %(room)s 聊天室的消息"
messages_in_room_and_others: "你有一些来自 %(room)s 聊天室和其他人的消息"
messages_from_person_and_others: "[%(app)s] 你有一些来自 %(person)s 和其他人的消息"
invite_from_person_to_room: "%(person)s 邀请你加入 %(room)s 聊天室"
invite_from_person: "%(person)s 邀请你注册<>"
password_reset: "【】密码重置"
email_validation: "【】验证您的电子邮件"
# vim:ft=yaml

  • 样例

# Configuration file for Synapse.
#
# This is a YAML file: see [1] for a quick introduction. Note in particular
# that *indentation is important*: all the elements of a list or dictionary
# should have the same indentation.
#
# [1] https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html
#
# For more information on how to configure Synapse, including a complete accounting of
# each option, go to docs/usage/configuration/config_documentation.md or
# https://element-hq.github.io/synapse/latest/usage/configuration/config_documentation.html
server_name: "chat.xxxx.de"
pid_file: /data/homeserver.pid
listeners:
- port: 80
tls: false
type: http
x_forwarded: true
resources:
- names: [client, federation]
compress: false
database:
name: sqlite3
args:
database: /data/homeserver.db
log_config: "/data/chat.xxxx.log.config"
media_store_path: /data/media_store
registration_shared_secret: "d6Ht+WZGxD8+Bu9NL3m::k~1xcixg_Qe5-"
report_stats: false
macaroon_secret_key: "2yfYf5iQlX2bjP1AGTzZG-Bdyh8tfaVZ8mS6"
form_secret: "uuDAscAd6qeY7sJzDI*4,SE2SXqi89W:wTZh*E"
signing_key_path: "/data/chat.xxxx.de.signing.key"
trusted_key_servers:
- server_name: "matrix.org"

enable_registration: True #若是私人服务器设置为false可关闭注册
registration_requires_token: true #使用token注册
- email
suppress_key_server_warning: True
public_baseurl: https://chat.xxxx.de
serve_server_wellknown: true
block_non_admin_invites: false
allow_guest_access: false
email:
smtp_host: smtp.larksuite.com #无需引号
smtp_port: 587 #无需引号
smtp_user: "no-reply@xxxx.de"
smtp_pass: "ZP56dOgiT"
force_tls: true
require_transport_security: true
enable_tls: true
notif_from: "Your Friendly %(app)s homeserver <no-reply@xxxx.de>"
app_name: my_branded_matrix_server
enable_notifs: true
notif_for_new_users: false
client_base_url: "https://xxxx.xxxx.de"
validation_token_lifetime: 15m
invite_client_location: https://app.element.io

subjects:
message_from_person_in_room: "[%(app)s] You have a message on %(app)s from %(person)s in the %(room)s room..."
message_from_person: "[%(app)s] You have a message on %(app)s from %(person)s..."
messages_from_person: "[%(app)s] You have messages on %(app)s from %(person)s..."
messages_in_room: "[%(app)s] You have messages on %(app)s in the %(room)s room..."
messages_in_room_and_others: "[%(app)s] You have messages on %(app)s in the %(room)s room and others..."
messages_from_person_and_others: "[%(app)s] You have messages on %(app)s from %(person)s and others..."
invite_from_person_to_room: "[%(app)s] %(person)s has invited you to join the %(room)s room on %(app)s..."
invite_from_person: "[%(app)s] %(person)s has invited you to chat on %(app)s..."
password_reset: "[%(server_name)s] Password reset"
email_validation: "[%(server_name)s] Validate your email"
# vim:ft=yaml

  • 设置文件夹权限:使用以下命令设置 data 文件夹权限:
chmod -R +777 ./data
  • 启动服务器:在含有 docker-compose.yml 的目录下使用以下命令启动服务器:
docker compose up -d
  • 验证搭建正确性:若将服务器该端口映射到公网,访问 公网IP+端口,应出现包含 "It works! Synapse is running" 的界面,证明搭建正确。

2. 使用 Nginx Proxy Manager 进行反向代理

  • 打开 Nginx Proxy Manager,并添加 Proxy Host。

    • 此处使用的域名是前文中 "你的域名"。
    • IP 与端口则是前文中 Docker 容器映射到的 IP 与端口。
    • 回源协议选择 HTTP,开启 TLS(如果使用 Cloudflare CDN 也可不开启 TLS)。
  • 将域名解析至服务器公网 IP,若访问 https://你的域名 出现与上文一样的 "It works! Synapse is running" 的界面,证明搭建成功。


3. 接入 Cloudflare CDN(可选)

  • 由于 Cloudflare CDN 会自行提供边缘 TLS 证书,若要接入 Cloudflare CDN,前文配置 Nginx Proxy Manager 时可不使用 TLS,或使用 Cloudflare 提供的 15 年有效期的源服务器证书。

  • 另外一种方法是不使用 Nginx Proxy Manager,而直接使用 Origin Rules 将该域名解析至指定端口,但不推荐此种方式,因为 Cloudflare 免费计划中每个域名只有 10 条 Origin Rules,且使用此种方式需在公网上暴露端口。


4. 搭建 Synapse 时的一些注意事项

  1. 开启 TLS 十分重要

    • Matrix 协议的加密与 TLS 有着密不可分的关系,若不开启 TLS 直接使用 HTTP 搭建 Home Server,在使用过程中会发现无法生成加密秘钥等问题。
  2. 接入 Cloudflare CDN 后的上传文件限制

    • 在接入 Cloudflare CDN 后,由于免费版的限制,最大文件上传大小为 100MB,否则会返回 Error 413。
  3. 文件存储

    • 文件会全部存储在搭建用服务器上,所以尽量使用硬盘较大的服务器作为 Home Server。

5. 使用 Cloudflare Pages 搭建 Element 客户端

由于 Element 客户端为纯前端页面,可以使用 Cloudflare Pages 进行搭建,而不必浪费服务器资源。以下是搭建的步骤:

  1. 获取代码

  2. 修改配置

    • 找到 config.simple.json 文件, 修改为 config.json。
    • 修改 HomeServer 为你自己的 Home Server 地址。
         "m.homeserver": {
    "base_url": "https://xxx.xxxxx.de",
    "server_name": "xxx.xxxxx.de"
    },
  3. 部署到 Cloudflare Pages

    • 登录你的 Cloudflare 账户。

    • 创建一个新的 Pages 项目,选择刚刚 fork 的 Element 项目名称。

    • 在项目设置中,填写以下信息:

      • Build command:

        yarn install --ignore-engines && yarn build
      • Build output directory:

        webapp
  4. 定义变量和密钥

    • 在项目设置中,定义以下变量:

      TypeNameValue
      PlaintextNODE_VERSION20
      PlaintextNPM_VERSION10
      PlaintextYARN_VERSION1.22.22
  5. 域名解析

    • 将你自己的客户端域名解析至 Cloudflare Pages 上,作为你在前文中提到的 "你的 element 域名"。

6. 选择 Matrix 客户端

在 Matrix 上选择自己喜欢的客户端,可以访问以下链接查看可用的客户端:

Matrix 客户端生态系统

7. 使用命令行创建账户

如果您在注册账户时遇到问题,可以选择使用命令行创建账户。请使用以下命令:

docker exec -it matrix_synapse register_new_matrix_user -c /data/homeserver.yaml http://172.18.0.2:80

参数说明

  • -c /data/homeserver.yaml:指定 Synapse 配置文件的路径。
  • http://172.18.0.2:80:指定 Synapse 服务器的 URL(请根据实际情况修改 IP 地址)。

使用此命令后,系统会提示您输入新用户的用户名和密码。确保记录下这些信息以便日后使用。

8. 文档

Matrix Admin Token API

Matrix Configuration Doc