【实用的开源工具】Matrix(Synapse + Element):搭一个自己的聊天服务器

阅读约 9 分钟
【实用的开源工具】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.comSynapse 真正运行的地方容器,端口 8008
chat.example.comElement 网页客户端容器,端口 8080

这样做的原因:

  1. 用户 ID 干净:@alice:example.com,不带 matrix.。官方也建议生产环境用你的主域名做 server_name,类似邮箱写 [email protected]。
  2. Element 和 Synapse 分开域名:Element 官方不建议两者共用域名,防止用户发来的恶意内容借同域名获得信任而造成 XSS。
  3. 联邦流量走 443:默认别的服务器会去连 example.com:8448。我们用 .well-known 委派,告诉对方改去 matrix.example.com:443,这样不用对外开放 8448 端口。

最重要的一件事:server_name 一旦定下就改不了(官方原话是安装之后无法更改)。想好再动手。

第 0 步:准备

  • 三个域名的 DNS 都指向服务器,并准备好证书(可以用通配符证书,或者分别签)。
  • 服务器装好 Docker 和 Docker Compose、Nginx。
  • 建工作目录:
bash
mkdir -p /opt/matrix/element && cd /opt/matrix

第 1 步:生成 Synapse 配置

bash
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 generate

SYNAPSE_SERVER_NAME 和 SYNAPSE_REPORT_STATS 是必填项(后者选 yes 或 no,决定是否上报匿名统计)。命令会在 synapse-data/ 里生成 homeserver.yaml 和签名密钥。镜像标签请以 Docker Hub 上实际存在的为准,生产环境固定版本号。

第 2 步:改 homeserver.yaml

默认配置用的是 SQLite,需要改成 PostgreSQL,并让 Synapse 知道自己在反向代理后面。

数据库:把默认的 database: 段替换成:

yaml
database:
  name: psycopg2
  args:
    user: synapse
    password: 改成你的数据库密码
    database: synapse
    host: db
    cp_min: 5
    cp_max: 10

监听:找到 port: 8008 那一段,加上 x_forwarded: true,让 Synapse 从代理头里读取真实访客 IP:

yaml
listeners:
  - port: 8008
    tls: false
    type: http
    x_forwarded: true
    resources:
      - names: [client, federation]
        compress: false

对外地址:

yaml
public_baseurl: "https://matrix.example.com"

注意两点:官方说明容器里运行 Synapse 时不要把 bind_addresses 改成 127.0.0.1,否则收不到代理转发的请求;enable_registration 保持默认关闭,我们用命令行建账号。

第 3 步:Compose 文件

/opt/matrix/compose.yaml:

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:ro

db 部分来自 Synapse 仓库的示例 Compose;Element 用官方镜像,并挂载自己的 config.json(官方写法是映射到 /app/config.json)。element 的 latest 也建议改成固定版本。

Element 的配置,/opt/matrix/element/config.json:

json
{
  "default_server_config": {
    "m.homeserver": {
      "base_url": "https://matrix.example.com",
      "server_name": "example.com"
    }
  }
}

启动:

bash
cd /opt/matrix
docker compose up -d
docker compose logs -f synapse

第 4 步:Nginx

matrix.example.com(Synapse):

nginx
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):

nginx
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 / 前面:

nginx
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 *。

改完执行:

bash
nginx -t && systemctl reload nginx

第 5 步:创建账号

bash
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)和证书是否都通过。联邦要通,别的服务器上的人才能加你、你也才能加别人。

只想自己人用,可以先不管联邦,只确认登录和聊天正常。

备份

官方列出的需要备份的东西:

  1. homeserver.yaml 和其他配置文件。
  2. 服务器签名密钥(在 synapse-data/ 里,和配置一起备份最简单)。
  3. PostgreSQL 数据库。
  4. 媒体文件(用户上传的图片、文件)。默认存在 synapse-data/ 数据目录下,具体路径以你的 homeserver.yaml 里的 media_store_path 为准。

恢复数据库时有两条官方警告:不要往已经有表的数据库里恢复;e2e_one_time_keys_json 这张表不要备份,或者恢复后清空,否则会出现消息解密失败。

踩坑清单

  1. server_name 定了就改不了。 想好再装,别用测试名字上线。
  2. 别用 SQLite。 官方明确说只适合测试,生产环境请直接用 PostgreSQL,加入大房间时性能差距很大。
  3. PostgreSQL 的编码和排序规则要一次设对。 官方要求数据库用 UTF8 编码,locale=C。Compose 里的 POSTGRES_INITDB_ARGS 只在第一次初始化数据目录时生效,已经初始化过的 pgdata 再改没用,要删掉数据目录重新初始化(所以先测试,别等有数据了才发现)。
  4. Synapse 不会重试连接数据库。 数据库没起来它就会失败退出,所以 Compose 里要写 restart: unless-stopped。
  5. proxy_pass 后面不能带路径。 官方强调:写成 http://127.0.0.1:8008/ 会让 Nginx 改写网址,导致签名验证错误。反向代理不能对网址做任何规范化。
  6. Nginx 默认只能传 1M。 要把 client_max_body_size 调成和 max_upload_size 一致,不然发图片、文件会失败。
  7. Element 和 Synapse 不要共用域名。 官方安全说明里的建议,有 XSS 风险。
  8. Element 必须走 HTTPS。 官方明确要求,否则聊天安全没有保障。
  9. .well-known 必须放在 example.com 的 443 上。 官方说明 .well-known 文件本身是通过默认的 HTTPS 端口提供的。网站如果还没配 HTTPS,先配好。
  10. 没配委派,别人会默认去连 8448。 要么开放并代理 8448,要么按上面配 .well-known。两个都没做,联邦就不通。
  11. registration_shared_secret 要保密。 官方说明:知道它的人,即使 enable_registration 关着,也能在你的服务器上注册用户,包括管理员。Docker 版文档也提醒:不再需要时,把它删掉并重启。
  12. 容器数据目录的权限。 官方说明镜像默认用 UID/GID 991 运行,用绑定目录挂载时要保证它可写,或者用环境变量 UID、GID 指定。
  13. 没配邮箱,就没有找回密码。 官方说明:不配置 SMTP,密码重置、邮箱验证和邮件通知都不可用。
  14. 语音和视频通话要另配 TURN 服务器。 官方说明可靠的通话必须配置 TURN,这篇没有覆盖。
  15. URL 预览默认关闭,开启要小心。 官方说明开启时必须配置 IP 黑名单,否则用户可以借你的服务器去探测内网。至少要屏蔽回环地址和内网地址段。
  16. 加入大型公开房间会增加资源占用。 这是我的判断,不是官方原话:联邦房间的历史和成员都要同步到你的服务器,小服务器要留足内存和磁盘。
  17. Docker 发布的端口会绕过 ufw 之类的防火墙。 所以示例里都绑定在 127.0.0.1。
  18. 升级前先备份,再读发布说明。 Synapse 更新很频繁,数据库迁移是单向的,不要无准备地直接拉最新镜像。

出处

想要类似的东西?网站、Telegram 机器人、运维工具,说说你的需求。
发布需求

有想法或问题?去留言板留言 →