【实用的开源工具】Matrix(Synapse + Element):搭一个自己的聊天服务器
「实用的开源工具」系列:我只收集值得用的开源项目,写清楚它能做什么、怎么部署、有哪些坑,并在文末标明出处。内容整理自官方文档,核对日期 2026-10-30,具体版本以官方为准。这篇是系列里最复杂的一篇,建议先在测试域名上走一遍,再上正式域名。
项目信息卡
| 项目 | 说明 |
|---|---|
| 名称 | Matrix:一套开放的聊天协议。服务端常用 Synapse,网页客户端常用 Element Web |
| 做什么 | 私聊、群聊、文件传输、端到端加密;不同服务器的用户可以互相联系(联邦) |
| Synapse | 服务端,AGPL-3.0,最近版本 v1.164.1(2026-10-28 发布,查询于 2026-10-30) |
| Element Web | 网页客户端,AGPL-3.0,最近版本 v1.12.33(2026-10-27 发布) |
| 仓库 | element-hq/synapse、element-hq/element-web |
| 文档 | Synapse 官方文档 |
| 依赖 | PostgreSQL(官方说明 SQLite 只适合测试)、一个域名、HTTPS 证书 |
它能做什么
- 自己的聊天服务:用户名是
@名字:你的域名,数据全在你的服务器上。 - 端到端加密:私聊和群聊都可以加密。
- 联邦:你的用户可以和其他 Matrix 服务器上的人聊天、加入对方的房间;也可以只在自己人之间用。
- 多种客户端:网页、手机、桌面都有,不止 Element 一种。
- 桥接:生态里有把 Matrix 和 Telegram、微信等连起来的桥,这篇不展开。
不适合的场景:只想要“能马上用”的人。它比 Memos 这类工具重得多,要自己维护数据库、备份、升级。如果只是团队内部聊天,先想清楚是不是真的需要。
先规划:三个域名各管什么
下面全用 example.com 举例,请换成自己的:
| 域名 | 用途 | 对应服务 |
|---|---|---|
example.com | 你的 server_name,用户 ID 里 : 后面的部分 | 你原来的网站,只需要加两个小文件 |
matrix.example.com | Synapse 真正运行的地方 | 容器,端口 8008 |
chat.example.com | Element 网页客户端 | 容器,端口 8080 |
这样做的原因:
- 用户 ID 干净:
@alice:example.com,不带matrix.。官方也建议生产环境用你的主域名做 server_name,类似邮箱写[email protected]。 - Element 和 Synapse 分开域名:Element 官方不建议两者共用域名,防止用户发来的恶意内容借同域名获得信任而造成 XSS。
- 联邦流量走 443:默认别的服务器会去连
example.com:8448。我们用.well-known委派,告诉对方改去matrix.example.com:443,这样不用对外开放 8448 端口。
最重要的一件事:
server_name一旦定下就改不了(官方原话是安装之后无法更改)。想好再动手。
第 0 步:准备
- 三个域名的 DNS 都指向服务器,并准备好证书(可以用通配符证书,或者分别签)。
- 服务器装好 Docker 和 Docker Compose、Nginx。
- 建工作目录:
mkdir -p /opt/matrix/element && cd /opt/matrix第 1 步:生成 Synapse 配置
docker run -it --rm \
-v /opt/matrix/synapse-data:/data \
-e SYNAPSE_SERVER_NAME=example.com \
-e SYNAPSE_REPORT_STATS=no \
matrixdotorg/synapse:v1.164.1 generateSYNAPSE_SERVER_NAME 和 SYNAPSE_REPORT_STATS 是必填项(后者选 yes 或 no,决定是否上报匿名统计)。命令会在 synapse-data/ 里生成 homeserver.yaml 和签名密钥。镜像标签请以 Docker Hub 上实际存在的为准,生产环境固定版本号。
第 2 步:改 homeserver.yaml
默认配置用的是 SQLite,需要改成 PostgreSQL,并让 Synapse 知道自己在反向代理后面。
数据库:把默认的 database: 段替换成:
database:
name: psycopg2
args:
user: synapse
password: 改成你的数据库密码
database: synapse
host: db
cp_min: 5
cp_max: 10监听:找到 port: 8008 那一段,加上 x_forwarded: true,让 Synapse 从代理头里读取真实访客 IP:
listeners:
- port: 8008
tls: false
type: http
x_forwarded: true
resources:
- names: [client, federation]
compress: false对外地址:
public_baseurl: "https://matrix.example.com"注意两点:官方说明容器里运行 Synapse 时不要把 bind_addresses 改成 127.0.0.1,否则收不到代理转发的请求;enable_registration 保持默认关闭,我们用命令行建账号。
第 3 步:Compose 文件
/opt/matrix/compose.yaml:
services:
synapse:
image: matrixdotorg/synapse:v1.164.1
restart: unless-stopped # Synapse 不会重试连数据库,失败要靠重启
environment:
- SYNAPSE_CONFIG_PATH=/data/homeserver.yaml
volumes:
- ./synapse-data:/data
ports:
- "127.0.0.1:8008:8008"
depends_on:
- db
db:
image: postgres:15-alpine
restart: unless-stopped
environment:
- POSTGRES_USER=synapse
- POSTGRES_PASSWORD=改成你的数据库密码
# 必须在第一次初始化时设好,见下面的“坑”
- POSTGRES_INITDB_ARGS=--encoding=UTF-8 --lc-collate=C --lc-ctype=C
volumes:
- ./pgdata:/var/lib/postgresql/data
element:
image: vectorim/element-web:latest
restart: unless-stopped
ports:
- "127.0.0.1:8080:80"
volumes:
- ./element/config.json:/app/config.json:rodb 部分来自 Synapse 仓库的示例 Compose;Element 用官方镜像,并挂载自己的 config.json(官方写法是映射到 /app/config.json)。element 的 latest 也建议改成固定版本。
Element 的配置,/opt/matrix/element/config.json:
{
"default_server_config": {
"m.homeserver": {
"base_url": "https://matrix.example.com",
"server_name": "example.com"
}
}
}启动:
cd /opt/matrix
docker compose up -d
docker compose logs -f synapse第 4 步:Nginx
matrix.example.com(Synapse):
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name matrix.example.com;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
location ~ ^(/_matrix|/_synapse/client) {
# 注意:proxy_pass 端口后面不要加任何路径(连一个 / 也不要)
proxy_pass http://127.0.0.1:8008;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
# Nginx 默认只允许 1M 的上传,要和 homeserver.yaml 的 max_upload_size(默认 50M)一致
client_max_body_size 50M;
proxy_http_version 1.1;
}
}chat.example.com(Element,必须 HTTPS):
server {
listen 443 ssl;
server_name chat.example.com;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
}
}example.com:在你原来网站的 server 块里,加两个 .well-known 小文件,放在 location / 前面:
location /.well-known/matrix/server {
return 200 '{"m.server": "matrix.example.com:443"}';
default_type application/json;
}
location /.well-known/matrix/client {
return 200 '{"m.homeserver": {"base_url": "https://matrix.example.com"}}';
default_type application/json;
add_header Access-Control-Allow-Origin *;
}server这个告诉其他服务器:联邦请求去matrix.example.com:443,不用 8448。client这个告诉客户端:输入@alice:example.com就能自动找到服务器。网页版客户端要求带跨域头,所以有Access-Control-Allow-Origin *。
改完执行:
nginx -t && systemctl reload nginx第 5 步:创建账号
cd /opt/matrix
docker compose exec synapse register_new_matrix_user http://localhost:8008 -c /data/homeserver.yaml按提示输入用户名、密码,问 Make admin 时第一个账号选 yes。然后打开 https://chat.example.com,用 @用户名:example.com 登录。
第 6 步:检查联邦
官方文档推荐用 Matrix Federation Tester 检查:输入 example.com,看委派(.well-known)和证书是否都通过。联邦要通,别的服务器上的人才能加你、你也才能加别人。
只想自己人用,可以先不管联邦,只确认登录和聊天正常。
备份
官方列出的需要备份的东西:
homeserver.yaml和其他配置文件。- 服务器签名密钥(在
synapse-data/里,和配置一起备份最简单)。 - PostgreSQL 数据库。
- 媒体文件(用户上传的图片、文件)。默认存在
synapse-data/数据目录下,具体路径以你的homeserver.yaml里的media_store_path为准。
恢复数据库时有两条官方警告:不要往已经有表的数据库里恢复;e2e_one_time_keys_json 这张表不要备份,或者恢复后清空,否则会出现消息解密失败。
踩坑清单
server_name定了就改不了。 想好再装,别用测试名字上线。- 别用 SQLite。 官方明确说只适合测试,生产环境请直接用 PostgreSQL,加入大房间时性能差距很大。
- PostgreSQL 的编码和排序规则要一次设对。 官方要求数据库用 UTF8 编码,
locale=C。Compose 里的POSTGRES_INITDB_ARGS只在第一次初始化数据目录时生效,已经初始化过的pgdata再改没用,要删掉数据目录重新初始化(所以先测试,别等有数据了才发现)。 - Synapse 不会重试连接数据库。 数据库没起来它就会失败退出,所以 Compose 里要写
restart: unless-stopped。 proxy_pass后面不能带路径。 官方强调:写成http://127.0.0.1:8008/会让 Nginx 改写网址,导致签名验证错误。反向代理不能对网址做任何规范化。- Nginx 默认只能传 1M。 要把
client_max_body_size调成和max_upload_size一致,不然发图片、文件会失败。 - Element 和 Synapse 不要共用域名。 官方安全说明里的建议,有 XSS 风险。
- Element 必须走 HTTPS。 官方明确要求,否则聊天安全没有保障。
.well-known必须放在example.com的 443 上。 官方说明.well-known文件本身是通过默认的 HTTPS 端口提供的。网站如果还没配 HTTPS,先配好。- 没配委派,别人会默认去连 8448。 要么开放并代理 8448,要么按上面配
.well-known。两个都没做,联邦就不通。 registration_shared_secret要保密。 官方说明:知道它的人,即使enable_registration关着,也能在你的服务器上注册用户,包括管理员。Docker 版文档也提醒:不再需要时,把它删掉并重启。- 容器数据目录的权限。 官方说明镜像默认用 UID/GID 991 运行,用绑定目录挂载时要保证它可写,或者用环境变量
UID、GID指定。 - 没配邮箱,就没有找回密码。 官方说明:不配置 SMTP,密码重置、邮箱验证和邮件通知都不可用。
- 语音和视频通话要另配 TURN 服务器。 官方说明可靠的通话必须配置 TURN,这篇没有覆盖。
- URL 预览默认关闭,开启要小心。 官方说明开启时必须配置 IP 黑名单,否则用户可以借你的服务器去探测内网。至少要屏蔽回环地址和内网地址段。
- 加入大型公开房间会增加资源占用。 这是我的判断,不是官方原话:联邦房间的历史和成员都要同步到你的服务器,小服务器要留足内存和磁盘。
- Docker 发布的端口会绕过 ufw 之类的防火墙。 所以示例里都绑定在
127.0.0.1。 - 升级前先备份,再读发布说明。 Synapse 更新很频繁,数据库迁移是单向的,不要无准备地直接拉最新镜像。
出处
有想法或问题?去留言板留言 →