ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

办公场景自托管聊天平台:Synapse部署与运维实战

办公场景自托管聊天平台:Synapse部署与运维实战

1. 为什么在办公场景里,我更愿意用 Synapse 而不是临时拉个群

前段时间帮团队整理内部通讯方案的时候,我决定把 Matrix 协议的服务端 Synapse 装到一台 Ubuntu 服务器上,做一套只跑在本地网络里的办公平台。选这套东西的原因很直接:它自带端到端加密、房间权限、历史消息同步,而且服务端、客户端都是开源软件,数据完全落在自己手里。文章面向的是准备在自己团队里搭内部聊天的同学,不一定有很深的运维基础,但至少会用 Linux 命令行,能照着复制命令、改几行配置。

在正式动手之前,我想先把方案选型说清楚。Synapse 不是那种装完就能自动弹窗的“局域网聊天工具”,而是一个需要认真对待的通讯服务器。它负责账号验证、消息路由、历史记录存储;实际聊天的图形界面通常由 Element 来做。两者组成一套完整的自托管消息系统。你可以把它理解成一个开源的内部 IM 后端,所有人在电脑、手机上看到的会话、房间、文件,都通过同一个 Synapse 服务端同步交换。

有人会问:公司现成的云通讯软件不也挺好吗?对,小团队用着确实省事,但有两个隐性代价。一是数据在别人服务器上,办公文件、聊天记录、项目讨论里的敏感信息,本质上不在你控制范围内;二是平台的开放规则、账号体系、踢人权限、消息保留策略,都是别人定好的,你想做内部隔离、只给项目组开独立空间,反而要迁就产品设计。Synapse 的特点是协议开放、服务端可控、房间权限精细。你今天搭好,明天想接机器人、接企业微信风格的 Webhook、甚至把聊天记录导出做审计,都有官方接口和社区方案。

还有一点很关键:Matrix 是一套协议,不是某个公司垄断的产品。Synapse 只是其中最常见的服务端实现之一。也就是说,哪天你嫌 Synapse 太重,可以换其他兼容实现,客户端基本不用换。这种“协议层不被锁定”的特性,对长期使用的办公平台来说比什么都重要。我见过不少团队在某个云 IM 里积攒了大量消息记录,后来因为收费政策调整想迁走,结果发现根本导不出来,只能忍气吞声继续用。开源协议加自托管,至少让你永远保留“数据可以打包带走”的自由。

1.1 一套本地办公通讯系统要满足什么

我列了一下办公场景对聊天工具的核心诉求,拿这套标准去比 Matrix,你就知道它为什么值得投入精力。第一是账号可控——员工离职能把账号直接停用,聊天记录能按策略保留或清理。第二是历史消息可查——新同事加入项目组,能看到之前的讨论内容,不用反复问“之前那个决定是怎么做的”。第三是权限分级——不同项目之间互相隔离,外部访客只能看到特定房间。第四是消息安全——尤其是法务、财务、人事这类部门,端到端加密不是可选项,而是刚需。

这四条 Synapse 都能满足,但需要注意,它不是开箱即用。默认配置偏保守,很多功能需要管理员手动开启。比如端到端加密,服务器默认支持协议,但客户端之间要主动启用;再比如“只看指定房间”的访客模式,需要改配置才能开放。这正是我写这篇文章的原因:把部署过程中会踩的配置坑、命名坑、权限坑提前帮你趟平。

1.2 核心概念:server_name、房间、端到端加密

上手之前,三个概念必须理解,否则配置时很容易一头雾水。

第一个是server_name。它相当于这台服务器的“身份证号”,所有用户 ID 都由它组成,比如@chen:matrix.local。注意,它不是访问地址。你通过192.168.1.20:8008访问服务器没关系,但用户 ID 后缀依然会是matrix.local。这个设计很多新手第一次搞不明白,我后面会专门展开。

