会议纪要、发布清单和排错记录,经常需要几个人同时补内容。把 Markdown 文件来回发送,容易出现多个“最终版”;每个人只改自己的本地文件,又很难知道其他人正在写哪里。HedgeDoc 提供浏览器里的协作编辑和预览,适合临时共写,也可以作为小团队的长期文档入口。
协作页能打开,不代表权限已经合理。文档是否可以匿名读取、访客能否编辑、上传附件是否可被公开取到,这些都需要在部署时决定。本文按有账号的小团队使用来设置,初始文档采用私人权限,不直接搭一个任何人都能创建笔记的开放实例。
部署前先确认 VPS 的磁盘、内存和公网访问条件,也可以查看雨云云服务器;注册时填写优惠码 KuZhuJi。
文本和上传文件是两份数据
HedgeDoc 的笔记及相关应用数据在数据库里,上传图片使用另一处持久存储。只备份 PostgreSQL,文档中的图片仍可能丢;只拷贝上传目录,也不会得到笔记正文和用户信息。

正式入口采用 HTTPS,应用通过内部网络连接数据库,数据库没有公网映射。两处数据都纳入备份,恢复时按同一份记录核对。
官方 Docker 文档目前提供 quay.io/hedgedoc/hedgedoc:1.12.0。下面是新实例示例,采用独立 PostgreSQL 17,使用该主版本的 /var/lib/postgresql/data 持久路径。换成 PostgreSQL 18 或更高版本时,先核对对应镜像的目录规则,不能只改一个数字继续沿用挂载。
密码先生成,域名先确定
需要已有 Docker Compose,并为应用准备一个域名,例如 docs.example.com。本文正式配置假定域名和 HTTPS 反向代理可以接到宿主机 3005;域名尚未就绪时,不要通过临时地址创建正式分享链接。
mkdir -p ~/services/hedgedoc
cd ~/services/hedgedoc
umask 077
printf 'HEDGEDOC_DB_PASSWORD=%s\n' "$(openssl rand -hex 24)" > .env
printf 'HEDGEDOC_SESSION_SECRET=%s\n' "$(openssl rand -hex 32)" >> .env
chmod 600 .env
数据库密码生成十六进制值,放进连接 URL 时不会产生需要额外编码的特殊字符。会话密钥用于应用会话,保存后持续使用,不在每次更新时重新生成。它和数据库密码用途不同,也不作为用户登录密码。
保存 compose.yaml,把 CMD_DOMAIN 改成实际域名:
services:
database:
image: postgres:17-alpine
environment:
POSTGRES_USER: hedgedoc
POSTGRES_DB: hedgedoc
POSTGRES_PASSWORD: ${HEDGEDOC_DB_PASSWORD:?fill database password}
volumes:
- database:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U hedgedoc -d hedgedoc"]
interval: 10s
timeout: 5s
retries: 10
restart: unless-stopped
app:
image: quay.io/hedgedoc/hedgedoc:1.12.0
environment:
CMD_DB_URL: postgres://hedgedoc:${HEDGEDOC_DB_PASSWORD}@database:5432/hedgedoc
CMD_DOMAIN: docs.example.com
CMD_PROTOCOL_USESSL: "true"
CMD_URL_ADDPORT: "false"
CMD_SESSION_SECRET: ${HEDGEDOC_SESSION_SECRET:?fill session secret}
CMD_EMAIL: "true"
CMD_ALLOW_EMAIL_REGISTER: "true"
CMD_ALLOW_ANONYMOUS: "false"
CMD_ALLOW_ANONYMOUS_EDITS: "false"
CMD_DEFAULT_PERMISSION: private
CMD_ENABLE_UPLOADS: registered
volumes:
- uploads:/hedgedoc/public/uploads
ports:
- "127.0.0.1:3005:3000"
depends_on:
database:
condition: service_healthy
restart: unless-stopped
volumes:
database:
uploads:
官方应用支持本地邮件地址形式的账号登录,这里的 CMD_EMAIL 与 SMTP 发信配置不是一回事。首次临时允许账号注册,用于建立成员账号;账号准备好以后关闭注册。数据库由 Compose 网络内连接,不需要把 5432 映射出来。
docker compose config --quiet
docker compose up -d
docker compose logs --tail=100 app
反向代理要同时处理 HTTP 与 WebSocket
反向代理的上游是 127.0.0.1:3005。浏览器看到的是 HTTPS,因此应用的域名、SSL 和端口设置也对应正式入口。代理应支持 WebSocket,并保留正确的转发头,否则页面可能能打开,但多人实时编辑不能正常同步。
上线初期限制入口到维护者可访问的范围,再注册所需账号。创建好以后将 CMD_ALLOW_EMAIL_REGISTER 改为 "false",执行 docker compose up -d,退出登录检查注册入口及实际行为。管理员后续添加用户时按官方账户管理说明处理,不需要再次长期打开公共注册。

