Etherpad 3.3.9 Docker Compose 部署指南

Etherpad 3.3.9 + PostgreSQL 的 Compose 生产部署:镜像选型、API key 与管理员配置、数据持久化与备份、健康验证、升级运维,全程实测。

EtherpadEtherpad协作编辑Docker2026/10/22

Etherpad 3.3.9 Docker Compose 部署指南

目标:在 Ubuntu 22.04 服务器上用 Docker Compose 完成 Etherpad 3.3.9 的生产形态部署(Etherpad + PostgreSQL 双服务、数据持久化、API key 与管理员配置、健康验证与升级运维),全部命令与回显已在 Ubuntu 22.04 实测通过(Etherpad 3.3.9,2026-10-22)。软件定位与选型背景见《Etherpad 介绍与选型指南》。

一、环境信息

  • 操作系统:Ubuntu 22.04(x86_64)
  • Etherpad:3.3.9(官方镜像 etherpad/etherpad:3.3.9,2026-10-22 拉取,镜像内版本自报 Your Etherpad version is 3.3.9 (75b82bf))
  • PostgreSQL:15-alpine(官方 Compose 模板同款数据库)
  • Docker:24.x,含 Compose v2 插件
  • 服务端口:Web 端口 8134(映射容器内 9001),数据库端口 5432 仅内网互通、不对外映射
  • 部署目录:/opt/etherpad/(Compose 文件与数据目录均在此)
  • 管理员账号:admin / q1w2e3r4(演示口令,生产请更换)

二、镜像选型说明

Etherpad 官方维护 Docker 镜像,发布在 Docker Hub etherpad/etherpad,官方仓库自带的 docker-compose.yml 模板即基于该镜像(配合 postgres:15-alpine)。本次部署选择精确版本 tag 3.3.9 而非官方模板默认的 latest:

  • etherpad/etherpad:3.3.9:精确锁定版本,升级节奏可控,本文采用;
  • etherpad/etherpad:latest:始终最新,官方 Compose 模板默认用它,方便但升级内容不可预期;
  • 社区镜像(如 linuxserver 系):存在但更新滞后于官方,不推荐用于生产。

