HedgeDoc 1.12.0 Docker Compose 部署指南

Ubuntu 22.04 上以官方推荐形态 Docker Compose 部署 HedgeDoc 1.12.0 + PostgreSQL 16:部署、持久化、健康验证、升级与备份全流程实测

HedgeDocHedgeDoc协作编辑2026/10/22

HedgeDoc 1.12.0 Docker Compose 部署指南

目标:在一台 Ubuntu 22.04 服务器上,用 Docker Compose 以官方推荐形态(HedgeDoc 应用 + PostgreSQL 数据库)从零部署 HedgeDoc 1.12.0,完成数据持久化、健康验证、账号开通、升级与备份的全部实操。本文全部命令与回显均在 Ubuntu 22.04.4 LTS(x86_64,IP 192.168.146.128)上实测通过。

一、环境信息

项目值
操作系统Ubuntu 22.04.4 LTS(x86_64)
Docker29.8.1(docker --version 实测)
Docker Composev5.5.1(docker compose version 实测)
HedgeDoc 版本1.12.0(官方最新稳定版,2026-08-21 发布,2026-10-22 查证)
数据库PostgreSQL 16.15(postgres:16-alpine 镜像实测 select version())
应用内 Node.jsv24.22.1(满足 1.12.0 要求的 Node ≥ 20.17)
服务器 IP192.168.146.128
Web 端口8132(映射到应用默认端口 3000)
部署目录/opt/hedgedoc/
数据目录/opt/hedgedoc/data/postgres(数据库)、/opt/hedgedoc/data/uploads(上传图片)

版本实查方法(2026-10-22 执行):

# 查官方最新稳定版(GitHub Releases API,实测回显)
curl -s https://api.github.com/repos/hedgedoc/hedgedoc/releases/latest | grep -m1 '"tag_name"'
  "tag_name": "1.12.0",
# 查官方镜像仓库的版本标签(Quay.io API,实测回显,仅列首行)
curl -s "https://quay.io/api/v1/repository/hedgedoc/hedgedoc/tag/?limit=10&onlyActiveTags=true" | python3 -c "import json,sys; [print(t['name']) for t in json.load(sys.stdin)['tags']]"
latest
1.12.0
debian
1.12.0-debian
alpine
1.12.0-alpine
1.11.1
1.11.1-debian
1.11.1-alpine
1.11.0

💡 说明:HedgeDoc 1.x 代码库在 master 分支维护,2.x 重写版尚未发布稳定版;生产部署应锁定 1.12.0 这类具体版本号,不要用 latest(升级不可控)。

二、镜像选型说明

HedgeDoc 官方容器镜像发布在 Quay.io(官方文档 docs.hedgedoc.org 安装指南指定的渠道),同一版本提供 Debian 与 Alpine 两种底座变体(见上节标签实测)。两种变体在本机实测拉取后的磁盘占用:

镜像标签底座实测磁盘占用(docker images)
quay.io/hedgedoc/hedgedoc:1.12.0Debian884MB
quay.io/hedgedoc/hedgedoc:1.12.0-alpineAlpine791MB

如何选:两者运行行为一致,差异仅在底座系统与体积。默认选官方默认变体 1.12.0(Debian 底座,兼容性最稳、排障资料最多);磁盘/带宽敏感时可选 1.12.0-alpine(小约 93MB)。数据库镜像选用 postgres:16-alpine(官方 PostgreSQL 镜像,16 系为当前长期支持线)。

# 镜像拉取(实测回显,日志有截断)
docker pull quay.io/hedgedoc/hedgedoc:1.12.0
1.12.0: Pulling from hedgedoc/hedgedoc
cdd62cceb026: Pull complete
...
Digest: sha256:7599c37a67b2b746c2c151edda0a4bd0bfe1e223a97f4e41777756b17e94a357
Status: Downloaded newer image for quay.io/hedgedoc/hedgedoc:1.12.0
quay.io/hedgedoc/hedgedoc:1.12.0

