ARTICLE · 1341424
老板要文档清单,你还在翻三个人微信收藏
开源运维
2026.11.10
老板要文档清单
你还在翻三个人微信收藏?
运维手册散在三个人的微信收藏里,SOP 存在某个同事的本地 Word,值班表是 Excel 截图——人一离职,文档跟着蒸发。想上 Confluence,按人头报预算,财务那关先卡住;想用 Notion,数据出境和合规又过不去。这是国内中小团队最典型的文档困境:不是没有工具,是没有一个自己能管、按空间分权限、还带版本历史的地方。
Docmost 就是冲这个场景来的。GitHub 上 2.2 万星,官方定位很直白:开源的协作 Wiki 和文档软件,Confluence 与 Notion 的替代品。技术栈是 NestJS 后端 + PostgreSQL 存正文与元数据 + Redis 做缓存和实时协作的适配器,三个容器起步,AGPL-3.0 许可,商用自建不花钱。下面这份教程按真实部署命令走,参数原样照抄即可,坑也一并写清楚。
壹
它到底解决什么
CHAPTER 01
先别急着敲命令,判断一下这东西对不对你的胃口。三个最典型的落地场景:
运维 SOP 与故障处置手册。 按空间切开——机房、网络、系统各一个 Space,每个空间下按"日常巡检 / 故障处置 / 变更流程"建页面树。页面历史会记录谁在什么时候改了哪一段,值班同事照着 SOP 执行时发现步骤过时,直接改,改完留痕,下次复盘能翻到是谁、为什么改。这比共享盘里 SOP_final_v3_最终版_真的最终.docx 靠谱得多。
部门知识库。 空间 + 组 + 权限三层模型。财务的方案书放进财务空间,运维账号看不到;技术部的架构决策记录放技术空间,全员可读不可写。权限粒度到页面级,私有页面只有作者和被授权的人能进。这一层是 Confluence 收费的核心,Docmost 开源版直接给。
技术文档带图。 页面里能直接嵌 draw.io、Excalidraw、Mermaid 三种图,架构图、流程图、时序图不用截图贴进来,改图就是改文档。评审意见用评论挂在具体段落旁边,不用在群里刷"第 3 段那个接口地址是不是错了"。
贰
部署:一份 compose 起三个容器
CHAPTER 02
前置条件四条,缺一不可:Linux 主机、Docker 24 以上、装了 compose 插件、3000 端口空着。先验一遍:
docker --version && docker compose version
配置目录只放 compose 文件和 .env,数据卷全交给 Docker 管,别自己 mkdir 数据目录再 bind mount,权限和 SELinux 会教你做人。
mkdir -p /opt/docmost && cd /opt/docmost
两个密钥必须现场生成。APP_SECRET 程序启动时强校验,必须 32 位以上;DB_PASSWORD 给 Postgres 用:
echo "APP_SECRET=$(openssl rand -hex 32)" > .env
echo "DB_PASSWORD=$(openssl rand -hex 16)" >> .env
然后写 compose。三个服务、三个命名卷,一个都不能少:
cat > docker-compose.yml <<'EOF'
services:
docmost:
image: docmost/docmost:latest
# 生产环境换成 Releases 里的版本号,本文对应 v0.97.0
depends_on: [db, redis]
environment:
APP_URL: 'http://192.168.6.10:3000' # 必须写成同事真正访问的地址(反代后填 https 域名)
APP_SECRET: '${APP_SECRET}'
DATABASE_URL: 'postgresql://docmost:${DB_PASSWORD}@db:5432/docmost'
REDIS_URL: 'redis://redis:6379'
DISABLE_TELEMETRY: 'true'
FILE_UPLOAD_SIZE_LIMIT: '50mb'
TZ: 'Asia/Shanghai'
ports:
- "3000:3000"
restart: unless-stopped
volumes:
- docmost_data:/app/data/storage
db:
image: postgres:18
environment:
POSTGRES_DB: docmost
POSTGRES_USER: docmost
POSTGRES_PASSWORD: '${DB_PASSWORD}'
TZ: 'Asia/Shanghai'
restart: unless-stopped
volumes:
- db_data:/var/lib/postgresql
# PG18 官方镜像的数据目录,别抄旧教程的 /var/lib/postgresql/data
redis:
image: redis:8
command: ["redis-server", "--appendonly", "yes", "--maxmemory-policy", "noeviction"]
restart: unless-stopped
volumes:
- redis_data:/data
volumes:
docmost_data:
db_data:
redis_data:
EOF
逐段说几个关键点。APP_URL 是全系统绝对地址的源头,邀请邮件链接、附件下载地址、页面里生成的绝对 URL 全从这来,必须写成同事浏览器里真正敲的地址,反代上 https 之后改成域名。DATABASE_URL 里的 ${DB_PASSWORD} 由 compose 从 .env 插值,所以 .env 和 compose 必须在同一目录。三个卷各司其职:docmost_data 挂 /app/data/storage 存附件和上传的图,db_data 挂 PG18 的数据目录,redis_data 存 AOF。注意 PG18 官方镜像的数据目录已经变成 /var/lib/postgresql(下面是带版本号的子目录),老教程里的 /var/lib/postgresql/data 挂上去等于把数据写进容器可写层。
拉起三个容器,首次要拉镜像加初始化 Postgres,等十几秒:
docker compose up -d
三条验证,一条都不能省:
docker compose ps
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:3000/
docker compose logs --tail 5 docmost
预期是三个容器 Up、首页返回 200、日志末尾出现 Nest application successfully started。任何一条不对,先看 docker compose logs docmost 有没有 The Environment variables has failed the following validations。