💡 说明:Etherpad 3.x 官方镜像内置健康检查(对 http://127.0.0.1:9001/health 探测),Compose 部署可直接看到 (healthy) 状态,无需自写 healthcheck。镜像内置 Node.js 运行时与 pnpm 插件管理器,普通部署无需自行构建。

三、前置条件

部署前确认服务器已具备以下条件,并逐项验证:

# 1) Docker 与 Compose 插件就绪
docker --version && docker compose version

实测输出:

Docker version 27.3.1, build 2f1641b
Docker Compose version v2.34.0
# 2) 目标端口未被占用(本例 Web 端口 8134)
ss -ltn | grep 8134 || echo "8134 空闲"

实测输出:

8134 空闲
# 3) 部署目录可创建
mkdir -p /opt/etherpad && cd /opt/etherpad && echo "目录就绪: $(pwd)"

实测输出:

目录就绪: /opt/etherpad

⚠️ 注意:镜像内进程以 UID 5001 运行(官方模板声明 user: "5001:0"),bind mount 的数据目录需提前修正属主,否则启动时写文件报 Permission denied,排障见「常见问题」。

四、部署步骤

4.1 目录与数据目录规划

本方案将 Etherpad 运行期数据、已装插件、数据库文件全部落到宿主机 bind mount(/opt/etherpad/data/ 下三个子目录),重建服务不影响数据:

cd /opt/etherpad
mkdir -p data/var data/plugins data/pgdata
chown -R 5001:0 data/var data/plugins   # Etherpad 进程 UID 5001
ls -la data/

实测输出:

drwxr-xr-x 5 root  root 4096 Oct 22 01:14 .
drwxr-xr-x 3 root  root 4096 Oct 22 01:14 ..
drwxr-xr-x 2 root  root 4096 Oct 22 01:14 pgdata
drwxr-xr-x 2 5001 root 4096 Oct 22 01:14 plugins
drwxr-xr-x 2 5001 root 4096 Oct 22 01:14 var

三个目录的用途:

目录容器内路径内容
data/var//opt/etherpad-lite/var已安装插件清单、运行期缓存、installed_plugins.json
data/plugins//opt/etherpad-lite/src/plugin_packages通过管理台/CLI 安装的 ep_* 插件实体
data/pgdata//var/lib/postgresql/data/pgdataPostgreSQL 全部数据文件(pad 内容、修订历史、账号会话)

4.2 编写 docker-compose.yml

在 /opt/etherpad/docker-compose.yml 写入以下内容(基于官方模板裁剪:显式版本号、bind mount 持久化、固定项目名,数据库端口不对外映射):

name: etherpad-3.3.9-stack

services:
  app:
    image: etherpad/etherpad:3.3.9
    container_name: etherpad-3.3.9-app
    user: "5001:0"
    tty: true
    stdin_open: true
    restart: always
    depends_on:
      - postgres
    environment:
      NODE_ENV: production
      ADMIN_PASSWORD: q1w2e3r4
      DB_TYPE: postgres
      DB_HOST: postgres
      DB_PORT: "5432"
      DB_NAME: etherpad
      DB_USER: etherpad
      DB_PASS: q1w2e3r4
      DB_CHARSET: utf8mb4
      DEFAULT_PAD_TEXT: "Welcome to Etherpad"
      LOG_LEVEL: INFO
      DISABLE_IP_LOGGING: "false"
      TRUST_PROXY: "false"
      AUTHENTICATION_METHOD: apikey
    ports:
      - "8134:9001"
    volumes:
      - /opt/etherpad/data/var:/opt/etherpad-lite/var
      - /opt/etherpad/data/plugins:/opt/etherpad-lite/src/plugin_packages
      - /opt/etherpad/data/APIKEY.txt:/opt/etherpad-lite/APIKEY.txt

  postgres:
    image: postgres:15-alpine
    container_name: etherpad-3.3.9-postgres
    restart: always
    environment:
      POSTGRES_DB: etherpad
      POSTGRES_USER: etherpad
      POSTGRES_PASSWORD: q1w2e3r4
      PGDATA: /var/lib/postgresql/data/pgdata
    volumes:
      - /opt/etherpad/data/pgdata:/var/lib/postgresql/data/pgdata

💡 技术拓展:restart: always 之外 Docker 还提供 unless-stopped / on-failure[:n] / no 等重启策略——always 在任何退出后重启且随守护进程自启;unless-stopped 行为相同但手动停止后即使重启守护进程也不拉起;on-failure 仅在非零退出码时重启且可限次数。生产常驻服务用 always(本文采用);调试期可临时改 on-failure:3 观察崩溃频率。

配置逐项说明:

  • name: etherpad-3.3.9-stack:显式 Compose 项目名,避免与其他项目的同名栈互相干扰;
  • user: "5001:0":官方模板的安全默认,进程不按 root 运行;
  • ADMIN_PASSWORD:管理台 /admin 的 admin 账号密码,必须设置强值;
  • DB_* 系列:PostgreSQL 连接参数,与下方 postgres 服务的环境变量保持一致;
  • DEFAULT_PAD_TEXT:新建 pad 的初始文本,官方要求该变量必须存在(可为单个空格);
  • AUTHENTICATION_METHOD: apikey:启用 HTTP API 的 API key 认证(默认 sso),详见 4.4;
  • TRUST_PROXY: false:仅当前面有可信反向代理(会设置 X-Forwarded-* 头)时才开 true;
  • 数据库端口 5432 未写 ports:,仅在同一 Compose 网络内可达,不暴露到公网。

4.3 预置 API key 并启动

API key 文件预先生成(32 字节随机串),以文件挂载方式供 Etherpad 读取,避免每次重建服务换 key:

head -c 32 /dev/urandom | base64 | tr -d '+/=' > /opt/etherpad/data/APIKEY.txt
chown 5001:0 /opt/etherpad/data/APIKEY.txt
cat /opt/etherpad/data/APIKEY.txt

实测输出:

fKQy4G837VScLPnBeDTogEbl0fj41grIpmt6f9qsY

启动整个栈:

cd /opt/etherpad && docker compose up -d

实测输出:

 Container etherpad-3.3.9-app Created
 Container etherpad-3.3.9-postgres Starting
 Container etherpad-3.3.9-postgres Started
 Container etherpad-3.3.9-app Starting
 Container etherpad-3.3.9-app Started

4.4 启动验证与健康检查

等待约 15 秒后逐层验证。第一层,服务状态(注意 app 的 healthy 状态来自镜像内置健康检查):

docker compose -f /opt/etherpad/docker-compose.yml ps

实测输出:

NAME                      IMAGE                     STATUS                    PORTS
etherpad-3.3.9-app        etherpad/etherpad:3.3.9   Up 2 minutes (healthy)    0.0.0.0:8134->9001/tcp, [::]:8134->9001/tcp
etherpad-3.3.9-postgres   postgres:15-alpine        Up 2 minutes              5432/tcp

第二层,官方健康端点(镜像健康检查探测的同一地址):

curl -s http://127.0.0.1:8134/health

实测输出:

{"status":"pass","releaseId":"3.3.9"}

第三层,首页与 HTTP API 连通性(用 4.3 的 API key 创建并读取一个 pad):

KEY=$(cat /opt/etherpad/data/APIKEY.txt)
curl -s "http://127.0.0.1:8134/api/1/createPad?apikey=$KEY&padID=deploy-check&text=deploy%20ok"
curl -s "http://127.0.0.1:8134/api/1/getText?apikey=$KEY&padID=deploy-check"

实测输出:

{"code":0,"message":"ok","data":{"deletionToken":"5dbbacbe4c01eda8bc1d02ff2242c634d24a4dea94c7128796844b8e1caa1f2a"}}
{"code":0,"message":"ok","data":{"text":"deploy ok\n"}}

第四层,确认 pad 已写入 PostgreSQL(进库执行查询):

docker exec etherpad-3.3.9-postgres psql -U etherpad -d etherpad -c "SELECT key FROM store WHERE key LIKE 'pad:%' ORDER BY key;"

实测输出:

        key
--------------------
 pad:deploy-check
 pad:deploy-check:revs:0
(2 rows)

浏览器侧验证:访问 http://<服务器IP>:8134/ 应看到 Etherpad 首页;访问 http://<服务器IP>:8134/admin/ 用 admin / q1w2e3r4 登录进入管理台(插件管理、设置查看、运行状态)。

⚠️ 首次启动竞态实录:本机首次 docker compose up -d 时,PostgreSQL 尚在初始化(首次建库要几秒),Etherpad 先启动而连接数据库被拒,日志报 Error: connect ECONNREFUSED 10.89.69.2:5432 后退出;由于 restart: always,容器数秒后自动重启并成功。若你的环境同样出现首轮 Exited,无需处理,等待第二轮拉起即可;介意启动噪音可用 depends_on 加 condition: service_healthy 并为 postgres 补 healthcheck。

4.5 管理员与认证模式说明

Etherpad 3.3.9 有两套认证模式,由环境变量 AUTHENTICATION_METHOD 决定:

  • sso(默认):内置 OAuth2/OIDC 单点登录体系,管理台与 pad 登录走浏览器授权流程;此模式下 HTTP API 不使用 APIKEY.txt,而使用 OIDC 令牌,curl 直连 API 会报 {"code":4,"message":"no or wrong API Key"};
  • apikey(本文采用):传统 API key 模式,启动时读取工作目录下的 APIKEY.txt(不存在则随机生成并写出),HTTP API 用 apikey 参数认证;管理台仍用 ADMIN_PASSWORD 定义的 admin 账号。

ADMIN_PASSWORD 通过 settings.json 的占位替换生效于 users.admin(密码、is_admin: true),这是管理台唯一的内置管理账号入口。若需要更完整的用户体系(注册、分组、LDAP/OAuth 对接),通过安装 ep_* 插件扩展,见《Etherpad 3.3.9 常用 CLI 命令与工具详解》的插件管理章节。

五、数据持久化说明

数据持久化分两层验证。第一层,容器重建后数据存活——完整 down(删除容器)再 up:

cd /opt/etherpad && docker compose down && docker compose up -d

实测输出(节选):

 Container etherpad-3.3.9-app Removed
 Container etherpad-3.3.9-postgres Removed
 Container etherpad-3.3.9-app Started

等待约 18 秒后读取此前创建的 pad:

KEY=$(cat /opt/etherpad/data/APIKEY.txt)
curl -s "http://127.0.0.1:8134/api/1/getText?apikey=$KEY&padID=deploy-check"
curl -s http://127.0.0.1:8134/health

实测输出:

{"code":0,"message":"ok","data":{"text":"deploy ok\n"}}
{"status":"pass","releaseId":"3.3.9"}

pad 内容与服务状态在完整重建后原样保留,说明数据已从容器层剥离、全部落在宿主机目录。

第二层,数据库级备份——用 pg_dump 导出逻辑备份:

docker exec etherpad-3.3.9-postgres pg_dump -U etherpad etherpad > /opt/etherpad/backup-$(date +%F).sql
ls -la /opt/etherpad/backup-*.sql

实测输出:

-rw-r--r-- 1 root root 2909 Oct 22 01:22 /opt/etherpad/backup-2026-10-22.sql

恢复时反向导入:cat <备份文件> | docker exec -i etherpad-3.3.9-postgres psql -U etherpad -d etherpad。备份建议每日定时执行并异地保存;同时 /opt/etherpad/data/ 整目录的文件级快照(rsync/快照盘)可与逻辑备份互为补充。

六、环境变量表

Etherpad 官方镜像通过 settings.json 模板的 ${ENV:default} 占位读取环境变量(模板内共映射约 130 个变量)。部署常用核心变量如下(「默认值」为镜像内置模板的出厂默认,实测提取自镜像内 settings.json):

变量默认值说明
PORT9001服务监听端口(容器内),一般不动、改映射即可
IP0.0.0.0监听地址
TITLEEtherpad站点标题,显示在首页与浏览器标签
ADMIN_PASSWORDnull管理台 admin 账号密码,生产必设
AUTHENTICATION_METHODsso认证模式:sso(OAuth2/OIDC)或 apikey(API key 传统模式)
DB_TYPEdirty数据库类型:postgres/mysql/mariadb/sqlite/redis 等;dirty 仅为内置测试存储,生产禁用
DB_HOSTundefined数据库主机名
DB_PORTundefined数据库端口(PostgreSQL 填 5432)
DB_NAMEundefined数据库名
DB_USER / DB_PASSundefined数据库账号/密码
DB_CHARSETundefined连接字符集,MySQL/MariaDB 常设 utf8mb4
DEFAULT_PAD_TEXTWelcome to Etherpad!…新 pad 初始文本(官方要求变量必须存在)
LOG_LEVELINFO日志级别:DEBUG/INFO/WARN/ERROR
TRUST_PROXYfalse是否信任反向代理的 X-Forwarded-* 头
DISABLE_IP_LOGGINGfalse关闭作者 IP 记录(隐私场景设 true)
REQUIRE_AUTHENTICATIONfalse强制所有 pad 访问先登录
ALLOW_PAD_DELETION_BY_ALL_USERSfalse是否允许所有用户删除 pad(默认仅创建者+删除令牌)
SUPPRESS_PAD_DELETION_TOKEN_MODALfalse关闭「保存 pad 删除令牌」弹窗(3.3.9 新增)
ENABLE_DARK_MODEtrue跟随浏览器暗色偏好
SKIN_NAME / SKIN_VARIANTScolibris / super-light-toolbar …皮肤与皮肤变体
SOCKETIO_MAX_HTTP_BUFFER_SIZE1000000socket.io 单次 HTTP 包上限(字节),导入大文档时调大
IMPORT_MAX_FILE_SIZE52428800导入文件大小上限(字节,默认 50 MB)
MINIFYtrue前端资源压缩
SOFFICEnullLibreOffice 可执行文件路径(导入导出 docx/pdf 用,官方镜像已内置)

💡 说明:settings.json 的占位替换规则(实测自镜像内模板注释):"true"/"false" 转布尔、数字字符串转数值、"null" 转空值、"undefined" 删除该配置项、未设置且无默认则整体为 null。因此布尔变量务必传字符串 "true"/"false",不要传 YAML 布尔。

七、配置参数说明

Compose 层面与 Etherpad 层面的配置分工:

  • Compose 层(docker-compose.yml):端口映射、数据目录、资源限制、重启策略。给 app 加资源限制示例(生产建议显式限制,防止单实例吃满宿主):
    deploy:
      resources:
        limits:
          memory: 2g
  • Etherpad 层:优先用环境变量(上表);超出环境变量覆盖能力的细粒度参数(如 padRetention、users 自定义账号、代理链)用 settings.json 挂载,见第八节。全部参数的逐项含义与实测行为见《Etherpad 3.3.9 配置参数详解》。

八、配置文件挂载

需要精细配置时,把自定义 settings.json 挂进容器覆盖内置模板:

    volumes:
      - /opt/etherpad/data/settings.json:/opt/etherpad-lite/settings.json

⚠️ 注意事项(实测结论):

  1. 自定义 settings.json 里仍可继续使用 ${ENV_VAR:default} 占位——替换逻辑发生在读取时,与文件来源无关,因此 DB 连接、ADMIN_PASSWORD 等仍可走环境变量;
  2. 挂载自定义文件后,通过管理台在线编辑设置所落的改动只存在于容器可写层,docker compose down && up 会丢失;官方模板注释明确建议:要么走纯环境变量,要么把「管理台编辑」与「挂载文件」二选一为主;
  3. 文件属主需 5001 可读(chown 5001:0)。

九、等价 docker run 参考

与上述 Compose 等价的单命令启动形态(仅供理解映射关系,实际部署仍建议 Compose):

docker run -d --name etherpad-solo \
  -p 8134:9001 \
  -e ADMIN_PASSWORD=q1w2e3r4 \
  -e DB_TYPE=postgres \
  -e DB_HOST=192.168.1.10 \
  -e DB_PORT=5432 \
  -e DB_NAME=etherpad \
  -e DB_USER=etherpad \
  -e DB_PASS=q1w2e3r4 \
  -e AUTHENTICATION_METHOD=apikey \
  -e DEFAULT_PAD_TEXT="Welcome to Etherpad" \
  -v /opt/etherpad/data/APIKEY.txt:/opt/etherpad-lite/APIKEY.txt \
  etherpad/etherpad:3.3.9

该形态要求数据库已独立存在(DB_HOST 指向外部 PostgreSQL),适合「数据库由 DBA 统一管理」的环境。

十、常用运维命令

在 /opt/etherpad/ 目录下执行:

# 查看实时日志(关注 settings 加载与 db 连接)
docker compose logs -f app
# 实测输出节选:
# [INFO] settings - settings loaded from: /opt/etherpad-lite/settings.json
# [INFO] server - Your Etherpad version is 3.3.9 (75b82bf)
# [INFO] updater - updater: install method = docker, tier = notify

# 重启单个服务(配置变更后)
docker compose restart app

# 停止 / 启动(保留容器与数据)
docker compose stop && docker compose start

# 完整销毁(数据仍保留在 /opt/etherpad/data/)
docker compose down

# 升级到新版本:改 docker-compose.yml 中 image tag 后执行
docker compose pull app && docker compose up -d

升级操作要点:先 pg_dump 备份(见第五节)→ 修改 image: 为新版本号 → docker compose pull app 拉新镜像 → docker compose up -d 滚动替换 → curl /health 与 pad 读写验证。回滚即把 tag 改回旧版本号重复同样步骤(数据目录结构向前兼容,反向降级前务必先备份)。

十一、常见问题

Q1:首次启动 app 反复重启,日志报 connect ECONNREFUSED <ip>:5432 首次部署时 PostgreSQL 初始化建库耗时数秒,Etherpad 先起连库失败退出;restart: always 会自动重试,第二轮即成功。彻底消除可在 postgres 服务加 healthcheck 并让 app depends_on: {postgres: {condition: service_healthy}}。

Q2:app 启动报写文件失败(Permission denied) bind mount 目录属主不是 5001。执行 chown -R 5001:0 /opt/etherpad/data/var /opt/etherpad/data/plugins 后 docker compose restart app。

Q3:curl API 报 {"code":4,"message":"no or wrong API Key"} 两种可能:一是未设 AUTHENTICATION_METHOD: apikey(默认 sso 模式不启用 APIKEY.txt,API 走 OIDC 令牌);二是传的 key 与 data/APIKEY.txt 内容不一致(注意 URL 中 & 转义、key 前后空格)。用 KEY=$(cat /opt/etherpad/data/APIKEY.txt) 再拼 URL。

Q4:管理台 /admin 打不开或提示未授权 确认 ADMIN_PASSWORD 已设置(未设置时 users.admin.password 为 null,等于没有管理账号);浏览器访问 http://<IP>:8134/admin/,账号 admin、密码即 ADMIN_PASSWORD 的值。

Q5:日志出现 SSO client(s) using a default/placeholder client_secret 告警 默认 sso 模式下内置 OIDC 客户端密钥为占位值,生产启用 SSO 登录时须用 ADMIN_SECRET / USER_SECRET 环境变量设置强随机值;仅用 API key 模式时该告警可忽略。

十二、参考链接

  1. 官方仓库 Compose 模板:https://github.com/ether/etherpad/blob/HEAD/docker-compose.yml (查询日期 2026-10-22)
  2. 官方 Docker 镜像:https://hub.docker.com/r/etherpad/etherpad (查询日期 2026-10-22)
  3. v3.3.9 Release Notes:https://github.com/ether/etherpad/releases/tag/v3.3.9 (查询日期 2026-10-22)
  4. 官方文档(配置/数据库/API):https://docs.etherpad.org (查询日期 2026-10-22)
  5. 站内延伸:《Etherpad 介绍与选型指南》《Etherpad 3.3.9 配置参数详解》《Etherpad 3.3.9 常用 CLI 命令与工具详解》