第二个是“房间”。Matrix 里所有聊天都在房间中进行,每个房间有独立的 ID 和访问控制策略。你可以把房间理解为“带权限的微信群”:公开房间任何人可见,私有房间只有成员能进,还能设置禁言、踢人、指定管理员。办公场景下,我会按“流程组”“研发小组”“管理团队”分别建房间,每个房间单独拉人。

第三个是端到端加密。Matrix 默认的加密协议,理论上服务器即使被入侵也拿不到消息正文,只能看到元数据。这个特性对办公场景很友好,但配套要解决“密钥备份”问题,不然用户换手机后可能看不到历史加密消息。这个后面讲到客户端配置时再细说。

2. 部署前的三个关键判断:版本、拓扑、命名

每次我给别人讲自托管服务,都提醒先别急着敲命令。先花十分钟想清楚:装在什么系统、怎么跑、叫什么名字。这三个决定直接决定后期维护成本。出问题是小事,最怕的是上线两周后发现架构选错,再迁移数据。

2.1 Ubuntu 版本与硬件底线

我建议用 Ubuntu 20.04 LTS 或 22.04 LTS,24.04 LTS 也可以,但 20.04 和 22.04 的资料最多,遇到问题最容易搜到答案。服务器配置方面,单纯跑 Synapse 做内部聊天,4 核 4G 内存就非常宽裕。如果团队在 30 人以内,2G 内存也能跑,但我不建议再低了。因为 Synapse 是 Python 写的,启动时吃内存比较猛,日常运行基本保持在 1GB 到 1.5GB 左右,加上系统本身的开销,2G 内存会显得紧巴巴。

硬盘反而是更要关注的。聊天记录、图片、语音消息、文件分享会持续占用空间,建议给 Synapse 单独挂一块至少 100GB 的数据盘,并把 Docker 数据目录迁移到这块盘上。别跟系统盘挤在一起,否则哪天聊天文件把根目录塞满,整台服务器都会出问题。磁盘类型方面,普通 SATA SSD 就够了,不一定要 NVMe,因为消息读写的压力远没有数据库那种高频随机读写夸张。

2.2 域名方案:局域网内怎么解决 server_name

server_name的取名有个原则:在你组织的内部环境中唯一、稳定、好记。常见做法是直接用公司内部域名,比如matrix.company.local,或者简化为matrix.local。如果你没有内部 DNS 服务器,也不打算给客户端配 hosts 文件,可以用 IP 吗?技术上演戏,但我不推荐。原因是你给用户注册账号之后,用户 ID 就是@chen:192.168.1.20,以后换服务器 IP,账号就全乱了。最好还是固定一个内部域名,跟具体 IP 解耦。

本地网络版有个好处是:不需要考虑公网 DNS 解析,不需要跟公共的 Matrix 服务器做联邦。所以server_name随便起,只要团队内部认账就行。但如果你以后想跟其他单位的 Matrix 服务器互联,那server_name必须是对外可解析的真实域名。我在办公场景默认先不考虑联邦,把系统做成一个封闭的、只有内网能访问的独立聊天平台。这样最安全,也最简单。

实际操作中,我会在局域网内的一台设备上写 hosts 解析,比如 Windows 电脑把C:\Windows\System32\drivers\etc\hosts里加一行192.168.1.20 matrix.local,手机端也同样处理。如果公司本来就有内部 DNS,直接在 DNS 上加一条 A 记录即可,所有客户端都不用动。这一步千万别省,后面客户端连接的时候你就知道有多省事。

2.3 Docker Compose 还是裸装 Python

Synapse 官方给了两种主流部署方式:直接用 Python 安装,或者用 Docker。我个人的判断是:除非你特别熟悉 Python 虚拟环境和依赖管理,否则优先用 Docker Compose。原因很简单,Synapse 的依赖很多,直接装在系统里容易把 Python 环境搞脏,以后升级还可能踩依赖冲突的坑。用 Docker 把 Synapse 和系统隔离,数据放在宿主机目录里,升级就是拉新镜像、重启容器,干净利落。