三条验证命令跑完的输出:三个容器 Up、首页 200、Nest 已启动
叁
第一次打开:建工作区只有一次机会
CHAPTER 03
浏览器访问 http://192.168.6.10:3000,会进 setup 页,填工作区名称、管理员邮箱和密码。这个接口只在一个工作区都不存在时可用——服务端 SetupGuard 的判据就是 workspace 数量,建完再访问会直接回 workspace setup already completed,没有第二次机会。所以工作区名想好再填,管理员邮箱用一个能收信的。
想让邀请邮件正常发出去,得配 SMTP;不配的话就在成员管理里复制邀请链接手动发微信。注意邀请链接会过期,发出去催着点。

打开首页:左边是空间和页面树,中间是页面内容,右上角搜索与成员管理
肆
把文档搬进来:空间、组、权限怎么划
CHAPTER 04
进来之后先划结构,别上来就写。Space 对应部门或项目,一个空间一棵页面树;Group 管人,把"运维组""财务组"建好,成员按组授权;页面可以设私有,也可以整空间公开只读。这套模型撑住几十人的团队绰绰有余。
页面历史与版本回滚是默认能力,改错了随时退。附件和图片落在 docmost_data 卷的 /app/data/storage 下,所以备份的时候这个卷和数据库一样重要。搜索默认走数据库全文索引,文档量级到几千页以内够用;再大就上 Typesense,设 SEARCH_DRIVER=typesense 并补上对应连接参数。

