Etherpad 3.3.9 Docker Compose 部署指南
Etherpad 3.3.9 + PostgreSQL 的 Compose 生产部署:镜像选型、API key 与管理员配置、数据持久化与备份、健康验证、升级运维,全程实测。
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/pgdata | PostgreSQL 全部数据文件(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):
| 变量 | 默认值 | 说明 |
|---|---|---|
PORT | 9001 | 服务监听端口(容器内),一般不动、改映射即可 |
IP | 0.0.0.0 | 监听地址 |
TITLE | Etherpad | 站点标题,显示在首页与浏览器标签 |
ADMIN_PASSWORD | null | 管理台 admin 账号密码,生产必设 |
AUTHENTICATION_METHOD | sso | 认证模式:sso(OAuth2/OIDC)或 apikey(API key 传统模式) |
DB_TYPE | dirty | 数据库类型:postgres/mysql/mariadb/sqlite/redis 等;dirty 仅为内置测试存储,生产禁用 |
DB_HOST | undefined | 数据库主机名 |
DB_PORT | undefined | 数据库端口(PostgreSQL 填 5432) |
DB_NAME | undefined | 数据库名 |
DB_USER / DB_PASS | undefined | 数据库账号/密码 |
DB_CHARSET | undefined | 连接字符集,MySQL/MariaDB 常设 utf8mb4 |
DEFAULT_PAD_TEXT | Welcome to Etherpad!… | 新 pad 初始文本(官方要求变量必须存在) |
LOG_LEVEL | INFO | 日志级别:DEBUG/INFO/WARN/ERROR |
TRUST_PROXY | false | 是否信任反向代理的 X-Forwarded-* 头 |
DISABLE_IP_LOGGING | false | 关闭作者 IP 记录(隐私场景设 true) |
REQUIRE_AUTHENTICATION | false | 强制所有 pad 访问先登录 |
ALLOW_PAD_DELETION_BY_ALL_USERS | false | 是否允许所有用户删除 pad(默认仅创建者+删除令牌) |
SUPPRESS_PAD_DELETION_TOKEN_MODAL | false | 关闭「保存 pad 删除令牌」弹窗(3.3.9 新增) |
ENABLE_DARK_MODE | true | 跟随浏览器暗色偏好 |
SKIN_NAME / SKIN_VARIANTS | colibris / super-light-toolbar … | 皮肤与皮肤变体 |
SOCKETIO_MAX_HTTP_BUFFER_SIZE | 1000000 | socket.io 单次 HTTP 包上限(字节),导入大文档时调大 |
IMPORT_MAX_FILE_SIZE | 52428800 | 导入文件大小上限(字节,默认 50 MB) |
MINIFY | true | 前端资源压缩 |
SOFFICE | null | LibreOffice 可执行文件路径(导入导出 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
⚠️ 注意事项(实测结论):
- 自定义 settings.json 里仍可继续使用
${ENV_VAR:default}占位——替换逻辑发生在读取时,与文件来源无关,因此 DB 连接、ADMIN_PASSWORD等仍可走环境变量; - 挂载自定义文件后,通过管理台在线编辑设置所落的改动只存在于容器可写层,
docker compose down && up会丢失;官方模板注释明确建议:要么走纯环境变量,要么把「管理台编辑」与「挂载文件」二选一为主; - 文件属主需 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 模式时该告警可忽略。
十二、参考链接
- 官方仓库 Compose 模板:https://github.com/ether/etherpad/blob/HEAD/docker-compose.yml (查询日期 2026-10-22)
- 官方 Docker 镜像:https://hub.docker.com/r/etherpad/etherpad (查询日期 2026-10-22)
- v3.3.9 Release Notes:https://github.com/ether/etherpad/releases/tag/v3.3.9 (查询日期 2026-10-22)
- 官方文档(配置/数据库/API):https://docs.etherpad.org (查询日期 2026-10-22)
- 站内延伸:《Etherpad 介绍与选型指南》《Etherpad 3.3.9 配置参数详解》《Etherpad 3.3.9 常用 CLI 命令与工具详解》