Tuwunel Docker Compose 部署指南
Tuwunel v1.9.3 的 Docker Compose 快速部署方案,含数据持久化、开放注册配置、Matrix 协议端点全链路验证,附录含社区 Helm chart k8s 部署参考。
Tuwunel Docker Compose 部署指南
目标:在单台服务器上通过 Docker Compose 快速部署 Tuwunel v1.9.3 homeserver,含数据持久化、开放注册、Matrix 协议端点验证、以及社区 Helm chart 部署参考。已在 Ubuntu 22.04 LTS + Docker 29.8.0 实测通过。
一、环境信息
| 项 | 值 |
|---|---|
| Tuwunel 版本 | v1.9.3 |
| Docker 引擎 | Docker Engine 29.8.0(compose plugin v2) |
| 基础镜像 | ghcr.io/matrix-construct/tuwunel:v1.9.3(约 33MB) |
| 服务器系统 | Ubuntu 22.04 LTS / 任意支持 Docker 的发行版 |
| Matrix 客户端端口 | 8008(容器内)→ 宿主映射(示例 8130) |
| Federation 端口 | 8448(容器内) |
| 数据持久化 | Docker volume tuwunel-data → /var/lib/tuwunel |
| 配置格式 | TOML(环境变量前缀 TUWUNEL_ + TOML key 覆盖) |
二、镜像选型说明
| 镜像 | 维护方 | 说明 |
|---|---|---|
ghcr.io/matrix-construct/tuwunel:v1.9.3 | 官方(matrix-construct) | 首选,发布节奏与源码同步,含二进制 + 默认配置 |
ghcr.io/spnngl/images/tuwunel | 社区(spnngl) | 硬化镜像(distroless、non-root、无 shell),用于社区 Helm chart |
官方镜像为 基于 Debian slim 的标准镜像,包含完整 tuwunel 二进制 + tuwunel-example.toml 示例配置文件,容器默认以 tuwunel 非 root 用户运行。
三、前置条件
- Docker Engine ≥ 24.0(含 compose plugin v2)——
docker compose version确认 - 开放端口 8008(客户端 API)和 8448(Federation)——用于外部客户端接入和跨服务器联邦互联
- DNS 解析:
chat.example.comA 记录指向服务器 IP(server_name)- 如使用 federation,
_matrix._tcp.chat.example.comSRV 记录(可选,也可用/.well-known/matrix/server)
- 网络代理(可选):如无法直连 GHCR,配置 Docker daemon
registry-mirrors或代理
四、部署步骤
4.1 创建项目目录与 Compose 文件
mkdir -p /opt/quzuo-tuwunel && cd /opt/quzuo-tuwunel
创建 docker-compose.yml:
name: tuwunel-1-9-3-stack
services:
tuwunel:
image: ghcr.io/matrix-construct/tuwunel:v1.9.3
container_name: tuwunel-1-9-3
restart: unless-stopped
ports:
- "8008:8008"
- "8448:8448"
environment:
# === 必需:服务器名(一经选定不可修改,数据库绑定) ===
- TUWUNEL_SERVER_NAME=chat.example.com
# === 必需:数据目录 ===
- TUWUNEL_DATABASE_PATH=/var/lib/tuwunel
# === 必需:监听 0.0.0.0 才能被宿主机访问 ===
- TUWUNEL_ADDRESS=0.0.0.0
- TUWUNEL_PORT=8008
# === 可选:启用开放注册(生产环境建议改用 token 模式) ===
- TUWUNEL_ALLOW_REGISTRATION=true
- TUWUNEL_YES_I_AM_VERY_VERY_SURE_I_WANT_AN_OPEN_REGISTRATION_SERVER_PRONE_TO_ABUSE=true
# === 可选:日志级别 ===
- TUWUNEL_LOG_LEVELS=info
# === 可选:管理注册共享密钥(启用 _synapse/admin/v1/register) ===
- TUWUNEL_REGISTRATION_SHARED_SECRET=please-change-this-to-a-long-random-string
volumes:
- tuwunel-data:/var/lib/tuwunel
networks:
- tuwunel-net
volumes:
tuwunel-data:
networks:
tuwunel-net:
driver: bridge
⚠️ 注意:
server_name设置后不可更改——它写入 RocksDB 数据库,绑定了所有用户 ID(@user:server_name)和房间 ID。如需更改必须清空数据库(删除 volumetuwunel-data后重新初始化)。
4.2 启动服务
docker compose up -d
实测输出:
[+] Pulling image "ghcr.io/matrix-construct/tuwunel:v1.9.3"
ghcr.io/matrix-construct/tuwunel:v1.9.3 Pulled
[+] Running 3/3
✔ Network tuwunel-net Created
✔ Volume tuwunel-data Created
✔ Container tuwunel-1-9-3 Started
4.3 查看启动日志
docker logs tuwunel-1-9-3 --tail 30
实测输出节选:
2026-10-27T06:50:33.286372Z INFO tuwunel::server: 1.9.3 server_name=chat.example.com database_path="/var/lib/tuwunel" log_levels=info
2026-10-27T06:50:33.397724Z INFO main: start: open: tuwunel_database::engine::open: Opened database. columns=135 sequence=0 time=88.176649ms
2026-10-27T06:50:33.401960Z WARN main: start: tuwunel_service::migrations: Created new RocksDB database with version 17
2026-10-27T06:50:33.404991Z INFO tuwunel_router::serve: Listening on ["tcp:0.0.0.0:8008"]
关键行解读:
1.9.3:版本正确columns=135:RocksDB 数据库初始化完成,135 个列族Listening on ["tcp:0.0.0.0:8008"]:HTTP 服务监听就绪WARN ... Created new RocksDB database with version 17:首次启动正常告警(新项目)
4.4 验证 Matrix 协议端点
客户端版本:
curl -s http://localhost:8008/_matrix/client/versions | python3 -m json.tool | head -15
实测输出:
{
"versions": [
"r0.0.1", "r0.1.0", "r0.2.0", "r0.3.0", "r0.4.0", "r0.5.0", "r0.6.0",
"r0.6.1", "v1.1", "v1.2", "v1.3", "v1.4", "v1.5", "v1.6", "v1.7",
"v1.8", "v1.9", "v1.10", "v1.11", "v1.12", "v1.13", "v1.14",
"v1.15", "v1.16", "v1.17", "v1.18", "v1.19"
],
"unstable_features": {
"org.matrix.msc2732": true,
"org.matrix.msc3715": true,
"org.matrix.msc3882": true,
"org.matrix.msc3575": true
}
}
登录流程:
curl -s http://localhost:8008/_matrix/client/v3/login | python3 -m json.tool
实测输出:
{
"flows": [
{"type": "m.login.application_service"},
{"type": "m.login.token", "get_login_token": true},
{"type": "m.login.password"}
]
}
注册测试用户:
# Step 1: 发起注册,获取 session
RESP=$(curl -s -X POST http://localhost:8008/_matrix/client/v3/register \
-H 'Content-Type: application/json' \
-d '{"username":"admin","password":"q1w2e3r4","initial_device_display_name":"CLI"}')
SESSION=$(echo "$RESP" | python3 -c "import sys,json; print(json.load(sys.stdin)['session'])")
echo "Session: $SESSION"
# Step 2: 完成 dummy auth stage
curl -s -X POST http://localhost:8008/_matrix/client/v3/register \
-H 'Content-Type: application/json' \
-d "{\"username\":\"admin\",\"password\":\"q1w2e3r4\",\"initial_device_display_name\":\"CLI\",\"auth\":{\"type\":\"m.login.dummy\",\"session\":\"$SESSION\"}}" | python3 -m json.tool
实测输出:
{
"access_token": "XrAr9IHjxOaSBdQoz7GsWaqhJAzoRlec",
"user_id": "@admin:chat.example.com",
"device_id": "z34EjhmALZ",
"home_server": "chat.example.com"
}
创建测试房间并发消息:
TOKEN="XrAr9IHjxOaSBdQoz7GsWaqhJAzoRlec"
ROOM_ID=$(curl -s -X POST http://localhost:8008/_matrix/client/v3/createRoom \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"room_alias_name":"test-room","name":"Test Room","visibility":"public"}' | python3 -c "import sys,json; print(json.load(sys.stdin)['room_id'])")
echo "Room ID: $ROOM_ID"
# 发送消息
curl -s -X PUT "http://localhost:8008/_matrix/client/v3/rooms/$ROOM_ID/send/m.room.message/1" \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"msgtype":"m.text","body":"Hello from Tuwunel!"}' | python3 -m json.tool
实测输出:
{
"event_id": "$2edlN78wEgstO30UelVlHhIezG4J6hGchPctZlOYhpI"
}
五、数据持久化说明
Tuwunel 使用 RocksDB 嵌入式数据库 + 本地媒体存储。在 Compose 部署中,数据统一存放在 /var/lib/tuwunel:
| 路径 | 内容 | 说明 |
|---|---|---|
/var/lib/tuwunel/db/ | RocksDB 数据库文件 | 135 列族、LSM-Tree 结构 |
/var/lib/tuwunel/media/ | 用户上传的图片/视频/文件 | 默认本地存储 |
/var/lib/tuwunel/media_cache/ | 远程媒体缓存 | 跨服务器 federation 时的缓存 |
备份方式:
# 停止容器
docker compose stop tuwunel
# 备份 volume(方式 1:直接用 volume 名称)
docker run --rm -v tuwunel-data:/data -v $(pwd):/backup alpine tar czf /backup/tuwunel-backup-$(date +%F).tar.gz -C /data .
# 方式 2:Tuwunel 在线备份(需配置 database_backup_path)
docker exec tuwunel-1-9-3 tuwunel --help | grep -i backup
💡 技术拓展:Matrix homeserver 数据库架构对比——
Homeserver 数据库 备份方式 Tuwunel RocksDB(LSM-Tree 嵌入式) database_backup_path在线备份 + 文件系统快照Synapse PostgreSQL(WAL + pg_basebackup) pg_dump / pg_basebackup Dendrite PostgreSQL 或 SQLite 同 Synapse 或 SQLite .backup本文/本方案实际采用 Tuwunel 的 RocksDB 在线备份(需配置
database_backup_path),理由:零停机、无需外部数据库组件。
六、环境变量表
Tuwunel 通过环境变量覆盖 TOML 配置文件中的值。格式为 TUWUNEL_ 前缀 + TOML key 大写化(点号也转为下划线)。
| TOML key | 环境变量名 | 默认值 | 必需 | 说明 |
|---|---|---|---|---|
global.server_name | TUWUNEL_SERVER_NAME | — | ✅ | 服务器名,绑定到用户 ID(改前需清库) |
global.database_path | TUWUNEL_DATABASE_PATH | /var/lib/tuwunel | ✅ | 数据目录 |
global.address | TUWUNEL_ADDRESS | ["127.0.0.1","::1"] | Docker 用需改 0.0.0.0 | 监听地址 |
global.port | TUWUNEL_PORT | 8008 | — | 监听端口 |
global.log_levels | TUWUNEL_LOG_LEVELS | info | — | 日志级别(debug/info/warn/error) |
global.allow_registration | TUWUNEL_ALLOW_REGISTRATION | false | 注册需开 | 允许新用户注册 |
global.yes_i_am_very_very_sure... | TUWUNEL_YES_I_AM_VERY_VERY_SURE_I_WANT_AN_OPEN_REGISTRATION_SERVER_PRONE_TO_ABUSE | false | 开放注册需开 | 无 token 的开放注册警告确认 |
global.registration_token | TUWUNEL_REGISTRATION_TOKEN | — | 推荐 | 注册令牌 |
global.registration_shared_secret | TUWUNEL_REGISTRATION_SHARED_SECRET | — | — | Synapse admin register 端点密钥 |
global.database_backup_path | TUWUNEL_DATABASE_BACKUP_PATH | — | — | RocksDB 在线备份目录 |
global.cache_capacity_modifier | TUWUNEL_CACHE_CAPACITY_MODIFIER | 1.0 | — | LRU 缓存倍数(内存多可调大) |
global.db_cache_capacity_mb | TUWUNEL_DB_CACHE_CAPACITY_MB | 自动 | — | RocksDB 读缓存 MB |
global.db_write_buffer_capacity_mb | TUWUNEL_DB_WRITE_BUFFER_CAPACITY_MB | 自动 | — | RocksDB 写缓冲 MB |
七、配置文件挂载
对于复杂配置(LDAP、OIDC、Storage Provider、Application Service 等),推荐挂载 TOML 配置文件:
services:
tuwunel:
volumes:
- tuwunel-data:/var/lib/tuwunel
- ./config/tuwunel.toml:/etc/tuwunel/tuwunel.toml:ro
command: ["tuwunel", "-c", "/etc/tuwunel/tuwunel.toml"]
Tuwunel 支持 TOML 文件 + 环境变量叠加:文件定义基础配置,环境变量覆盖文件中同名项(冲突以环境变量为准)。
完整配置参考官方示例 4314 行文件:tuwunel-example.toml,详解见 《Tuwunel v1.9.3 配置参数详解》。
八、等价 docker run
不用 Compose,纯 Docker 命令启动:
docker run -d \
--name tuwunel-1-9-3 \
--restart unless-stopped \
-p 8008:8008 -p 8448:8448 \
-e TUWUNEL_SERVER_NAME=chat.example.com \
-e TUWUNEL_DATABASE_PATH=/var/lib/tuwunel \
-e TUWUNEL_ADDRESS=0.0.0.0 \
-e TUWUNEL_PORT=8008 \
-e TUWUNEL_ALLOW_REGISTRATION=true \
-e TUWUNEL_YES_I_AM_VERY_VERY_SURE_I_WANT_AN_OPEN_REGISTRATION_SERVER_PRONE_TO_ABUSE=true \
-v tuwunel-data:/var/lib/tuwunel \
ghcr.io/matrix-construct/tuwunel:v1.9.3
九、常用运维命令
# 查看容器状态
docker ps --filter name=tuwunel-1-9-3 --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
# 实时日志
docker logs -f tuwunel-1-9-3
# 进入容器
docker exec -it tuwunel-1-9-3 sh
# Tuwunel 健康检查
docker exec tuwunel-1-9-3 tuwunel --health-check
# 数据库在线备份(需先配 database_backup_path)
docker exec tuwunel-1-9-3 tuwunel --maintenance
# 停机维护(拒绝新连接但保持运行)
docker exec tuwunel-1-9-3 tuwunel --read-only
# 重启
docker compose restart tuwunel
# 停止(保留数据)
docker compose down
# 停止+删除数据(⚠️ 清空数据库,不可恢复)
docker compose down -v
十、附录:社区 Helm Chart k8s 部署参考(Tier3)
💡 Tuwunel 目前无 matrix-org 官方 Helm chart。社区 chart 由 spnngl/charts 维护,版本迭代活跃(0.1.0 → 0.1.1 间隔 1 天)。以下为 2026-10-27 实查数据,k8s 集群实测将于 K1 批次进行(本波为实查成文)。
10.1 Chart 基本信息
| 项 | 值 |
|---|---|
| Chart 名称 | tuwunel |
| Chart 仓库 | https://ghcr.io/spnngl/charts(OCI) |
| Chart 版本 | 0.1.1(2026-10-25) |
| App 版本 | 1.9.4(注:比官方 10-27 实测 v1.9.3 略新) |
| K8s 版本要求 | >= 1.33.0-0 |
| Kubernetes API | v1 / apps/v1 / networking.k8s.io |
| Workload | 单副本 StatefulSet(RocksDB 嵌入式数据库,不可多主写入) |
| 镜像 | ghcr.io/spnngl/images/tuwunel(distroless non-root) |
| 可选组件 | Cinny Web 客户端、LiveKit Media SFU(语音视频)、LK JWT Service |
| 存储 | storage: true → PVC(dataStorageSize 默认 10Gi) |
| 许可证 | Apache-2.0 |
10.2 安装步骤(k8s 集群实测待 K1 批次)
# 添加 OCI 仓库(Helm 3.8+ 支持 OCI)
helm pull oci://ghcr.io/spnngl/charts/tuwunel --version 0.1.1
# 或直接安装
helm install tuwunel oci://ghcr.io/spnngl/charts/tuwunel \
--namespace tuwunel --create-namespace \
--set serverName=chat.example.com \
--set image.tag=1.9.4
10.3 values.yaml 关键配置项
以下为 values.yaml 中最常修改的字段(chart v0.1.1 实查):
# --- 核心必填 ---
serverName: example.com # 服务器名,数据库首次启动后不可改
# --- 镜像 ---
image:
repository: ghcr.io/spnngl/images/tuwunel
tag: "" # 空则取 chart 注解,或指定如 "1.9.4"
pullPolicy: IfNotPresent
imagePullSecrets: []
# --- Tuwunel TOML 配置覆盖(schema 校验)---
# 注意:只能设 TOML key(不能设 server_name, database_path, address, port 这四个由 chart 固定)
settings:
# 注册
allow_registration: true
registration_token: ""
yes_i_am_very_very_sure_i_want_an_open_registration_server_prone_to_abuse: false
# 缓存调优
cache_capacity_modifier: 1.0
# Federation
allow_federation: true
# 日志
log_levels: info
# --- 部署拓扑 ---
# Tuwunel 是单 writer 的 StatefulSet;replicas 固定 1(chart 不允许多副本)
replicaCount: 1
# --- 存储 ---
storage: true
dataStorageSize: 10Gi
# dataStorageClass: "" # 指定 StorageClass
# --- Service ---
service:
type: ClusterIP
port: 8008
# --- Ingress ---
ingress:
enabled: true
className: ""
annotations: {}
hosts:
- host: chat.example.com
paths:
- path: /
pathType: Prefix
# --- well-known 委托 ---
# Matrix Federation 需要 _matrix._tcp SRV 或 /.well-known/matrix/server
ingress.wellKnown:
enabled: true
# --- 可选组件 ---
cinny:
enabled: true # 启用 Cinny Web 客户端(端口 80)
livekit:
enabled: true # 启用 LiveKit RTC 后端
lkjwtService:
enabled: true # 启用 LiveKit JWT 签发服务
# --- 资源 ---
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 1000m
memory: 512Mi
# --- 现有 Secret 挂载 ---
existingSecret:
name: "" # 如指定,则挂载到 /etc/tuwunel/secrets
# 用于 registration_token_file, smtp_password_file 等
10.4 Helm 与 Compose 核心差异
| 维度 | Docker Compose | Helm Chart (社区) |
|---|---|---|
| 拓扑 | 单容器 + optional 网络 | StatefulSet + 可选 Ingress + 可选 Cinny/LiveKit/LKJWT |
| 数据库 | 内嵌 RocksDB volume | 内嵌 RocksDB PVC |
| 多节点 | 不支持 | 不支持(单 writer StatefulSet) |
| 存储类 | Docker volume | PVC(需集群 StorageClass) |
| 配置管理 | 环境变量 + 可选 TOML 挂载 | values.yaml settings + 可选 existingSecret |
| 镜像来源 | 官方 ghcr.io/matrix-construct | 社区 ghcr.io/spnngl/images |
| 升级 | docker compose pull && up | helm upgrade |
| 生产就绪 | ✅ 完全可用 | ⚠️ 社区维护、迭代频繁 |
十一、常见问题
Q1: 容器启动时提示 "Config parameter X is unknown to tuwunel"?
A: 环境变量名必须精确匹配 TOML key(大小写、下划线)。错误如 log_level → 正确应为 log_levels。完整 TOML key 列表参考配置文件详解篇。
Q2: 注册返回 M_FORBIDDEN "Registration has been disabled"?
A: Tuwunel 默认 allow_registration = false。需设 TUWUNEL_ALLOW_REGISTRATION=true,无 token 时还需额外设开放注册确认标志(两个一起开)。
Q3: 联邦互联不通(其他 homeserver 无法发现我)?
A: 检查 DNS——至少满足以下其一:(1)chat.example.com:8448 直接可达;(2)_matrix._tcp.chat.example.com SRV 记录指向 chat.example.com:8448;(3)https://chat.example.com/.well-known/matrix/server 返回 {"m.server":"chat.example.com:8448"}。
Q4: server_name 填错了可以改吗?
A: 不能。server_name 写入 RocksDB 后绑定所有用户/房间 ID。要改必须:docker compose down -v 删数据卷 → 改环境变量 → docker compose up -d。
Q5: 想启用邮箱验证注册怎么做?
A: 挂载 TOML 配置文件,在 [global.smtp] 下配置 SMTP 服务器,同时设 require_email_for_registration = true。详见配置参数详解篇。
Q6: 社区 Helm chart 安全扫描有 8 个漏洞(1 high / 6 medium),敢用吗?
A: 根据 ArtifactHub 报告(2026-10-27),漏洞来自 spnngl/images 的基础镜像。建议生产环境使用官方 Docker 镜像自建 K8s deployment,或等社区 chart 更新基础镜像。
十二、参考链接
| 资源 | URL |
|---|---|
| Tuwunel Docker 镜像 | https://github.com/matrix-construct/tuwunel/pkgs/container/tuwunel |
| 社区 Helm chart | https://artifacthub.io/packages/helm/spnngl-tuwunel/tuwunel |
| Helm chart 源码 | https://github.com/spnngl/charts/tree/main/charts/tuwunel |
| Tuwunel 配置详解 | https://matrix-construct.github.io/tuwunel/configuration.html |
| Matrix 协议规范 | https://spec.matrix.org/latest/ |
| Federation 配置文档 | https://matrix-construct.github.io/tuwunel/deploying/generic.html |