Docker 还有一个好处:未来如果想加 PostgreSQL、Redis、Nginx 反向代理,都可以通过 Compose 文件一起管理,不用再另外维护一套安装流程。办公平台最难的不是第一次装好,而是三个月后做安全升级、加组件时还能保持环境可控。Compose 让整套服务变成“代码即配置”,改一行文件、执行一条命令,服务就变了,这对小型团队的运维来说非常友好。

3. 从零开始:在 Ubuntu 上部署 Synapse

现在进入正题。我按“目录准备 → 生成配置 → 修改配置 → 启动服务 → 创建管理员”这条线走。整个过程我用的是/srv/matrix作为数据目录,你可以按自己习惯换,但后续命令里的路径也要一起换。

3.1 通过 Docker Compose 生成初始配置

先安装 Docker 和 Compose 插件:

sudo apt update sudo apt install -y docker.io docker-compose-v2 sudo systemctl enable --now docker

然后创建数据目录并生成初始配置:

sudo mkdir -p /srv/matrix/data cd /srv/matrix sudo docker run --rm \ -e SYNAPSE_SERVER_NAME=matrix.local \ -e SYNAPSE_REPORT_STATS=no \ -e SYNAPSE_NO_TLS=1 \ -v /srv/matrix/data:/data \ matrixdotorg/synapse:latest generate

这条命令会生成一个标准的 Synapse 配置目录。解释一下几个参数:SYNAPSE_SERVER_NAME就是前面说的用户 ID 后缀,我用的matrix.local,你改成自己的内部域名;SYNAPSE_NO_TLS=1表示不在 Synapse 内部启用 TLS 证书。本地网络内部用 HTTP 即可,如果要挂 HTTPS,后面再在 Nginx 层处理,不要把 TLS 堆在 Synapse 里,避免配置复杂化。

生成之后,/srv/matrix/data下会出现homeserver.yaml文件和签名密钥文件。签名密钥很重要,千万别弄丢,它相当于这台 Synapse 服务器的印章,以后客户端验证服务器身份就靠它。备份数据时一定要把这个文件一起备份。

接着写一个 Compose 文件:

services: synapse: image: matrixdotorg/synapse:latest container_name: office-matrix restart: unless-stopped ports: - "8008:8008" volumes: - ./data:/data

保存为/srv/matrix/docker-compose.yml,然后执行:

cd /srv/matrix sudo docker compose up -d sudo docker compose ps

看到容器状态为 running,就说明 Synapse 已经启动,监听在 8008 端口。如果启动失败,docker compose logs是排第一的排查命令,大部分问题是配置文件路径不对、权限不足或者端口被占用。

3.2 修改 homeserver.yaml:本地办公版的关键参数

生成出来的homeserver.yaml能直接跑,但离“办公可用”还差几处关键配置。我建议打开文件,重点检查以下内容。

第一,public_baseurl。这一项是给客户端生成链接用的。如果你让用户通过http://matrix.local:8008访问,就写:

public_baseurl: "http://matrix.local:8008/"

如果直接用 IP 访问,也可以写http://192.168.1.20:8008/。但前面说过,尽量用域名,因为用户 ID 后缀是固定的,不能随意改。

第二,注册限制。办公平台一般不希望任何人跑到登录页注册一个账号进来。默认配置里enable_registration通常是关闭的,这正合适。我会保持关闭,然后用管理员手动创建账号,或者临时开启注册再关闭。如果团队超过几十人,每次手动建账号不现实,可以在内网环境下暂时打开注册,但一定要加上registration_shared_secret,防止外部扫描到端口后随便注册。

第三,联邦功能。本地网络版不需要对外通信,建议把联邦白名单设为空:

federation: domain_whitelist: []

这样 Synapse 不会主动连接外部 Matrix 服务器,别人也无法通过联邦把消息投递进来。如果你未来有与其他单位互联的需求,再去掉这个限制,并把server_name换成公开域名即可。

第四,上传限制。办公场景里经常有人发大文件、录屏,默认的 10MB 限制会让人抓狂。改成 50MB 或 100MB 都比较合理:

max_upload_size: 100M