这是官方仓库提供的早期界面截图,展示源文本和预览并排的工作方式。截图来自旧版示例,当前版本的按钮位置和登录方式可能不同,部署以对应版本的配置说明为准。
准备一份无敏感内容的测试笔记,写标题、列表和代码块,刷新页面后确认内容还在。上传一张普通图片,检查预览和图片地址。再退出登录访问笔记,核对私人默认权限是否按预期限制。
准备独立实例时,可在雨云选择适合的云服务器配置,优惠码 KuZhuJi。配置按实际任务选择,数据库和附件另做备份。
用两个账号测试协作,不用两个管理员窗口
成员 A 创建文档,按当前权限选项给文档设置适合协作的范围;成员 B 通过自己的账号打开。两个人在不同段落输入内容,检查文本同步、预览和重新加载后的结果。不要直接给访客开放编辑来掩盖账号或代理的问题。
HedgeDoc 的权限名称有各自含义,私人、仅登录者编辑和访客可编辑不是同一个选项。实际选择前查看当前版本的说明,并用匿名窗口和另一个普通账号测试读写。默认私人只是起点,之后人为更改了单份文档权限,仍要单独检查。
匿名编辑关闭也不等于每份文档都不能公开阅读。准备对外发布的文档,先去掉内部主机名、凭据和未公开信息,再确认阅读范围。协作页 URL 可以被复制传播,不应将难猜的路径当作完整的身份认证。
图片上传成功以后,还要验证访问边界
文档权限和附件 URL 的访问规则可能不同。对含有敏感信息的图片,用无痕窗口直接打开它的地址,确认实际结果后再决定是否适合上传。不能因为正文是私人文档,就默认附件本身一定受同样的登录保护。
本文使用本地 uploads 卷,避免把存储参数同时混进首次部署。需要对象存储时,再根据当前版本支持的方式配置,并重新验证 URL、上传、删除和备份。改变存储后,旧附件的路径和可访问性也要处理,不能只测试一张新图。
团队还应约定文档的用途。会议共写时先记录议题、结论和待确认内容,结束后整理出负责人与日期;临时排错页完成后归档,避免后来的读者把未验证的猜测当成结论。文档系统保存内容,不会自动替你判定哪一段已经确认。
需要增加服务器时,可以打开雨云选购页面,填写优惠码 KuZhuJi;迁移前保留数据与原有部署配置。
同步编辑不能代替外部备份
备份前暂停应用写入,再导出数据库并保存 uploads。数据库容器继续运行以便导出;文件命令在同一 Compose 目录执行。
mkdir -p backups
docker compose stop app
docker compose exec -T database pg_dump -U hedgedoc -d hedgedoc -Fc > "backups/hedgedoc-db-$(date +%F-%H%M%S).dump"
docker compose run --rm --no-deps --entrypoint sh app -c 'tar -C /hedgedoc/public/uploads -czf - .' > "backups/hedgedoc-uploads-$(date +%F-%H%M%S).tar.gz"
docker compose start app
上传目录可能由应用运行用户持有。这里使用原应用镜像读自己的挂载,避免在宿主机猜 Docker 卷路径。运行前确认备份目录有足够空间;命令失败时不要把一个空文件当作成功备份,检查返回状态、文件大小以及压缩包清单。
将这一轮数据库导出、附件包、Compose、.env 和对应镜像版本记录放在一起,标明同一备份时间段,再转移到受保护的外部存储。不要把 .env 作为公开文档附件上传回这个实例。
恢复时先在独立目录验收
测试实例使用独立的 Compose 项目名、卷和回环端口,保持备份对应的应用与 PostgreSQL 版本。数据库恢复完成、附件解包并确认属主后,再启动应用;具体数据库导入操作按导出格式使用 PostgreSQL 工具,不把自定义格式 dump 当普通 SQL 文本直接执行。
验收时使用两个普通账号检查文档正文、协作、私人权限和附件。新旧实例不要同时指向同一数据库或 uploads 目录。升级同样先在副本完成迁移和验证;如果新版本已经修改数据库,回退需要升级前的数据库及附件副本一起恢复,而不只是换回旧镜像。