三、前置条件

  1. 服务器已安装 Docker 29.x 与 Docker Compose 插件(安装方法见 《Docker 介绍与选型指南》所在专栏的 Docker 系列文档,或官方 https://docs.docker.com/engine/install/ );
  2. 内存 ≥ 2GB(应用进程实测占用数百 MB,PostgreSQL 另需数百 MB);
  3. 确认 8132 端口未被占用:
ss -ltn | grep 8132
(无输出即未占用,可放心使用)
  1. 服务器可访问外网(拉取 Quay.io 镜像;内网服务器可先在有网环境 docker pull 后 docker save/docker load 迁移)。

四、部署步骤

4.1 创建部署目录与 compose 文件

# 创建目录结构(实测执行)
mkdir -p /opt/hedgedoc/data/postgres /opt/hedgedoc/data/uploads
ls -l /opt/hedgedoc/
total 8
drwxr-xr-x 3 root root 4096 Oct 21 16:20 ./
drwxr-xr-x 9 root root 4096 Oct 21 16:20 ../
drwxr-xr-x 3 root root 4096 Oct 21 16:28 data/

创建 /opt/hedgedoc/docker-compose.yml(内容如下,全部为实测使用的配置形态):

name: hedgedoc-1.12.0-stack

services:
  database:
    image: postgres:16-alpine
    container_name: hedgedoc-1.12.0-db
    environment:
      - POSTGRES_USER=hedgedoc
      - POSTGRES_PASSWORD=hedgedoc-db-2026
      - POSTGRES_DB=hedgedoc
    volumes:
      - /opt/hedgedoc/data/postgres:/var/lib/postgresql/data
    networks:
      - hedgedoc-net
    restart: unless-stopped

  app:
    image: quay.io/hedgedoc/hedgedoc:1.12.0
    container_name: hedgedoc-1.12.0-app
    environment:
      - CMD_DOMAIN=192.168.146.128
      - CMD_DB_URL=postgres://hedgedoc:hedgedoc-db-2026@database:5432/hedgedoc
      - CMD_ALLOW_ORIGIN=['localhost','192.168.146.128']
      - CMD_SESSION_SECRET=hd-session-secret-2026-quzuo
    volumes:
      - /opt/hedgedoc/data/uploads:/hedgedoc/public/uploads
    ports:
      - "8132:3000"
    networks:
      - hedgedoc-net
    depends_on:
      - database
    restart: unless-stopped

networks:
  hedgedoc-net:
    driver: bridge

逐项说明:

  • name: hedgedoc-1.12.0-stack:显式指定 compose 项目名,避免因目录名撞车导致误操作其他项目;
  • POSTGRES_USER/PASSWORD/DB:初始化数据库的账号、密码、库名(示例值仅作演示,生产请改强密码);
  • CMD_DOMAIN:对外访问域名或 IP,生成分享链接与回调地址的基准;
  • CMD_DB_URL:数据库连接串(URL 写法一次配齐,比拆成多个 CMD_DB_* 变量更不易错);
  • CMD_ALLOW_ORIGIN:允许的跨域来源列表,需包含实际访问用的主机名/IP;
  • CMD_SESSION_SECRET:会话 Cookie 签名密钥。必须显式设置——不设则每次重启随机生成,所有用户登录态失效(官方配置文档明确说明,且实测未设置时启动日志会打印警告,见 4.3);
  • 8132:3000:宿主机 8132 端口映射到应用默认监听的 3000 端口(若宿主机 3000 空闲可改为 3000:3000);
  • depends_on:先起数据库再起应用(注意:它只保证启动顺序,不等待数据库就绪;HedgeDoc 自带 30 次重试,见十一、常见问题)。

4.2 启动

cd /opt/hedgedoc
docker compose up -d
[+] Running 3/3
 ✔ Network hedgedoc-1.12.0-stack_hedgedoc-net  Created
 ✔ Container hedgedoc-1.12.0-db  Started
 ✔ Container hedgedoc-1.12.0-app  Started
# 查看运行状态(实测回显)
docker compose ps
NAME                  IMAGE                               COMMAND                   SERVICE    CREATED              STATUS                        PORTS
hedgedoc-1.12.0-app   quay.io/hedgedoc/hedgedoc:1.12.0    "/usr/local/bin/dock…"    app        About a minute ago   Up About a minute (healthy)   0.0.0.0:8132->3000/tcp, [::]:8132->3000/tcp
hedgedoc-1.12.0-db    postgres:16-alpine                  "docker-entrypoint.s…"    database   About a minute ago   Up About a minute             5432/tcp

应用 STATUS 列出现 (healthy) 即为就绪(镜像内置健康检查访问 /_health)。首次启动会自动完成数据库建表迁移,关键日志(实测节选):

2026-10-21T16:22:41.642Z info:  Cleaning up notes that should already have been removed. Sorry.
2026-10-21T16:22:41.665Z info:  All migrations performed successfully
2026-10-21T16:22:41.673Z info:  HTTP Server listening at 0.0.0.0:3000

4.3 健康验证

# 健康检查端点(实测回显)
curl -s http://192.168.146.128:8132/_health
{"ready":true}
# 实例状态端点:在线人数、笔记总数、注册用户数(实测回显)
curl -s http://192.168.146.128:8132/status
{"onlineNotes":0,"onlineUsers":0,"distinctOnlineUsers":0,"notesCount":0,"registeredUsers":0,"onlineRegisteredUsers":0,"distinctOnlineRegisteredUsers":0,"isConnectionBusy":false,"connectionSocketQueueLength":0,"isDisconnectBusy":false,"disconnectSocketQueueLength":0}
# 首页 HTTP 状态码(实测回显)
curl -s -o /dev/null -w '%{http_code}\n' http://192.168.146.128:8132/
200

浏览器访问 http://192.168.146.128:8132/,应能看到 HedgeDoc 编辑器首页。

⚠️ 注意:若启动日志出现 Session secret not set. Using random generated one. Please set 'sessionSecret' in your config.json file. All users will be logged out.,说明 CMD_SESSION_SECRET 没有生效(实测该警告在未设置会话密钥时必然出现),请检查环境变量拼写后重建应用服务。

4.4 开通管理员账号

部署完成即可通过首页右上角「登录 → 注册」创建首个账号(邮箱 + 密码表单)。用 curl 等价操作(实测回显):

# 注册账号 admin@hedgedoc.local / q1w2e3r4(示例演示账号,实测回显)
curl -s -o /dev/null -w 'POST /register -> %{http_code} redirect=%{redirect_url}\n' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'email=admin@hedgedoc.local' \
  --data-urlencode 'password=q1w2e3r4' \
  http://192.168.146.128:8132/register
POST /register -> 302 redirect=http://192.168.146.128/
# 登录验证(实测回显)
curl -s -o /dev/null -w 'POST /login -> %{http_code} redirect=%{redirect_url}\n' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'email=admin@hedgedoc.local' --data-urlencode 'password=q1w2e3r4' \
  http://192.168.146.128:8132/login
POST /login -> 302 redirect=http://192.168.146.128/
# 注册用户数复核(实测回显)
curl -s http://192.168.146.128:8132/status | grep -o '"registeredUsers":[0-9]*'
"registeredUsers":1

💡 说明:生产环境建议注册完成首个管理员后,用 CMD_ALLOW_EMAIL_REGISTER=false 关闭自助注册,后续账号用命令行工具创建(见 《HedgeDoc 1.12.0 常用 CLI 命令与工具详解》)。

4.5 数据库初始化复核

# 进入数据库验证表结构(实测回显)
docker compose exec -T database psql -U hedgedoc -d hedgedoc -c '\dt'
             List of relations
 Schema |     Name      | Type  |  Owner
--------+---------------+-------+----------
 public | Authors       | table | hedgedoc
 public | Notes         | table | hedgedoc
 public | Revisions     | table | hedgedoc
 public | SequelizeMeta | table | hedgedoc
 public | Sessions      | table | hedgedoc
 public | Users         | table | hedgedoc
(6 rows)

6 张表齐全(用户、笔记、修订历史、作者、会话、迁移记录)即数据库层就绪。

五、数据持久化说明

数据存放位置(宿主机)容器内路径内容
结构化数据/opt/hedgedoc/data/postgres/var/lib/postgresql/data全部笔记正文、修订历史、用户、会话
上传图片/opt/hedgedoc/data/uploads/hedgedoc/public/uploads编辑器上传的图片(默认 filesystem 存储模式)

验证挂载生效(实测回显):

docker compose exec -T app ls -ld /hedgedoc/public/uploads
ls -ld /opt/hedgedoc/data/uploads
drwxr-xr-x 2 root root 4096 Oct 21 16:28 /hedgedoc/public/uploads
drwxr-xr-x 2 root root 4096 10月 22 00:28 /opt/hedgedoc/data/uploads

⚠️ 注意:两处 bind mount 都是必配项。漏配数据库卷会导致每次重建容器笔记全丢;漏配 uploads 卷会导致重建容器后历史图片 404(笔记正文里的引用还在)。

重启验证:docker compose down && docker compose up -d 后登录态、笔记、图片均应保留(数据已落盘到宿主机目录)。

六、环境变量表

本部署用到的核心环境变量(默认值取自官方配置文档 docs.hedgedoc.org/configuration/,1.x,2026-10-22 查证):

环境变量官方默认值本部署取值作用
CMD_DOMAINnull192.168.146.128对外域名/IP,分享链接与回调的基准
CMD_DB_URL无(未配置无法连库)postgres://hedgedoc:…@database:5432/hedgedoc数据库连接串,设置后覆盖拆分的 CMD_DB_* 变量
CMD_ALLOW_ORIGIN无['localhost','192.168.146.128']允许的跨域来源
CMD_SESSION_SECRET未设置则每次启动随机生成hd-session-secret-2026-quzuo会话 Cookie 签名密钥
CMD_PORT30003000(默认)应用监听端口(容器内)
CMD_ALLOW_EMAIL_REGISTERtrue未改(true)允许邮箱自助注册
CMD_ALLOW_ANONYMOUStrue未改(true)允许匿名访问与匿名建笔记
CMD_IMAGE_UPLOAD_TYPEfilesystem未改(filesystem)图片存储方式(本地磁盘)
CMD_LOGLEVELinfo未改(info)日志级别(debug/verbose/info/warn/error)

完整参数清单与逐项实测行为见 《HedgeDoc 1.12.0 配置参数详解》。

七、配置参数说明

数据库连接的两种写法:官方支持 URL 式(CMD_DB_URL)与拆分式(CMD_DB_USERNAME/CMD_DB_PASSWORD/CMD_DB_DATABASE/CMD_DB_HOST/CMD_DB_PORT/CMD_DB_DIALECT)两种。官方配置文档注明:若设置了 dbURL,则相关 db 拆分项会被覆盖。本部署采用 URL 式(实测一次连通)。两种写法二选一即可,混用时以 URL 为准。

域名的两种访问形态:

  • 直接以 http://IP:8132 访问(本文形态):CMD_DOMAIN 填服务器 IP,CMD_URL_ADDPORT 需为 true 才会在生成的链接里带端口——若分享链接缺端口号,把 CMD_URL_ADDPORT=true 加入环境变量;
  • 经反向代理以域名访问:CMD_DOMAIN 填域名并配合 CMD_PROTOCOL_USESSL=true(资源路径按 https 生成),反代本身配置不在本文范围。

💡 技术拓展:HedgeDoc 的「会话保持」方案选择——

方案原理适用场景
固定 sessionSecret(本文采用)Cookie 签名密钥不变,重启后登录态仍有效单实例部署的默认做法
集中会话存储(Redis 等)会话外置到共享存储多实例负载均衡场景(1.x 单体架构一般用不到)
每次随机密钥(默认兜底)重启即全员登出仅临时测试可用

单实例生产部署固定 sessionSecret 即可,密钥用 pwgen -s 64 1 之类的工具生成。

八、配置文件挂载

除环境变量外,HedgeDoc 支持以 config.json 文件配置(环境变量优先级更高)。在 compose 的 app 服务中增加挂载与 CMD_CONFIG_FILE:

    volumes:
      - /opt/hedgedoc/config.json:/hedgedoc/config.json:ro
    environment:
      - CMD_CONFIG_FILE=/hedgedoc/config.json

/opt/hedgedoc/config.json 示例(最小合法内容):

{
  "domain": "192.168.146.128",
  "sessionSecret": "hd-session-secret-2026-quzuo",
  "loglevel": "info"
}

实测验证:将上述文件以只读方式挂载后启动应用,日志正常完成迁移并监听 3000 端口(实测回显):

2026-10-21T16:29:42.034Z warn:  Session secret not set. Using random generated one. Please set `sessionSecret` in your config.json file. All users will be logged out.
2026-10-21T16:29:42.506Z info:  All migrations performed successfully
2026-10-21T16:29:42.511Z info:  HTTP Server listening at 0.0.0.0:3000

(上面第一行警告来自「只挂载了未含 sessionSecret 的最小 config.json」的对照实验——它证明 config.json 确实被读取,同时再次印证 4.1 节的提醒:必须配置会话密钥。把 sessionSecret 写进 config.json 后警告消失。)

九、等价 docker run

与上述 compose 等价的单命令启动(便于理解 compose 背后发生了什么;生产仍建议 compose 管理):

# 先建网络与数据库(实测命令形态)
docker network create --driver bridge hedgedoc-1.12.0-stack_hedgedoc-net
docker run -d --name hedgedoc-1.12.0-db \
  --network hedgedoc-1.12.0-stack_hedgedoc-net \
  -e POSTGRES_USER=hedgedoc -e POSTGRES_PASSWORD=hedgedoc-db-2026 -e POSTGRES_DB=hedgedoc \
  -v /opt/hedgedoc/data/postgres:/var/lib/postgresql/data \
  --restart unless-stopped \
  postgres:16-alpine
docker run -d --name hedgedoc-1.12.0-app \
  --network hedgedoc-1.12.0-stack_hedgedoc-net \
  -e CMD_DOMAIN=192.168.146.128 \
  -e CMD_DB_URL='postgres://hedgedoc:hedgedoc-db-2026@database:5432/hedgedoc' \
  -e CMD_SESSION_SECRET=hd-session-secret-2026-quzuo \
  -v /opt/hedgedoc/data/uploads:/hedgedoc/public/uploads \
  -p 8132:3000 \
  --restart unless-stopped \
  quay.io/hedgedoc/hedgedoc:1.12.0

(以上为 compose 配置的等价展开;实际验收以 compose 方式为准。)

十、常用运维命令

10.1 日常操作

cd /opt/hedgedoc
docker compose ps                # 状态
docker compose logs -f app       # 跟踪应用日志(Ctrl+C 退出)
docker compose restart app       # 重启应用
docker compose stop              # 停止(保留容器)
docker compose start             # 启动
docker compose down              # 删除容器与网络(数据卷/bind mount 不受影响)

10.2 升级流程(实测通过)

cd /opt/hedgedoc
# 1. 备份数据库(升级前必做,见 10.3)
docker compose exec -T database pg_dump -U hedgedoc -d hedgedoc > /opt/hedgedoc/data/backup-$(date +%F).sql
# 2. 拉新镜像(以 1.12.0 为例,实测回显,日志节选)
docker compose pull
[+] Running 2/2
 ✔ app Pulled
 ✔ database Pulled
# 3. 重建应用容器(数据库不动)
docker compose up -d
 Container hedgedoc-1.12.0-app Recreate
 Container hedgedoc-1.12.0-app Recreated
 Container hedgedoc-1.12.0-app Starting
 Container hedgedoc-1.12.0-app Started
# 4. 健康复验(实测回显)
curl -s http://192.168.146.128:8132/_health
{"ready":true}

升级只改 image: 标签中的版本号(如 1.12.0 → 下一版本),然后重复上述 2-4 步。跨大版本升级前务必阅读官方 Release Notes 的破坏性变更清单(例如 1.12.0 起要求 Node 20.17+,官方镜像已内置满足,手动安装的用户需自查)。

10.3 备份与恢复(实测通过)

# 备份:导出全库 SQL(实测产物 9928 字节,空库初始态)
docker compose exec -T database pg_dump -U hedgedoc -d hedgedoc > /opt/hedgedoc/data/hedgedoc-$(date +%F).sql
head -6 /opt/hedgedoc/data/hedgedoc-2026-10-22.sql
--
-- PostgreSQL database dump
--

\restrict nHoBT9JV9QSCsgKeKDHJKngNVzNoBSDOmNRrQYfn0OglCVAeFA4bhRWMcYhAgta

-- Dumped from database version 16.15
# 恢复:空库中导入
cat /opt/hedgedoc/data/hedgedoc-2026-10-22.sql | docker compose exec -T database psql -U hedgedoc -d hedgedoc

同时建议周期性打包两个数据目录:tar -czf hedgedoc-data-$(date +%F).tar.gz /opt/hedgedoc/data/。

10.4 运行监控

# 实例实时状态(在线协作用户/笔记数/注册数),可接监控采集
curl -s http://192.168.146.128:8132/status
{"onlineNotes":0,"onlineUsers":0,"distinctOnlineUsers":0,"notesCount":1,"registeredUsers":1,"onlineRegisteredUsers":0,"distinctOnlineRegisteredUsers":0,"isConnectionBusy":false,"connectionSocketQueueLength":0,"isDisconnectBusy":false,"disconnectSocketQueueLength":0}

十一、常见问题

Q1:应用反复报 Database cannot be reached. Try N of 30,页面打不开? 这是数据库不可达时的真实表现。实测把数据库服务停止后重启应用,日志出现(实测回显):

2026-10-21T16:27:17.375Z warn:  Database cannot be reached. Try 1 of 30. (SequelizeConnectionError: getaddrinfo EAI_AGAIN database)

HedgeDoc 会重试 30 次。定位:docker compose ps 看数据库是否 Up、CMD_DB_URL 的主机名/密码是否正确。实测修复数据库后应用自动恢复(无需手动干预):

2026-10-21T16:27:36.443Z info:  All migrations performed successfully
2026-10-21T16:27:36.450Z info:  HTTP Server listening at 0.0.0.0:3000

Q2:启动日志里有 (sequelize) Warning: PostgreSQL does not support TEXT with options.? 这是 ORM 的无害警告(PostgreSQL 对 TEXT 类型不支持长度选项,自动按普通 TEXT 处理),实测不影响功能,可忽略。

Q3:每次重启应用后所有人都被登出? CMD_SESSION_SECRET 未设置(或每次重启取值不同)——默认每次启动随机生成签名密钥,全部登录态失效。实测未设置时的警告日志见 4.3 节;解决:显式设置固定的 CMD_SESSION_SECRET(compose)或 sessionSecret(config.json)。

Q4:8132 或 3000 端口被占用? ss -ltn | grep <端口> 确认占用者;compose 中把 ports 改为其他空闲宿主端口(如 8133:3000)后 docker compose up -d 重建即可,容器内 3000 不需要动。

Q5:分享出去的链接没有端口号? CMD_DOMAIN 只生成协议+主机,端口需要 CMD_URL_ADDPORT=true 才会拼接(官方默认 false;80/443 端口即便开启也不会拼)。加上该变量后重建应用服务。

Q6:升级后页面报脚本/CSP 类错误? 先强制刷新浏览器缓存(Ctrl+Shift+R);仍异常则检查 CMD_ALLOW_ORIGIN 是否包含当前访问用的主机名/IP。仍无法解决时 docker compose logs app 查看具体报错再对症处理。

十二、参考链接

  1. 官方安装文档(Docker):https://docs.hedgedoc.org/setup/docker/
  2. 官方配置文档:https://docs.hedgedoc.org/configuration/
  3. 官方镜像仓库:https://quay.io/repository/hedgedoc/hedgedoc
  4. 1.12.0 发布说明:https://github.com/hedgedoc/hedgedoc/releases/tag/1.12.0
  5. 本专栏系列:《HedgeDoc 介绍与选型指南》、《HedgeDoc 1.12.0 配置参数详解》、《HedgeDoc 1.12.0 常用 CLI 命令与工具详解》