需要注意,这只是 Synapse 侧的配置,客户端 App 本身也可能有自己的上传限制。Element 桌面端一般没有,手机端看版本。

3.3 创建管理员账号并验证服务

修改完配置后重启容器:

cd /srv/matrix sudo docker compose restart

等几秒,然后用客户端或命令行检查 8008 端口是否正常响应:

curl -I http://127.0.0.1:8008/_matrix/client/versions

能返回 HTTP 200 就说明服务活着。接着创建管理员账号:

sudo docker exec -it office-matrix \ register_new_matrix_user \ -u admin \ -p 你的强密码 \ -c /data/homeserver.yaml \ http://127.0.0.1:8008

有些版本的命令行工具支持-a参数直接标记管理员,如果不支持,就需要去数据库里调整用户的 admin 字段。初次使用建议直接建一个带管理员身份的高权限账号,接下来在管理后台建房间、封禁用户都方便。

我踩过一个小坑:建完账号后马上用 Element 登录,结果提示账号不存在。后来发现是容器内时区或数据库初始化还没完成,稍微等十几秒再试就好了。如果你是刚启动完立刻注册,遇到登录失败不要慌,等容器日志稳定后重试。

4. 客户端登录与办公房间配置

服务端跑起来只是第一步。真正让团队用起来,还要解决客户端访问和房间体系设计。这部分我按照“怎么让同事连上来”和“怎么组织房间权限”两条线来讲。

4.1 Element Web 与桌面端接入

最省事的客户端方案是让同事安装 Element 桌面版,登录页选择“自定义服务器”,填入http://matrix.local:8008。手机端同样可以填自定义服务器地址。前提是手机能访问到这个内部域名或 IP。办公网络一般没问题,但要注意 Wi-Fi 和有线网如果不是同一 VLAN,可能需要网络同事开放相应策略。

Element Web 我有一个经验:不建议单独再搭一套 Web 托管,桌面端和手机端已经覆盖绝大多数场景。除非你团队里有临时访客,不方便装客户端,才拿一台内网 Nginx 托管 Element Web 静态页面。如果只是自己测试,直接用桌面端就好,别把部署复杂度浪费在 Web 上。

登录时如果服务器地址填的是http://matrix.local:8008,Element 会根据server_name自动拼出账号格式@你:matrix.local。这里再次体现 hosts 解析的价值。如果你没配 hosts,而是用 IP 登录,虽然也能登录,但用户 ID 会变成@你:192.168.1.20,难受。

4.2 房间权限:按项目组隔离,给访客开局部可见

Matrix 权限体系的核心是“房间状态事件”。你可以把每个房间想象成一个小型组织:创建者是最高权限,可以改房间属性、踢人、设管理员;管理员可以管理成员;普通成员只能发消息和上传文件;访客只能看公开内容,不能发言。

办公场景我的建议是三层结构。第一层是全员大厅,比如“公司公告”“茶水间”,全员加入,任何人可发言;第二层是项目组房间,比如“某某项目X”,默认只拉项目成员,其他同事看不到房间存在;第三层是保密房间,比如人事讨论组,创建后设为私密,成员不能邀请外部人,只能由管理员拉人。

操作上,创建房间时打开 Element 的“房间设置”,权限模型选“仅限受邀成员”。房间一旦设为私有,未经邀请的账号在服务器上搜索不到这个房间,这在办公场景里非常重要,不同项目之间不必互相干扰。如果某个房间需要向全公司公开浏览,就把访问策略改成“服务器上的任何人都可以看到房间内容”,发言权限仍可控制。

4.3 用户注册与密码管理

因为前面关掉了开放注册,管理员需要手动给同事建号。命令行方法就是register_new_matrix_user,但每次敲命令比较麻烦。一个小技巧是写一个简单的 Shell 脚本:

#!/bin/bash docker exec -it office-matrix \ register_new_matrix_user \ -u "$1" \ -p "$2" \ -c /data/homeserver.yaml \ http://127.0.0.1:8008

存成add_user.sh,以后./add_user.sh zhangsan 初始密码就能添加用户。给同事的初始密码一定要求首次登录后修改,Element 端支持改密码。

