2026 年 Matrix 消息过期自动删除配置

记录 Matrix 中实现消息过期自动删除的两种方式:Synapse retention 服务端清理,以及 maubot expiringmessages 机器人按房间撤回消息。

这篇记录 Matrix 里实现消息过期、自动删除的两种常见方式。第一种是在 Synapse 服务端启用 retention,让服务器按房间策略从数据库中清理过期事件;第二种是使用 maubot 的 expiringmessages 插件,让机器人在房间里按时间撤回消息。

如果你已经按前面的 Synapse Docker Compose 文章部署了 Matrix 服务,优先建议使用服务器端 retention。机器人方案更灵活,不一定需要服务器管理员权限,但它本质上是定时撤回消息,不等同于从数据库层面清理。

一、两种方案怎么选

服务器端 retention 适合你自己管理 Synapse 服务端的场景。它的优点是策略更底层,可以由 Synapse 后台任务定期清理过期事件;缺点是需要修改 homeserver.yaml 并重启 Synapse,而且房间还需要设置 m.room.retention 状态事件。

机器人方案适合没有服务器权限、但拥有房间管理权限的场景。它通过机器人执行 redact 撤回超时消息,配置更方便;缺点是撤回操作会受机器人权限、联邦同步、客户端缓存等因素影响。

简单理解:

  • 有 Synapse 管理权限:优先用 retention
  • 只有房间管理权限:可以用 maubot 机器人。
  • 对安全性要求很高:不要把这两种方案理解成绝对可靠的“阅后即焚”。

二、方案一:启用 Synapse retention

先编辑 Synapse 的配置文件。Docker 部署时通常在宿主机这个位置:

nvim /root/data/docker_data/synapse/data/homeserver.yaml

homeserver.yaml 中加入或调整下面这段配置。注意:retention: 必须顶格写,前面不能有空格,也不能缩进到其他配置项下面。

retention:
  enabled: true
  default_policy:
    max_lifetime: 3d
  allowed_lifetime_max: 3d
  purge_jobs:
    - interval: 1d

这段配置的含义是:

  • enabled: true:启用 Synapse 的消息保留策略。
  • default_policy.max_lifetime: 3d:没有单独设置房间策略的房间,默认最多保留 3 天消息事件。
  • allowed_lifetime_max: 3d:如果房间自己设置了更长的保留时间,Synapse 会把它限制到最多 3 天。
  • purge_jobs:配置后台清理任务。这里不写 shortest_max_lifetimelongest_max_lifetime,表示这个任务覆盖所有已经过期的房间事件,每天跑一次。

时间可以按自己的服务器负载和房间规模调整。清理间隔越短,过期消息越快被处理,但数据库后台任务也会更频繁。

如果只是写 purge_jobs,还不等于所有房间都会自动按 3 天删除。purge_jobs 只是告诉 Synapse 后台清理任务什么时候跑、负责哪些生命周期范围;具体某个房间要保留多久,需要房间里有 m.room.retention 状态事件,或者在服务端配置全局默认策略。

如果你的目标不是 3 天,而是“三个月后自动删除”,不要写 3M。Synapse 的时长单位里 m 表示分钟,不表示月份;M 也不是可靠的月份单位。三个月建议按 90 天写成 90d

retention:
  enabled: true
  default_policy:
    max_lifetime: 90d
  allowed_lifetime_max: 90d
  purge_jobs:
    - interval: 1d

这段配置表示:没有单独设置房间策略的房间,默认保留 90 天;如果某个房间自己设置了超过 90 天的策略,也会被服务端限制到 90 天以内。房间仍然可以设置比 90 天更短的保留时间。

如果你想强制所有房间都尽量按 90 天执行,不希望房间设置成更短或更长,可以同时加上 allowed_lifetime_min

retention:
  enabled: true
  default_policy:
    max_lifetime: 90d
  allowed_lifetime_min: 90d
  allowed_lifetime_max: 90d
  purge_jobs:
    - interval: 1d

多数自用服务器不需要强制最短保留时间,只设置 allowed_lifetime_max 更灵活。

最终推荐确认一下这段配置在文件里的缩进大概是这样:

###### 消息保留策略,存在于房间级别,遵循 MSC1763
retention:
  enabled: true
  default_policy:
    max_lifetime: 90d
  allowed_lifetime_max: 90d
  purge_jobs:
    - interval: 1d

purge_jobs 也可以写成按生命周期分段的高级形式,例如官方示例里会把 3 天以内和 3 天以上的房间分给不同频率的任务。但如果自己管理的是小型 Matrix 服务器,通常用上面这种不限定范围的单个任务更稳妥,不容易漏掉房间。尤其不要写成 shortest_max_lifetime: 90dlongest_max_lifetime: 90d 同时放在同一个任务里;那只匹配最大生命周期刚好等于 90 天的房间,容易让其他房间被跳过。