写页面的样子:正文里直接插表格、代码块、画图和评论,右侧能看到页面历史
伍
反代、备份与升级
CHAPTER 05
上生产基本都要 Nginx 反代加 https。三个必须配对的参数:
WebSocket 升级头。 实时协作走 socket.io(服务端 4.8 + Redis adapter),不是普通 HTTP。Nginx 只写 proxy_pass 的话,单人编辑正常,两个人同时改一页就露馅——看不到对方光标、改动不同步、标题偶发回滚。要 proxy_http_version 1.1、透传 Upgrade 和 Connection 两个头、proxy_read_timeout 给到 600 以上,别用默认 60s。
`APP_URL` 改成实际域名(含 https)。 改完必须 docker compose up -d 重建容器才生效,reload nginx 没用。
`client_max_body_size` 要 ≥ `FILE_UPLOAD_SIZE_LIMIT`。 应用侧默认 50mb,Nginx 默认只有 1M,传十几页扫描件时浏览器先失败,docmost 日志里干干净净——请求根本没到应用,要去 Nginx 的 error.log 里才找得到 413。两处一起调大再 reload。
备份是两样东西,缺一个都不算备份:pg_dump 导库 + 打包 docmost_data 卷(或者改用 STORAGE_DRIVER=s3 上对象存储)。只做 dump 的话,恢复后每篇文档的图全是裂的。两个备份放同一天同一批,落到异地。
升级流程固定:先 dump → 改 compose 里的镜像 tag 到 Releases 里的版本号 → docker compose pull && docker compose up -d。Postgres 别跨大版本直接换 tag,18 的数据 19 读不了,要升就走 dump → 换镜像 → restore。
要服务端导出 PDF 得另起一个 Gotenberg 容器,把 GOTENBERG_URL 填进去;纯内网还要画图的话,DRAWIO_URL 留空会走公网 diagrams.net 的嵌入地址,内网机器打不开,得自己再起 drawio 容器。
陆
几个必坑
CHAPTER 06
⚠ 避坑 · `APP_SECRET` 不换成…
APP_SECRET 不换成 32 位以上随机值,或者干脆留着示例里的 REPLACE_WITH_LONG_SECRET,容器启动校验直接 exit(1),屏幕上只有一行 The Environment variables has failed the following validations 加一段 JSON,看着像镜像坏了其实是自己没改。更麻烦的是上线之后再换,之前签发的 JWT 全部失效(JWT_TOKEN_EXPIRES_IN 默认 30d),全公司被踢下线重登。正确做法:上线前就定好,存进密钥库,别写在 compose 里提交 Git。
⚠ 避坑 · `APP_URL` 照抄成 `h…
APP_URL 照抄成 http://localhost:3000,登录能用、写文档也能用,但邀请邮件里的链接、页面里生成的绝对地址、附件下载链接全指回 localhost,同事点开是打不开的本机地址,还以为是权限问题查半天。正确做法:填同事真正访问的地址,反代上 https 之后写实际域名并重建容器。
⚠ 避坑 · Nginx 反代只配 `prox…
Nginx 反代只配 proxy_pass、没转发 WebSocket 升级头,单人编辑完全正常,两个人同时改一页就出问题——看不到对方光标、改动不同步、标题偶发回滚。正确做法:proxy_http_version 1.1、透传 Upgrade 与 Connection、proxy_read_timeout 给到 600 以上。
⚠ 避坑 · 备份只做了 `pg_dump`
页面正文在库里,附件和上传的图在 docmost_data 卷的 /app/data/storage,dump 里一个都没有,恢复后每篇文档的图全是裂的。正确做法:导库 + 打包 storage 卷(或改用 S3)两样一起备。
⚠ 避坑 · postgres 的卷路径照抄老…
postgres 的卷路径照抄老教程写成 /var/lib/postgresql/data,PG18 官方镜像的数据目录已经是 /var/lib/postgresql,挂错等于把数据写进容器可写层,容器一重建、一次 compose down -v 就是全新空库。正确做法:按本文的路径挂,且别跨大版本直接换 tag。
⚠ 避坑 · Redis 用 `noevict…
Redis 用 noeviction 又没设 maxmemory,文档一多、并发协作一上来内存吃满,写命令直接失败,表现是页面能打开、改完不保存、光标不出现,而 docmost 容器日志干干净净。正确做法:给 redis 配 maxmemory 并盯 used_memory,或者 redis 单独一台,别和别的服务挤。
⚠ 避坑 · 企业版功能别当免费功能规划
AI 对话、API Key、MFA 二次验证、页面审批/验证、SSO 单点登录都在 ee 目录下,需要商业授权,开源版点开就是提示升级。采购前先确认这几个是不是硬需求,别等装完给老板演示时才发现。
柒
速查表 · 截图存手机
CHAPTER 07
# 0. 前置:Linux + Docker 24 以上 + compose 插件,3000 端口空着
docker --version && docker compose version
# 1. 配置目录:数据卷交给 docker 管,这里只放 compose 和 .env
mkdir -p /opt/docmost && cd /opt/docmost
# 2. 两个密钥:APP_SECRET 必须 32 位以上,程序启动时会强校验
echo "APP_SECRET=$(openssl rand -hex 32)" > .env
echo "DB_PASSWORD=$(openssl rand -hex 16)" >> .env
# 3. 写 compose:docmost + postgres:18 + redis:8,三个命名卷一个都不能少
cat > docker-compose.yml <<'EOF'
services:
docmost:
image: docmost/docmost:latest
# 生产环境换成 Releases 里的版本号,本文对应 v0.97.0
depends_on: [db, redis]
environment:
APP_URL: 'http://192.168.6.10:3000' # 必须写成同事真正访问的地址(反代后填 https 域名)
APP_SECRET: '${APP_SECRET}'
DATABASE_URL: 'postgresql://docmost:${DB_PASSWORD}@db:5432/docmost'
REDIS_URL: 'redis://redis:6379'
DISABLE_TELEMETRY: 'true'
FILE_UPLOAD_SIZE_LIMIT: '50mb'
TZ: 'Asia/Shanghai'
ports:
- "3000:3000"
restart: unless-stopped
volumes:
- docmost_data:/app/data/storage
db:
image: postgres:18
environment:
POSTGRES_DB: docmost
POSTGRES_USER: docmost
POSTGRES_PASSWORD: '${DB_PASSWORD}'
TZ: 'Asia/Shanghai'
restart: unless-stopped
volumes:
- db_data:/var/lib/postgresql
# PG18 官方镜像的数据目录,别抄旧教程的 /var/lib/postgresql/data
redis:
image: redis:8
command: ["redis-server", "--appendonly", "yes", "--maxmemory-policy", "noeviction"]
restart: unless-stopped
volumes:
- redis_data:/data
volumes:
docmost_data:
db_data:
redis_data:
EOF
# 4. 拉起三个容器(首次要拉镜像 + 初始化 Postgres,等十几秒)
docker compose up -d
# 5. 验证(图 1):三个容器 Up、首页 200、日志里 Nest 已启动
docker compose ps
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:3000/
docker compose logs --tail 5 docmost
| cd /opt/docmost && docker compose ps | |
| curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:3000/ | |
| docker compose logs --tail 3 docmost |
排错顺序:
APP_SECRET 不换成 32 位以上随机值(或者干脆留着示例里的 REPL…(详见避坑段)
APP_URL 照抄成 http://localhost:3000:登录能用、写…(详见避坑段)
Nginx 反代只配了 proxy_pass,没转发 WebSocket 升级头…(详见避坑段)
终
写在最后
SUMMARY
Docmost 的价值不在功能多,在于它把 Confluence 最贵的那部分——空间权限、版本历史、实时协作——用三个容器和一份 compose 交到你手上。部署成本半小时,运维成本取决于你有没有认真做备份和反代。上线前把 `APP_SECRET` 和 `APP_URL` 定死,上线后把 pg_dump 和 storage 卷绑成同一个备份任务,这两件事做对,剩下的就是往里填文档了。
🍵
熊大大 · 小茶馆掌柜
一线踩坑十余年,专治各种「网上都说行,生产就是不行」。
觉得这篇有用,文末右下角的「赞」和「在看」点一下,转发给需要的人。
THANKS FOR READING · 下期再会
我是熊大大,在机房和终端之间泡了十年茶。
如果你觉得今天这篇有收获,欢迎点赞、在看、转发三连,我们下篇见。















































