密码找回是另外一个容易忽略的点。Synapse 默认不支持管理员直接在后台重置密码,得去数据库里把密码哈希改掉,或者用命令行工具。我倾向于在homeserver.yaml里设置registration_shared_secret,这样可以用 API 快速重置密码。具体用法文档里写得很清楚,我这里提醒一句就够了:这条信息一定要保存好,不要泄露。

5. 本地办公版运维与调优建议

长期维护中,有几个点比第一次部署更重要。实话讲,部署只要照着抄就行,维护才是真正考验人的地方。

5.1 存储架构:先用 SQLite 还是直接上 PostgreSQL

Synapse 默认用 SQLite 数据库,文件就放在数据目录里。对于 30 人以下的办公场景,SQLite 完全够用,部署最简单、备份也简单。但有个前提:不要一个人在里面疯狂拉历史记录,也不要让机器人高频写入。只要日常聊天负载平稳,SQLite 不会成为瓶颈。

团队规模超过 50 人,或者你打算长期保留所有历史消息,我建议一步到位换 PostgreSQL。迁移过程不算复杂,但需要停服操作。我会在服务刚搭好的时候就直接用 PostgreSQL,因为这比以后数据多了再迁移省事得多。用 Compose 管理的话,加一个 PostgreSQL 容器,再把 Synapse 的数据库配置指过去即可。篇幅有限,我不展开全部配置文件,核心思路是:Synapse 支持 SQLite 迁移到 PostgreSQL,官方文档有现成步骤。

5.2 备份与恢复:数据无价,配置也一样

Synapse 的数据分三块:数据库里的账号、房间、消息索引;媒体文件(图片、视频、文件);签名密钥。备份策略很简单:数据库文件或 SQL 定时备份到另外一台机器,媒体目录整目录同步,密钥文件单独加密保存。恢复的时候,三个数据要配套还原,缺一个都会出错。

我自己的做法是写一个凌晨执行的定时任务,把/srv/matrix/data整体打包,上传到公司内部的对象存储或另一台机器的磁盘。因为聊天数据每天都在变,备份周期不要超过 24 小时。如果团队里有人频繁发文件,也可以把媒体目录单独增量同步,减少打包体积。这里强调一句:签名密钥丢失的后果非常严重,可能会导致所有客户端无法信任服务器,所以密钥文件一定要和数据库分开备份。

5.3 升级策略:不要追新版本,但要定期更新

Synapse 更新频率不算低。我的原则是:不要在办公平台刚跑稳定时频繁升级,但也不要半年不升。每次升级前先看官方 Changelog,确认没有破坏性的配置变更,然后拉新镜像、重启容器,观察半小时日志。如果有异常,马上回滚到旧镜像。

容器化部署的最大优势就是升级方便。Compose 文件里如果写了image: matrixdotorg/synapse:latest,每次docker compose pull会拉最新版,但latest标签在长时间运行后可能跟旧数据不兼容。建议改用明确的版本标签,比如matrixdotorg/synapse:v1.105.0,升级时手动改版本号。这样即使升级出错,也能迅速退回去。

6. 常见问题排查实录

这部分内容整理自我一路部署和日常运维里真实遇见的问题,每条都配上排查思路,希望能帮你在最快时间内定位问题。

6.1 客户端提示“无法连接到服务器”,但服务端看起来正常

最常见的坑不是端口不通,而是server_name与访问地址不一致。Synapse 的配置里server_name决定用户 ID,而客户端填的服务器地址是“连接地址”,两者不需要相同,但用户容易搞混。我建议先在浏览器访问http://matrix.local:8008,能打开就说明网络通;再打开客户端,服务器地址随手补上完整的http://前缀,很多客户端不填前缀会自动当 HTTPS 解析,导致握手失败。

真正网络层的排查用三条命令:

ss -lntp | grep 8008 sudo ufw status sudo docker compose logs --tail 100 synapse

