如何自建 Matrix 主服务器(homeserver)

按 Element 官方文档安装 Synapse,发布 .well-known 委派,按房间与媒体量规划内存。Matrix 托管 Core 套餐标价 $6/月起,年付等效 $4.80。
按 Element 官方文档安装 Synapse,发布 .well-known 委派,按房间数与媒体量规划内存。Matrix 托管 Core 套餐标价 $6/月起,年付等效 $4.80。
联邦改变的是邮箱归属,而不是受众可见性
自建 Matrix 主服务器最反直觉的一点是:联邦(federation)在设计中就让大部分拓扑保持公开。各主服务器之间会互相复制共享房间,机制上接近 SMTP 服务器在不同域名之间转发邮件——你的服务器加入一个房间后,这个房间同样会存在于其他所有参与者的主服务器上。自建真正转移的是元数据——谁在和谁说话、什么时候说——把它收进你自己管理的数据库里。它本身并不能做的,是把房间成员名单与更大的网络隔离开。
机制上分为两条通道,各司其职。参考实现主服务器 Synapse 通过 8448 端口讲 Matrix 规范定义的服务器对服务器(server-to-server)API,而 Element 等客户端应用则通过 443 端口访问你的域名。像 @you:example.com 这样的用户 ID,本质上是一个声明:example.com 运行着一台主服务器;远端节点会用你安装时生成的签名密钥来校验你发出的事件。加密保护的是房间内的消息内容,这与“谁在房间里”是两回事。
这种区分正是预期容易落空的地方。在加密房间里,消息内容对外部不可读,但成员关系这一事实、房间地址以及涉及的服务器名称,仍然会经过你的机器参与的各个联邦。一台服务十二人的家庭服务器,和一台拥有一万个房间的公共社区服务器,遵循的是同一套协议规则;区别只在于你加入房间时暴露了多少面。在发出第一个邀请之前就定好姿态,而不是事后补救。
典型的失败从这里开始:把私人房间当成隐形房间,然后在某台远端服务器的数据库里发现成员名单。支付方式、地理位置或托管档次都改变不了联邦语义——能改变它的只有配置:受限房间、联邦白名单,以及在一台你打算保持小规模的服务器上谨慎挑选要加入的房间。如果受众才是敏感部分,就让服务器完全不进公共房间,并告知每位成员:邀请会传播房间地址。先把这个姿态定下来,剩下的搭建就只是一张清单,而不是一场争论。
VPS $4.80* 起(年付期限),存储 1–5 TB NVMe 年付折合 $24/月起,带 IPMI 的独立服务器 $39.20/月起。加密货币账单,免 KYC。
立即启动内存按房间和媒体来定,而不是看 vCPU 标签
vCPU 数量是营销写在标签上的数字;内存才是真正决定一台主服务器体验好坏的轴。Synapse 会把房间状态、在线状态和媒体的记账信息保留在内存中以保持响应速度,工作集随已加入的房间、活跃用户和媒体仓库的增长而增长。一台核心多、内存小的机器会比它的规格表更早出现退化——通常先是加入房间变慢,然后是同步请求在负载下超时。
容量规划应跟随实际负载。一台服务十几个轻量房间的家庭服务器,在 8 vCPU、32 GB DDR5 ECC 的套餐上运行得很从容,数据库和媒体库放在本地 NVMe 上——该档位大约 320 GB——上传和状态重新同步带来的写入突发会被本地盘直接吸收,而不是排队等待。带大量媒体的联邦房间,或与其他网络对接的桥接(bridge),才是会突破这个底线的负载,因为每张图片、每段语音都会落进媒体仓库并留在那里。
在这个规模下,Postgres 就跑在同一台机器上——这常让在公司里把它当托管服务用的人感到意外。把数据库和媒体仓库放在本地存储上可以缩短请求路径:一次同步请求先碰内存,再碰本地磁盘,全程不经过任何网络跳数。要有意识地盯住媒体库——max_upload_size、保留策略和定期 vacuum,决定了增长是平平无奇还是演变成半夜的磁盘告警。
常见的错误是买足了带宽和核心,却让进程饿着内存,然后反过来怪联邦让同步变慢。第二个错误是把 Postgres 放到网络存储上,延迟尖峰恰好在房间重新同步时出现。按两条增长轴——已加入的房间和已存储的媒体——来定容量,把 CPU 标签排除在决策之外。拿不准时,内存上调一档;主服务器原谅多余的内存,远比原谅多余的核心容易。
按官方文档的路径安装 Synapse
安装只有一条权威路径,偏离它就是各种求助帖的起点。Synapse 安装指南会带你完成软件包或 virtualenv 的安装、生成 homeserver.yaml 和签名密钥的 --generate-config 运行,以及你所选 server_name 的注册。第一次就照着文档一步一步来;所有后续决定都写在配置文件里,你要让它天生正确,而不是事后打补丁。
有两个值值得慢下来认真对待。server_name 会成为这台机器上每个用户 ID 的域名部分,实际上不可更改;public_baseurl 则是客户端复制进链接和联邦端点的内容。以后改名服务器,所有引用旧域名的账号和房间都会变成孤儿——协议没有改名操作。选域名时就要当作会用十年,因为运维上你确实会用十年。
用 register_new_matrix_user 创建第一批用户,然后让 Element 之类的客户端通过你自己的域名连接,确认客户端 API 正常应答。在测试机上,整个流程——下单、开机、安装、首次登录——一个下午就能跑通。在 Core 上部署,标价 $6/月——年付等效 $4.80——等你把迁移流程演练过一次,再搬生产数据。
安装出问题的地方通常在于:混用软件包来源——发行版的旧版 Synapse 配上新版的配置模式——然后把随之而来的报错栈当成磁盘或网络故障去排查。锁定一个安装渠道,在笔记里记下版本号,之后每次升级都走同一个渠道。项目文档中心保持客户端安装路径的最新,而服务器文档则是配置键的权威来源。枯燥且可复现,胜过聪明但脆弱——尤其是对一台家人每天都要依赖的东西。
委派首先是 DNS 工程,其次才是算力
联邦失败更多发生在名字解析层,而不是算力层——这听起来违反直觉,直到你亲手追踪一次加入房间的过程。用户 ID 里的服务器名必须能解析,/.well-known/matrix/client 和 /.well-known/matrix/server 两个文件必须把请求指向正确的位置,8448 必须用一张该域名真正持有的证书应答 TLS。这三件事都做对,远端主服务器才能找到你;漏掉一件,它们会静默拒绝握手,你的日志里什么有用的东西都不会留下。
委派(delegation)存在的意义,是让面向用户的域名与服务器名可以不同。/.well-known/matrix/server 文件里带一个 m.server 字段,指明真正的联邦端点——它可以位于另一个主机名甚至另一台机器上;而通过 /.well-known/matrix/client 做的客户端委派,则把应用指向客户端 API。两者都以纯 JSON、正确的 Content-Type 通过 443 提供;在端点还在挪动的阶段,缓存存活时间要设得短一些。
一定要从你自己的网络之外测试委派,因为本地解析器会用缓存恭维你。用 curl 抓取两个 well-known 路径,用 openssl s_client 检查证书链,然后再期待远端加入能成功。在端点前放 CDN 是可以的,前提是它原样透传 JSON,并且远离联邦端口——在联邦端口上,CDN 的证书和缓冲习惯通常弊大于利。
经典的翻车方式是:为一个你从未真正开通的服务器名发布委派,或者让一台普通的 Web 服务器拿着错误的证书应答 8448。远端主服务器不会就这些事给你发邮件;它们只是不再来敲门。联邦是正确性工程,它奖励的是枯燥、有文档记录的 DNS 配置,而不是巧妙的配置。把委派配置块写下来一次,下一台服务器原样复用。
Postgres 和媒体库决定升级的成败
SQLite 作为默认数据库出厂,因为它让第一次启动毫无阻力;而在真实负载下,人们对它的好评也仅此一句。一旦服务器装进了带真实媒体的房间,就该迁移到 PostgreSQL——它的文档覆盖安装,Synapse 文档覆盖表结构。迁移工具 synapse_port_db 可以把现有的 SQLite 实例整体搬过去,最好趁一个安静的时间窗、停掉进程后再做。
媒体仓库是第二个悄无声息的增长点。加入的房间里共享的每一个头像、每一张图片、每一个文件都会落到你的磁盘上,而默认值设计得相当宽松:max_upload_size 限制单个文件大小,media_retention 设置决定远端媒体在清理前保留多久。第一天就把这两项设好,之后每月检查一次增长——一台感觉很小的主服务器,一个季度之内就可能装下 50 GB 别人的会议幻灯片。
数据库侧有两个旋钮值得每季度看一眼。Autovacuum 的默认值假设的是 Web 负载,而不是一个繁忙房间在两次心跳之间就能改写数千行的场景,所以要调高成本限制,直到膨胀曲线保持平坦。连接数的行为也类似:每个 worker 线程都开自己的数据库会话,一个活跃实例的会话数增长比新手预期的快得多——在 pg_stat_activity 里观察它们,一旦数量多到一眼数不过来,就在前面加一个连接池。
备份不体面但一锤定音:每晚一次 pg_dump,加上签名密钥和配置的副本,能让一台挂掉的机器在一小时内复活;PostgreSQL 自己的备份章节就是导出—恢复流程的权威参考。当工作集超出共享切片的容量时,租一台 Forge,标价 $49/月——年付等效 $39.20——给数据库和媒体库配上各自独立的本地 NVMe 盘。
常见的错误是连续多年升级却从不读数据库注意事项,然后才发现一次大版本升级包含的表结构迁移,在你的数据量上要跑好几个小时。把升级排进日程,每次升级前先做快照,让发布说明而不是紧迫感来驱动顺序。一个在周日早晨演练过的维护窗口,永远胜过周二晚上一场刺激的宕机。
先按法律选旗帜,再按延迟选
所有 12 个机房位置统一一个标价,这让司法辖区从一道预算题变成一道思考题。公开的溢价是例外:冰岛和挪威 +20%,瑞士 +35%,卢森堡 +15%。其余全部——阿姆斯特丹、法兰克福、东京、新加坡、香港、台北、斯德哥尔摩、赫尔辛基——按基础标价计费,所以你选的旗帜要么不花钱、要么付溢价,不存在另一套价格体系。
法律上的差异是真实的,但范围有限,不同负载对它们的权重也不同。雷克雅未克把非欧盟机架与无强制数据留存组合在一起;苏黎世在欧盟直接管辖范围之外运行瑞士 FADP 流程;阿姆斯特丹和法兰克福受 GDPR 管辖,同时拥有欧洲大陆最好的往返延迟;四个 APAC 节点各自遵循当地法规。先选辖区的那篇指南可以把这个决策排好序,离岸 VPS 指南梳理了其中的取舍,如果你的威胁模型涉及情报共享同盟,Five/Nine/Fourteen Eyes 解读解释了那些缩写。
以后再迁移比永远选错便宜,但并不免费:服务器名焊死在 DNS 上,所以换旗帜通常意味着全新部署和一次对联邦感知的账号迁移。第一次部署就要当机架是永久性的来规划,把之后的任何搬迁当作带备份的重建,而不是平移。积累多年的房间是最痛的部分——十年的对话压缩不动,从几十台远端服务器重新拉取媒体可能要花好几天。
延迟仍然决定用户体验:中欧的一户家庭会先感受到阿姆斯特丹或法兰克福的好坏,远早于注意到机架受哪部法典管辖。联邦还会放大这种效应,因为你的服务器在与几十台远端主服务器持续对话——像接入 AMS-IX 的阿姆斯特丹或接入 FICIX 的雷克雅未克这样对等互联良好的节点,能让这些对话保持短促,同步延迟不可感知。
选错的方式是:为负载选了法律,却没人为延迟负责——一台苏黎世机器服务一个欧盟用户为主的房间名单,买到了流程上的距离,付出的是谁也没要求的往返延迟。位置表格列出了每个节点的档次、上联带宽和适用法律,通读一遍就能把候选收敛到两个。把这两个列进候选名单,都做基准测试,让测量数据而不是坊间传说来终结争论。
端口:8448 服务联邦,443 服务客户端
联邦在一台普通 Web 服务器之外只需要一个入站端口:8448/tcp 承载服务器对服务器流量,与客户端用的 443/tcp 并列。两者在所有套餐上默认开放,所以防火墙工作主要是别在后期把它们弄坏。整个产品目录流量不限量,实际的上限是端口速率——入门 VPS 线为 1 Gbps——而不是任何可能被联邦流量耗尽的配额。
从外部向内验证。从远端执行 openssl s_client -connect matrix.example.com:8448,应能完成 TLS 握手并出示你域名的证书;通过 443 的客户端登录,行为应与任何其他 HTTPS 服务无异。一台放行 443 却丢弃 8448 的防火墙会制造经典的半死服务器:网页客户端一切正常,而远端加入莫名其妙地卡住。
把外部视角常驻进你的监控。一个来自不同网络的定时小任务,每五分钟尝试一次到联邦端口的 TLS 连接,它告诉你陌生人体验到什么——这才是这里唯一重要的视角。搭配一个提前 30 天触发的证书到期告警,因为证书一旦过期,远端参与者会静默地从你的房间里消失,而本地客户端照常工作,数据中心里没有任何东西会替你抱怨。
当你真的要加防火墙时——ufw allow 8448/tcp 是 Debian 上常见的写法——记住有状态规则重启后依然生效,而你对它们的记忆未必,所以把这两个开放端口写在委派笔记旁边。每台 VPS 标配一个 IPv4 和一个 IPv6 /64,这意味着联邦从第一天起就能双栈运行,不需要额外买地址,也不需要以后重新编号。
反复发生的事故是:一轮加固冲刺顺手关掉了 8448;联邦悄然退化,因为机器内部没有任何东西注意到外部不再到来。要对“出站联邦活动停止”设告警,而不只是对你自己的 HTTP 检查设告警,这样错误就只是五分钟的修复,而不是一周莫名其妙的房间异常报告。两个端口,都有文档,都有监控——这就是全部暴露面。
Dendrite 和 Conduit 用更少的资源跑同样的逻辑
Synapse 是参考实现,但不是唯一的实现。Dendrite(Matrix 生态的第二代主服务器)和 Conduit(用 Rust 编写的轻量服务器)都能跑在同一台 VPS 上,占用更小——二进制以 dendrite 和 conduit 安装,应答同一套协议。前面几节的容量逻辑在迁移后原样成立:内存按房间和媒体定,Postgres 放本地 NVMe,8448 可达,委派正确。
资源差异在小套餐上足以产生影响:轻量实现稳定在几百 MB 附近,而参考进程偏好几个 GB 的余量;崩溃后重启只需几秒,而大数据库预热要几分钟。在一台混合用途的机器上——这里一条隧道,那里一个网站根目录——这个差异决定哪些项目根本有机会被部署。不过要用你真实的房间列表来测试;合成基准测试对每个实现都过于客气,只有你社区的真实流量才说实话。
变化的是功能面和运维履历。Synapse 漫长的部署历史意味着大多数桥接指南、管理工具和审核流程默认它,而轻量服务器用一部分生态分量换来更精瘦的资源占用——这在一台还托管着其他东西的机器上是加分的。对家庭服务器来说,先测试轻量选项是合理的;对桥接繁重的社区服务器来说,参考实现的成熟度通常自己就能赢得这场争论。
主服务器之间的迁移不是改名:用户 ID 携带服务器名,所以 @you:example.com 里的域名只有在新实现应答同一个名字时才能幸存。把切换规划成一次割接——停旧服务器、搬数据、改委派指向——并且两边都保留可恢复的备份,直到新服务器完整运行一周没有意外。
陷阱是为了省资源选了轻量服务器,然后发现某个必需的桥接或审核工具不支持它。选择之前先盘点你真正在用的功能,因为省下的 RAM 在一个停摆的工作流面前一文不值。无论你跑哪一种服务器,协议层面的职责——名字、端口、密钥——都完全相同,所以前面几节的工作一项都不会白做。
Matrix 主服务器:按这个顺序跑完
按这个顺序执行,每一步都在校验上一步。第一,定姿态:受众模型、联邦还是封闭、只用私人房间还是允许公共房间。第二,选旗帜——为负载选法律,为用户选延迟——同时定规格,内存按房间和媒体定,而不是看任何标签。第三,下单开机,先配好 SSH 密钥,再让任何东西碰网络。
第四,DNS:服务器名、两份 /.well-known/matrix/ 文档、委派指向,然后是 8448 和客户端端口的证书。第五,按官方文档路径安装 Synapse,生成签名密钥,server_name 和 public_baseurl 各只设置一次,并用 register_new_matrix_user 注册第一个用户。第六,把数据库迁到 PostgreSQL,并在媒体库还没有值得丢失的东西之前就排好每晚的 pg_dump。
第七,从你自己网络之外——而不是从沙发上——开放并验证 8448/tcp 和 443/tcp 两个端口。第八,用一个远端账号测试一次真实的联邦加入,端到端盯完整个握手;然后才开始邀请别人。平台的开机在账单入账后大约一分钟完成,所以 DNS 与安装的流程可以在下单的同一个小时开始。
第九,把家规写在用户真正会读的地方:谁可以建房间、媒体政策是什么、新人如何获得邀请。社区总会漂向它的默认值,而没有写在任何地方的默认值,由嗓门最大的人决定。在安静的第一周花一小时写好那一页,可以避免第六个月才爆发的争吵——那时习惯已经固化,改变它们要消耗你再也无法铸造的善意。
第十,把维护节奏写下来:每月检查媒体库、每季度读完发布说明后升级、每年一次演练过的恢复。一台主服务器是家庭或组织的邮件基础设施级设备,按这个标准对待,它能稳定运行多年,最大的波澜不过是一次配置 diff。把委派笔记和签名密钥备份放在一起——因为它们合起来,就是这台服务器的身份。
你们帮我托管管理 Synapse 吗?
不。平台只出租 KVM 切片,完全不介入应用层——安装、升级、数据库调优和内容审核都归持有 root 登录的人。这正是主服务器属于你的原因:从媒体保留策略到联邦政策的每一个配置决定,都由你自己编写和执行,而不是走某个厂商的变更流程。
一台家庭主服务器需要多少内存?
十几个活跃用户、以私人房间为主,在 32 GB DDR5 ECC 套餐上、配合本地 NVMe 上的数据库和媒体库,就能运行得很从容。把安装推向更高档位的,是带大量媒体的联邦房间,或与其他网络对接的桥接——因为两者会同时撑大工作集和媒体仓库。
用 Dendrite 或 Conduit 替代 Synapse 可以吗?
两者都能跑在同一台 VPS 上、占用更小,容量逻辑也完全一致:内存按房间和媒体定,Postgres 放本地 NVMe,联邦端口保持开放。在拍板之前,先把你实际使用的桥接和审核工具,逐一对照各服务器的功能支持清单——轻量实现是用一部分生态成熟度换效率。
年付可以用 USDT 支付吗?
可以。十二个月的账单先把 20% 折扣作用在美元总额上,再按实时汇率转换成十九种币种中的任意一种,而 USDT 正是锚定美元的那一种。如果你希望支付通道本身泄露得更少,门罗币(Monero)承担这个角色——币种选择和付款周期选择是两个独立的旋钮。
联邦需要哪些端口?
服务器对服务器流量用 8448 端口,客户端用 443,两者在所有套餐上默认开放。.well-known 委派文件告诉远端主服务器该去哪里敲门,所以联邦首先是名字解析的正确性问题,其次才是带宽问题。务必从你自己网络之外验证两个端口,因为半开的防火墙造成的正是那种静默卡住的加入——它们永远不会出现在本地日志里。