TeamMapper 0.4.0 Docker Compose 部署指南
Ubuntu 26.04 上以 ghcr 官方镜像 + PostgreSQL 15 部署 TeamMapper 0.4.0 的完整实测流程,含建图/协作/持久化端到端验证与运维命令。
TeamMapper 0.4.0 Docker Compose 部署指南
目标:在 Ubuntu 26.04 服务器上以 Docker Compose 从零部署 TeamMapper 0.4.0(ghcr 官方预构建镜像 + PostgreSQL 15),完成建图、协作、持久化全链路验证。本文所有命令与回显均为 2026-11-02 实测采集。
一、环境信息
- 操作系统:Ubuntu 26.04.1 LTS(x86_64)
- Docker:29.9.2,build a82e528
- Docker Compose:v5.6.1
- 应用:TeamMapper 0.4.0(镜像
ghcr.io/b310-digital/teammapper:latest,镜像创建时间 2026-10-28,对应官方 releasev0.4.0-1) - 数据库:PostgreSQL 15(
postgres:15-alpine,与官方docker-compose-prod.yml一致) - 对外端口:8144(映射到应用内部 3000)
- 部署目录:
/opt/teammapper/deploy/(服务器上自建)
二、镜像选型说明
TeamMapper 官方镜像只发布在 GitHub Container Registry(ghcr.io),Docker Hub 上的 teammapper/* 均非官方。可用形态对照:
| 形态 | 来源 | 说明 |
|---|---|---|
ghcr.io/b310-digital/teammapper:latest | 官方 README「Quick Start」推荐 | 预构建,免编译,本文采用 |
ghcr.io/b310-digital/teammapper:v0.4.0-1 | 官方 Releases 对应 tag | 锁版本生产建议 |
源码构建(docker-compose-prod.yml + Dockerfile) | 官方仓库 | 需 clone 全仓库并 --build,构建链长 |
实测拉取(服务器直连 ghcr 成功,未走加速器):
docker pull ghcr.io/b310-digital/teammapper:latest
Digest: sha256:c565ceb598bd7ed31db8dd44b21882ea69c5f40be5d92f90f1db2d2bea98d5e6
Status: Downloaded newer image for ghcr.io/b310-digital/teammapper:latest
ghcr.io/b310-digital/teammapper:latest
⚠️ 网络说明:本环境访问
github.com网页端存在被返回伪 404 页的情况,仓库页/README 取证需走 HTTP 代理;但ghcr.io镜像拉取实测直连可用,无需代理或加速器。若你的网络拉取 ghcr 超时,可为 Docker 守护进程配置代理或镜像加速后重试。
💡 说明:实测发现镜像内
/home/node/app/teammapper/package.json的version字段为0.1.9,与 release tagv0.4.0-1不一致——这是上游 package.json 版本号未随 tag 同步的事实,不影响功能;核对部署版本应以 release tag 与镜像 digest 为准。
三、前置条件
- 已安装 Docker 与 compose 插件(
docker compose version有输出即可)。 - 目标端口未被占用:
ss -ltn | grep ':8144' || echo "8144 空闲"
8144 空闲
- 建立部署目录与配置目录:
mkdir -p /opt/teammapper/deploy/config
四、部署步骤
4.1 编写 compose 文件
/opt/teammapper/deploy/docker-compose.yml(本文实测文件原样,基于官方 README Quick Start 改写端口与凭据):
name: teammapper-0.4.0-stack
services:
app_prod:
image: ghcr.io/b310-digital/teammapper:latest
container_name: teammapper-0.4.0-app
environment:
MODE: PROD
BINDING: "0.0.0.0"
POSTGRES_DATABASE: teammapper-db
POSTGRES_HOST: postgres_prod
POSTGRES_PASSWORD: q1w2e3r4
POSTGRES_PORT: 5432
POSTGRES_SSL: "false"
POSTGRES_SSL_REJECT_UNAUTHORIZED: "false"
POSTGRES_USER: teammapper-user
POSTGRES_QUERY_TIMEOUT: 100000
POSTGRES_STATEMENT_TIMEOUT: 100000
DELETE_AFTER_DAYS: 30
LOG_LEVEL: log
JWT_SECRET: tm-jwt-9f3a7c2e5b8d1460
ports:
- "8144:3000"
depends_on:
- postgres_prod
volumes:
- ./config/settings.override.json:/home/node/app/teammapper/config/settings.override.json:ro
networks:
- tmnet
postgres_prod:
image: postgres:15-alpine
container_name: teammapper-0.4.0-db
environment:
PGDATA: /var/lib/postgresql/data/pgdata
POSTGRES_DB: teammapper-db
POSTGRES_PASSWORD: q1w2e3r4
POSTGRES_PORT: 5432
POSTGRES_USER: teammapper-user
volumes:
- postgres_prod_data:/var/lib/postgresql/data/pgdata
networks:
- tmnet
volumes:
postgres_prod_data:
networks:
tmnet:
driver: bridge
关键项解说:
MODE: PROD:以生产配置(settings.prod.json)启动 NestJS 后端;官方.env.default注释说明 PROD 模式建议配数据库 SSL,无 SSL 时 Quick Start 示例仍用MODE: PROD+POSTGRES_SSL: false,实测可正常启动。BINDING: "0.0.0.0":应用默认只监听部分地址,显式绑全接口才能被端口映射访问。POSTGRES_SSL_REJECT_UNAUTHORIZED: "false":连接自签名证书数据库时不校验证书链(官方 compose 默认值)。JWT_SECRET:后端对person_idcookie 做签名校验的密钥(auth/person-id.middleware),未设置时「我的导图列表」接口不认 cookie。DELETE_AFTER_DAYS: 30:GDPR 默认保留期,到期由每日定时任务清理。LOG_LEVEL: log:NestJS 日志级别,可选error/warn/log/debug/verbose。- 应用内部监听 3000,宿主端口按实际环境改(本文用 8144)。
4.2 准备挂载配置文件
settings.override.json 是官方支持的运行时覆盖配置(详见 《TeamMapper 0.4.0 配置参数详解》),必须预先创建,否则 compose 会把它挂成目录:
echo '{}' > /opt/teammapper/deploy/config/settings.override.json
4.3 启动
cd /opt/teammapper/deploy && docker compose up -d
实测回显:
Container teammapper-0.4.0-db Creating
Container teammapper-0.4.0-db Created
Container teammapper-0.4.0-app Creating
Container teammapper-0.4.0-app Created
Container teammapper-0.4.0-db Starting
Container teammapper-0.4.0-db Started
Container teammapper-0.4.0-app Starting
Container teammapper-0.4.0-app Started
4.4 验证服务
docker compose ps
NAME STATUS
teammapper-0.4.0-app Up 12 seconds
teammapper-0.4.0-db Up 12 seconds
curl -s -o /dev/null -w 'HTTP %{http_code}\n' http://127.0.0.1:8144/
HTTP 200
后端启动日志确认路由与协作网关就绪(docker logs teammapper-0.4.0-app 节选,实测首尾):
[Nest] 49 - 11/02/2026, 6:45:12 AM LOG [RoutesResolver] MapsController {/api/maps}:
[Nest] 49 - 11/02/2026, 6:45:12 AM LOG [RouterExplorer] Mapped {/api/maps/:id, GET} route
[Nest] 49 - 11/02/2026, 6:45:12 AM LOG [RouterExplorer] Mapped {/api/maps, POST} route
[Nest] 49 - 11/02/2026, 6:45:12 AM LOG [RouterExplorer] Mapped {/api/maps/:id/duplicate, POST} route
[Nest] 49 - 11/02/2026, 6:45:12 AM LOG [RoutesResolver] SettingsController {/api/settings}:
[Nest] 49 - 11/02/2026, 6:45:12 AM LOG [RouterExplorer] Mapped {/api/settings, GET} route
[Nest] 49 - 11/02/2026, 6:45:12 AM LOG [YjsGateway] Yjs WebSocket server started on /yjs
[Nest] 49 - 11/02/2026, 6:45:12 AM LOG [NestApplication] Nest application successfully started
浏览器访问 http://<服务器IP>:8144/ 即见 TeamMapper 首页(页面 <title>TeamMapper</title> 实测确认)。
4.5 端到端功能验证(建图 → 协作 → 持久化)
创建一张图(后端 REST 实测):
curl -s -X POST -H 'Content-Type: application/json' \
-d '{"rootNode":{"name":"E2E 中心主题","colors":{},"font":{},"image":{}}}' \
http://127.0.0.1:8144/api/maps
响应节选(实测,字段完整):
{
"map": {
"uuid": "8f6b81e3-5d41-4b76-b811-6682b7dc6e07",
"data": [ { "name": "E2E 中心主题", "isRoot": true, "id": "4195d165-e799-44da-971c-431e8d7a7b1a", "...": "..." } ],
"deleteAfterDays": 30,
"deletedAt": "2026-12-02T06:46:47.788Z"
},
"adminId": "d8558598-4bc3-4d87-b1d8-3df7c6da8d92",
"modificationSecret": "c6237b28-48d5-4a20-8dbb-082c17137d19"
}
⚠️ 注意:
rootNode必须带colors/font/image三个对象字段(可为空对象),缺字段会 400。这是后端 valibot 严格 schema(MapCreateSchema)的实测行为,详见 《TeamMapper 0.4.0 API 使用详解》。
协作链路实测:用 Yjs 协议起两个 WebSocket 客户端(一个带 modificationSecret 可写、一个只读),可写端新增节点后,只读端 1.2 秒内收到广播;只读端尝试写入被服务端静默丢弃(实测回显):
[A] 初始节点: ["E2E 中心主题"]
[A] 已发送新增节点 update, 节点数: 2
[B] 收到广播后节点: ["协作新增节点-来自客户端A","E2E 中心主题"]
[B] 节点数: 2
[A] B写入后A侧节点数(应不变): 2
RESULT: COLLAB_OK
持久化验证(协作写入约 3 秒后从 REST 读取,确认已落 PostgreSQL):
curl -s http://127.0.0.1:8144/api/maps/8f6b81e3-5d41-4b76-b811-6682b7dc6e07 | python3 -c "import sys,json;d=json.load(sys.stdin);print('持久化后节点数:',len(d['data']),'节点名:',[n['name'] for n in d['data']])"
持久化后节点数: 2 节点名: ['E2E 中心主题', '协作新增节点-来自客户端A']
五、数据持久化说明
- 导图数据全部在 PostgreSQL(
postgres_prod_data命名卷),应用本身无状态;Yjs 内存文档经防抖写库,实测写入后约 3 秒可查。 - 备份即备份数据库:
docker compose exec postgres_prod pg_dump -U teammapper-user teammapper-db > backup.sql。 - 官方 README 提示:命名卷初始化后,
.env.prod里数据库相关变量再改动不会作用于已有库,需手工改库。 - 单图 JSON 备份可走 API:
GET /api/maps/<uuid>(带x-map-modification-secret头可重置保留计时)。
六、环境变量表
compose environment 支持的全部变量(来源:官方 README「Environment variable overrides」+ docker-compose-prod.yml 实测核对):
| 变量 | 默认值 | 说明 |
|---|---|---|
MODE | DEV | PROD 走生产配置;无数据库 SSL 时官方 Quick Start 也用 PROD+SSL false |
BINDING | — | 监听地址,容器内固定 0.0.0.0 |
POSTGRES_HOST/PORT/DATABASE/USER/PASSWORD | — | 数据库连接五元组 |
POSTGRES_SSL | true(prod compose) | 是否以 SSL 连库;Quick Start 内网直连置 false |
POSTGRES_SSL_REJECT_UNAUTHORIZED | false | 自签证书时保持 false,官方建议生产用受信证书再置 true |
POSTGRES_QUERY_TIMEOUT / POSTGRES_STATEMENT_TIMEOUT | 100000 | 库侧查询/语句超时(毫秒) |
DELETE_AFTER_DAYS | 30 | 导图保留天数 |
LOG_LEVEL | log(非 DEV) | NestJS 日志级别 |
JWT_SECRET | 空 | person_id cookie 签名密钥 |
AI_ENABLED | false | AI 生图开关 |
FEATURE_ARROWS | 未设(JSON 配置决定) | 置 true 强制开启节点间箭头功能 |
IMPRINT_URL / PRIVACY_URL | 未设 | 首页页脚法务链接目标,未设则隐藏 |
PICTOGRAM_API_URL / PICTOGRAM_IMAGES_URL | ARASAAC 官方 | 图标功能的上游代理地址 |
七、配置文件挂载
官方配置分三层(优先级由低到高):
teammapper-backend/config/settings.dev.json/settings.prod.json:镜像内置默认值,改settings.prod.json需重新构建镜像;settings.override.json:挂载进/home/node/app/teammapper/config/settings.override.json,运行时可改,覆盖 prod 配置——本文 compose 已挂载,参数详解见 《TeamMapper 0.4.0 配置参数详解》。
挂载生效实测:向 override 文件写入 systemSettings.urls.imprintUrl 后重启应用,GET /api/settings 返回中即出现该值:
curl -s http://127.0.0.1:8144/api/settings | python3 -c "import sys,json;d=json.load(sys.stdin);print('imprintUrl:',d['systemSettings']['urls'].get('imprintUrl'))"
imprintUrl: http://127.0.0.1:8144/imprint
八、等价 docker run
不想用 compose 时,两条 docker run 等价于上文 compose(官方 README Quick Start 的拆分形态;数据库参数须与上文一致):
docker network create teammapper-net
docker run -d --name teammapper-db --network teammapper-net \
-e POSTGRES_DB=teammapper-db -e POSTGRES_USER=teammapper-user \
-e POSTGRES_PASSWORD=q1w2e3r4 \
-v teammapper-pgdata:/var/lib/postgresql/data postgres:15-alpine
docker run -d --name teammapper-app --network teammapper-net \
-p 8144:3000 \
-e MODE=PROD -e BINDING=0.0.0.0 \
-e POSTGRES_HOST=teammapper-db -e POSTGRES_PORT=5432 \
-e POSTGRES_DATABASE=teammapper-db -e POSTGRES_USER=teammapper-user \
-e POSTGRES_PASSWORD=q1w2e3r4 -e POSTGRES_SSL=false \
-e DELETE_AFTER_DAYS=30 -e JWT_SECRET=tm-jwt-9f3a7c2e5b8d1460 \
ghcr.io/b310-digital/teammapper:latest
九、常用运维命令
cd /opt/teammapper/deploy
docker compose ps # 查看状态
docker compose logs -f app_prod # 跟踪后端日志(含路由/WS 事件)
docker compose restart app_prod # 改 settings.override.json 后重启生效
docker compose pull && docker compose up -d # 升级:拉新镜像重建
docker compose down # 停止(保留数据卷)
docker compose down -v # 停止并删卷(官方标注 DANGER,清空全部导图)
官方内置的运维任务(经 app 容器 pnpm 脚本执行,按需手工触发):
# 立即执行过期导图清理(平时每日 cron 自动跑)
docker compose exec app_prod pnpm --filter teammapper-backend run prod:data:maps:cleanup
# 清理无节点引用的图片(每日 01:00 UTC 自动)
docker compose exec app_prod pnpm --filter teammapper-backend run prod:data:images:cleanup
# 直接跑 SQL(TypeORM 数据源)
docker compose exec app_prod pnpm --filter teammapper-backend exec typeorm query "select count(*) from mmp_map" --dataSource ./dist/data-source.js
十、常见问题
Q1:docker pull ghcr.io/... 超时?
ghcr 在部分网络环境不可直连。为 Docker 守护进程配置 HTTP 代理(/etc/systemd/system/docker.service.d/http-proxy.conf)或使用镜像加速后重试;本文实测环境直连成功。
Q2:起不来,日志报数据库连接失败?
核对 POSTGRES_* 五元组与 postgres_prod 服务的环境变量完全一致;compose 内服务名 postgres_prod 即 POSTGRES_HOST 的值。首次启动库初始化需数秒,app 会重试,可 docker compose restart app_prod。
Q3:settings.override.json 挂载后变成空目录?
docker compose up 前宿主机文件不存在时,compose 会按路径创建目录。先 echo '{}' > config/settings.override.json 再启动(见 4.2)。
Q4:升级后旧图打不开?
TeamMapper 前端/后端协议带版本子协议(teammapper.v2),旧版前端缓存连新后端会被 426 拒绝。强刷(Ctrl+F5)清掉浏览器缓存的旧前端即可;数据本身向后兼容(如节点内联图片双格式并存,官方 README)。
Q5:想永久保留导图?
把 DELETE_AFTER_DAYS 调大(如 3650)后 docker compose up -d 重建 app;注意已建图的 deletedAt 按创建时配置计算,历史图需改库或重新导入导出。
十一、参考链接
- 官方 README(Quick Start/Production 章节):https://github.com/b310-digital/teammapper
- 官方部署文档:https://github.com/b310-digital/teammapper/blob/main/docs/deployment.md (含反向代理示例)
- 官方镜像:https://ghcr.io/b310-digital/teammapper
- 同类自托管文档系统部署可参考 《Papermerge 3.5.3 Docker Compose 部署指南》