第一条看进程是否监听,第二条看防火墙,第三条看日志。办公网络环境里,问题大概率出在客户端电脑的 DNS 解析,或者服务器防火墙没放行 8008 端口。

6.2 登录时报“Invalid username or password”

先确认账号确实创建成功。用管理员账号在 Element 登录,看能否进入管理功能。如果管理员也登不上,重点检查数据库是否初始化完成。轻量环境下,数据库初始化可能需要几秒,刚启动马上注册账号容易出现这种问题。

另一种可能是时间不同步。Matrix 的端到端加密和会话认证依赖时间戳,服务器时间和客户端时间差太大会直接认证失败。执行timedatectl status看系统时间,不对就配置 NTP 同步。这个坑最容易忽略,因为它跟配置完全无关,纯粹是物理世界的时间偏差。

6.3 消息能发出去,但加密会话失败

登录正常、发消息也正常,但点开加密房间就报错,这多半是密钥备份没配好。Matrix 的端到端加密,密钥存在客户端本地,换设备后需要从密钥服务器恢复。Synapse 本身可以托管加密密钥,但需要在客户端设置里主动开启“创建恢复密钥”并记录恢复码。行政、财务这类账号尤其要提醒,否则换了电脑就看不到历史加密消息。

我建议在团队引入 Matrix 的第一周就发一页内部说明,教大家设置密钥备份,并把恢复码保存到公司密码管理器。这一段内容虽然简单,但直接影响员工对加密功能的信任度。

6.4 服务器内存占满、响应缓慢

如果只有少数用户但内存占用异常高,常见原因是媒体缩略图生成和日志堆积。Synapse 收到图片会生成多种尺寸的缩略图,图片多的时候 CPU、内存直线上涨。可以调整生成策略,限制缩略图尺寸规格,减少计算量。日志方面,Compose 默认不限制日志大小,跑久了可能吃掉几 GB 磁盘。

在 Compose 文件里加一段配置可以控制日志上限:

services: synapse: logging: driver: json-file options: max-size: "50m" max-file: "3"

重启容器后生效。这条配置我建议从第一天就加上,别等磁盘满了再处理。

7. 长期使用后的几个实用小经验

把这个办公平台跑起来以后,我总结了些文档里不会写清楚的小经验,不妨直接拿去用。

第一,房间命名要规范。Matrix 房间 ID 是随机字符串,不好看,但你可以给每个房间设置一个稳定的房间别名,比如#研发-客户端:matrix.local。同事之间发链接就把别名发出来,点开就能进房间,不用在服务器列表里筛。

第二,机器人接入是办公效率的一倍提升点。Synapse 支持应用服务,你可以自己写一个简单的通知机器人,把代码仓库的 CI 结果、监控告警、运维事件发到指定房间。内部系统对接这个场景,云平台往往要收费或者限制 API,自托管完全自己说了算。

第三,千万别什么都往全员房间丢。聊天平台用久了,全员房间里堆积大量无意义消息,后来的人根本翻不动。我给团队定的规则是:全员房间只放公告和必读信息,讨论一律进项目组房间。技术上的权限隔离有了,习惯上的内容隔离同样重要。

第四,如果哪天真要开放对外联邦,记得在防火墙放行 8448 端口。本地网络版配置里如果只是白名单留空,联邦就是关闭状态,8448 端口不用开。一旦改成开放联邦,这个端口必须暴露,否则外部服务器连不进来,但对外的一刻,整个安全模型也会改变,需要重新评估公网入口的风险。

最后说一个我这段时间用得最多的技巧:出问题先看日志,不要动不动重启。Synapse 日志本身写得相当清晰,很多错误信息已经给出原因,“Invalid configuration”会告诉你具体是哪一行有问题;“Federation is disabled”会提醒你干了件不可能的事。学会从日志往回倒推配置问题,比盲目重装要高效得多。这套办公平台我目前已经稳定跑了几个月,几十个同事日常聊天、传文件、会议室讨论都用它,基本没有让人操心的故障。对于一个内部聊天系统来说,稳定、可控、数据在手,就是最大的价值。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进