错误写法示例,retention: 前面多了一个空格,会导致 Synapse 启动时报 YAML 解析错误:

 retention:

如果改完后 Synapse 起不来,可以先查看出错位置附近的行号:

nl -ba /root/data/docker_data/synapse/data/homeserver.yaml | sed -n '100,125p'

也可以先验证 YAML 能不能正常解析:

docker run --rm \
  -v /root/data/docker_data/synapse/data:/data \
  matrixdotorg/synapse:latest \
  python -c 'import yaml; yaml.safe_load(open("/data/homeserver.yaml")); print("YAML OK")'

修改完成后重启 Synapse:

docker compose -f /root/data/docker_data/synapse/docker-compose.yaml restart

如果你的 Compose 文件就在当前目录,也可以进入目录后执行:

cd /root/data/docker_data/synapse
docker compose restart

三、给房间设置过期时间

服务端启用 retention 只是打开功能。如果前面没有配置 default_policy,具体房间还需要写入 m.room.retention 状态事件;如果已经配置了全局 default_policy,这一节可以不做,除非这个房间想使用不同于全局默认值的保留时间。

以 Element 为例,进入目标房间后,在输入框执行:

/devtools

打开开发者工具后,先进入“浏览房间状态”,再点击右下角“发送自定义状态事件”。不要使用“发送自定义时间线事件”,否则发送后不会出现在房间状态里,Synapse 也不会把它当作房间保留策略。

Element 开发者工具中填写 m.room.retention 状态事件

在“事件类型”里只填写事件名本身:

m.room.retention

如果界面里有“状态键(State Key)”输入框,保持为空。

事件内容示例,下面表示房间消息最多保留 3 天:

{
  "max_lifetime": 259200000
}

这里的 max_lifetime 单位是毫秒,常见换算如下:

  • 1 小时:3600000
  • 12 小时:43200000
  • 1 天:86400000
  • 3 天:259200000
  • 7 天:604800000

发送成功后,回到“浏览房间状态”页面,应该能看到新增的 m.room.retention。点进去确认内容里有 max_lifetime: 259200000,就说明当前房间的 3 天保留策略已经写入成功。保存后,Synapse 会在后台清理任务运行时处理过期消息。

这个房间状态事件只影响当前房间。其他房间如果没有设置 m.room.retention,并且服务端也没有配置 default_policy,就不会因为 purge_jobs 写了 3 天而自动删除。

需要注意,部分客户端可能仍然保留本地缓存,或者在时间线上显示为空白事件。服务端清理不代表每个客户端界面都会立刻同步成完全一样的状态。

四、方案二:使用 maubot 机器人

如果没有 Synapse 服务器管理权限,可以使用 maubot 的 expiringmessages 插件。它会在房间中追踪新消息,并在超过设定时间后执行撤回。

项目地址:

  • maubothttps://github.com/maubot/maubot
  • expiringmessages 插件:https://github.com/maubot/expiringmessages

这个方案的前提是你已经有一个可用的 maubot 实例,并且已经创建好安装了 expiringmessages 插件的机器人。

五、邀请机器人进房间

把安装好插件的机器人邀请到目标房间,然后给它足够的权限。通常至少需要把机器人提升为版主或管理员,确保它有权限撤回房间消息。

Matrix 房间里撤回消息依赖 power level。大多数房间里,撤回他人消息通常需要 50 或更高权限。如果机器人权限不足,插件即使配置成功,也无法真正删除超时消息。

六、机器人常用指令

在目标房间发送下面的指令设置消息有效期:

!expire set <duration>

<duration> 可以使用 dhms 组合表示天、小时、分钟和秒。

常见示例:

!expire set 7d

表示新消息 7 天后过期。

!expire set 12h

表示新消息 12 小时后过期。

!expire set 1d12h30m

表示新消息 1 天 12 小时 30 分钟后过期。

查看当前房间设置:

!expire show

取消当前房间的自动撤回:

!expire unset

注意,机器人一般只会追踪设置之后发送的新消息。设置之前已经存在的历史消息,不一定会被自动纳入处理。

七、重要限制

无论使用 retention 还是机器人撤回,都不要把它当成绝对可靠的隐私销毁机制。

首先,Matrix 是联邦协议。消息一旦进入其他服务器,清理或撤回事件需要跨服务器同步。对方服务器是否及时处理、是否保留历史、客户端是否已经缓存,都不是本服务器能完全控制的。

其次,撤回不等于防截图。任何成员都可以在消息过期前截图、复制或通过客户端缓存保存内容。

最后,“阅后即焚”在 Matrix 里并不可靠。已读状态依赖客户端是否发送回执事件,也无法强制所有客户端按同一逻辑执行销毁。

更稳妥的使用场景,是在你完全控制并信任的私有服务器、内部房间中使用消息过期策略,用它减少数据库长期堆积和降低历史消息暴露面,而不是把它当成绝对安全边界。