Docker Compose部署Docmost:数据库、附件持久化与首次协作

把新人手册放进自托管Wiki,容易漏掉两件事:文字还在,附件却丢了;管理员能编辑,第二个人却进不来。Docmost部署的交付终点应当是独立账号共同维护一页内容,并能在重建和恢复后继续使用。

下面给出一个全新实例的配置和验收步骤,按2026年10月15日核验的官方资料整理,没有将文档步骤写成部署实测。适用于已有Docker Engine、Compose V2和SSH权限的Linux服务器,不用于升级旧数据库,也不是公开生产部署方案。

1. 先确定版本、入口与数据归属

本文固定Docmost 0.96.0。该发行的官方Compose使用PostgreSQL 18与Redis 8,不能照搬旧教程的数据库版本和目录。这里将依赖明确到18.6-bookworm、8.10.2-trixie,标签来自官方镜像元数据;具体拉取与兼容情况需在自己的环境确认。

服务 用途 容器内持久化位置
Docmost 页面协作与文件访问 /app/data/storage,本地附件
PostgreSQL 18 页面、用户及权限等数据库内容 /var/lib/postgresql
Redis 8 队列等运行依赖 /data,启用AOF

数据库和Redis只在项目网络内通信,不发布宿主机端口。应用3000端口仅绑定服务器回环地址,由SSH隧道进入。首次初始化也保持这个边界,避免工作区所有者还没创建就开放入口。

2. 保存密钥,再写完整Compose

新建独立目录,确认下列项目名没有被现有实例使用:

bash 复制代码
mkdir docmost-guide
cd docmost-guide
umask 077
printf 'APP_SECRET=%s\nDB_PASSWORD=%s\n' \
  "$(openssl rand -hex 32)" \
  "$(openssl rand -hex 32)" > .env
chmod 600 .env

两个随机值分别生成。APP_SECRET要求至少32个字符,不能保留示例常量;数据库密码使用十六进制,减少拼进连接URI时的特殊字符编码问题。保存.env,不提交到公开仓库。

在同一目录创建compose.yaml:

yaml 复制代码
name: docmost-guide
services:
  docmost:
    image: docker.1ms.run/docmost/docmost:0.96.0
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
    environment:
      APP_URL: http://localhost:3000
      APP_SECRET: ${APP_SECRET:?set APP_SECRET in .env}
      DATABASE_URL: postgresql://docmost:${DB_PASSWORD:?set DB_PASSWORD in .env}@db:5432/docmost
      REDIS_URL: redis://redis:6379
      STORAGE_DRIVER: local
    ports:
      - "127.0.0.1:3000:3000"
    volumes:
      - docmost-files:/app/data/storage

  db:
    image: docker.1ms.run/library/postgres:18.6-bookworm
    restart: unless-stopped
    environment:
      POSTGRES_DB: docmost
      POSTGRES_USER: docmost
      POSTGRES_PASSWORD: ${DB_PASSWORD:?set DB_PASSWORD in .env}
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U docmost -d docmost"]
      interval: 10s
      timeout: 5s
      retries: 10
    volumes:
      - db-data:/var/lib/postgresql

  redis:
    image: docker.1ms.run/library/redis:8.10.2-trixie
    command: ["redis-server", "--appendonly", "yes", "--maxmemory-policy", "noeviction"]
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 10
    volumes:
      - redis-data:/data

volumes:
  docmost-files:
  db-data:
  redis-data:

镜像统一通过毫秒镜像的docker.1ms.run/完整路径获取,保留应用命名空间;PostgreSQL和Redis使用官方镜像的library/路径。入口可达与镜像下载完成、应用功能正常分别核验。

注意PostgreSQL 18这里挂载的是/var/lib/postgresql。不要为了沿用旧目录直接修改现有数据库容器的主版本;旧实例升级需要独立迁移方案。

3. 按"配置、依赖、应用"顺序启动

下面是读者在自己的服务器执行的步骤:

bash 复制代码
docker compose config --quiet
docker compose pull
docker compose up -d
docker compose ps
docker compose logs --tail=80 docmost db redis
curl -fsS http://127.0.0.1:3000/api/health

config --quiet检查配置与必填变量,不需要把含密钥的展开配置粘到讨论区。依赖健康检查通过只表示可以尝试启动应用;健康接口响应也不代表邀请、编辑和附件已经验证。

如果应用不断重启,先看数据库、Redis连接及APP_SECRET,再查文件目录权限。若数据库密码改过,旧数据卷里的账号密码不会因环境变量改动自动更新;不要用删卷掩盖这个问题。

把几个常见现象分开,能少走几轮无效重启:

现象 优先检查
镜像没有下载完成 实际标签、镜像入口、网络和认证响应,不先改数据库密码
数据库健康但应用连接失败 连接串内的账号、密码、服务名,以及现有卷初始化时的凭据
页面文字能读,文件打不开 本地文件卷是否挂对、文件是否存在,再核对访问权限
第二人登录后看不到手册 是否已接受工作区邀请、是否加入对应空间与成员组

日志里可能含邮箱、访问路径等信息。排障时只截取对应错误和时间段,清理密钥及邀请令牌,再向他人提供。

4. 建立工作区,再让第二个账号加入

在自己电脑执行SSH转发,替换账号及服务器地址,保留连接:

bash 复制代码
ssh -N -L 3000:127.0.0.1:3000 ops@YOUR_SERVER

浏览器打开http://localhost:3000,按初始化页面创建工作区和首个所有者账号。电脑3000端口应空闲;若改本地端口,需同时调整访问地址和APP_URL,不能让邀请链接仍指向旧入口。

在工作区设置的成员入口,输入第二位成员邮箱,角色先选Member,创建邀请。此固定版本的自托管界面支持在待接受邀请的菜单中选择"Copy link"。演示时可由管理员复制该邀请链接,经团队已有的可信沟通方式交给对应成员;链接含邀请令牌,不放公开文章或截图。

邀请邮件是另一条交付路径,需要配置自己的SMTP或Postmark。未配置邮件时,不能把"邀请记录已创建"写成"邮件已送达"。密码找回等邮件流程也要单独准备。这里采用指定邮箱的邀请注册,不虚构一个通用DISABLE_REGISTRATION环境变量。

第二个人在自己的电脑建立同样的SSH隧道,再用邀请链接设置独立账号。用无痕窗口或另一台电脑区分会话,不共用所有者密码。

5. 用一页新人手册检查协作与附件

新建"入职手册"空间,把第二位成员加入空间并授予Can Edit。工作区成员身份和空间可编辑权限应分别检查;Owner或Admin不是普通协作成员的默认选择。

在空间内新建页面,写入账号申请步骤和一张待办表。第一人补文字,第二人改一条步骤,并对一段内容添加评论,核对另一端是否同步。编辑器可通过/选择文件附件,上传一个无敏感信息的小样本,再由第二个账号下载并核对内容。

离开页面后重新登录,确认文字、评论和附件都可访问。后续做容器重建验证时保留三个卷;docker compose down -v会删除相关命名卷,不能当作日常重启命令。

如果页面能读但实时编辑异常,排查WebSocket链路。日后开放团队公网访问时,应另配HTTPS反向代理、正确外部APP_URL及WebSocket转发;本例的SSH访问不替代这些部署工作。

6. 把页面导出和实例备份分开

Markdown或HTML导出适合迁移、阅读与交接,按需要勾选包含附件;它不等于完整保存账号、权限和运行配置的实例备份。只备份PostgreSQL也可能留下附件引用,却缺少本地文件本体。

完整备份至少覆盖数据库逻辑备份、附件卷、Compose及受保护的密钥配置,并记录应用和数据库版本。选择维护窗口暂停应用写入,协调数据库与附件的一致性;Redis队列的保留或重建要有明确策略,AOF本身也不是异地备份。

恢复先在隔离环境进行:还原数据库和对应附件、使用正确密钥与配置,再检查两个账号、空间权限、页面及文件。验收通过后再考虑切换入口;不能只以容器Running宣布恢复成功。

本文范围是开源版核心文档协作。AI、SSO、审计及其他商业功能有单独授权条件,不能因镜像已启动就默认具备。完成部署时,留下四项实际记录:独立登录、双人编辑、附件取回、备份恢复;尚未验证的项目继续标为待验证。

相关推荐
VidDown1 小时前
上线三个月后的第一次事故:一个 Django 服务的日志、监控与故障复盘
数据库·python·django·wpf·音视频·视频编解码
小蒜学长1 小时前
基于Springboot+Vue的高校教师教学业绩综合管理系统的设计与开发(代码+数据库+LW)
java·数据库·spring boot·后端·教学业绩管理·三级权限
达梦数据1 小时前
DMDDB如何兼容 MongoDB
数据库·mongodb
蓝胖的四次元口袋1 小时前
Redis知识梳理(5)
数据库·redis·缓存
用户302822530681 小时前
你的 API 只返回 30 条,为什么数据库还是被打满了?
数据库·后端·架构
用户713874229001 小时前
一文读懂 AWS IAM:从工牌、钥匙到统一登录
数据库
cg.family1 小时前
K8S:scale 与 delete pod 核心区别
运维·docker·容器
tryxr1 小时前
如何优化sql
java·数据库·sql·数据库优化