Listmonk 6.2.0 Docker Compose 部署指南
使用 Docker Compose 一键部署 Listmonk 6.2.0:官方镜像三段式启动命令解析、环境变量配置与管理员自动创建、服务状态与日志验证、数据持久化确认、版本升级与卸载清理
Listmonk 6.2.0 Docker Compose 部署指南
目标:在一台安装了 Docker 与 Docker Compose 的 Linux 服务器上,使用官方镜像与 Docker Compose 一键部署 Listmonk 6.2.0(含 PostgreSQL 17 数据库),覆盖 compose 文件编写、启动、状态与日志验证、管理员账号确认、API 验证、数据持久化确认、版本升级与卸载清理。本文所有命令与回显均在 Listmonk v6.2.0 环境实测通过。
一、环境信息
本文所有命令与回显均在以下环境中实测:
- 操作系统:Linux x86_64(已安装 Docker 与 Docker Compose 插件)
- Listmonk 镜像:
listmonk/listmonk:v6.2.0 - 数据库镜像:
postgres:17-alpine - 服务端口:9000(Listmonk Web 与 API)
- 演示账号:
admin/q1w2e3r4(通过环境变量在首次启动时自动创建)
二、官方部署方案解析
2.1 镜像与组成
官方维护的 Docker 镜像为 listmonk/listmonk,官方仓库根目录提供标准 docker-compose.yml,由两个服务组成:
app:Listmonk 主程序,对外暴露 9000 端口;db:PostgreSQL 数据库(官方示例使用postgres:17-alpine),数据落盘到命名卷。
镜像启动时会打印入口信息(实测日志):
Launching listmonk with user=[root] group=[root] PUID=[0] PGID=[0]
2.2 启动命令三段式
官方 compose 为 app 服务定义的启动命令是三段拼接(实测原文):
command: [sh, -c, "./listmonk --install --idempotent --yes --config '' && ./listmonk --upgrade --yes --config '' && ./listmonk --config ''"]
三段含义:
--install --idempotent --yes:仅当数据库还是空库(首次启动)时执行一次表结构安装,之后自动跳过;--upgrade --yes:每次启动都执行一次数据库结构升级检查,新版本镜像拉起后自动完成迁移;--config '':把配置文件路径传空串,表示完全不用配置文件,只从环境变量读取配置。
💡 技术拓展:
--config ''传空串是官方约定:Listmonk 尝试打开名为空串的配置文件失败后,会退化为纯环境变量模式。因此 compose 部署中所有配置都以LISTMONK_前缀环境变量注入(详见第五章),而不是挂载config.toml。
2.3 机密文件模式
官方镜像支持 LISTMONK_*_FILE 后缀模式加载 Docker secrets / Podman secrets:例如 LISTMONK_ADMIN_USER 对应 LISTMONK_ADMIN_USER_FILE=/path/to/file_with_value,程序会从指定文件读取真实值,避免明文口令出现在编排文件里。
三、部署步骤
3.1 编写 docker-compose.yml
创建部署目录并写入 compose 文件(基于官方结构,镜像 tag 固定为 v6.2.0,并补充了管理员自动创建的环境变量):
mkdir -p /opt/listmonk-compose && cd /opt/listmonk-compose
cat > docker-compose.yml <<'EOF'
x-db-credentials: &db-credentials
POSTGRES_USER: &db-user listmonk
POSTGRES_PASSWORD: &db-password listmonk
POSTGRES_DB: &db-name listmonk
services:
app:
image: listmonk/listmonk:v6.2.0
container_name: listmonk_app
restart: unless-stopped
ports:
- "9000:9000"
networks:
- listmonk
hostname: listmonk.example.com
depends_on:
- db
command: [sh, -c, "./listmonk --install --idempotent --yes --config '' && ./listmonk --upgrade --yes --config '' && ./listmonk --config ''"]
environment:
LISTMONK_app__address: 0.0.0.0:9000
LISTMONK_db__user: *db-user
LISTMONK_db__password: *db-password
LISTMONK_db__database: *db-name
LISTMONK_db__host: db
LISTMONK_db__port: 5432
LISTMONK_db__ssl_mode: disable
LISTMONK_db__max_open: 25
LISTMONK_db__max_idle: 25
LISTMONK_db__max_lifetime: 300s
TZ: Asia/Shanghai
LISTMONK_ADMIN_USER: admin
LISTMONK_ADMIN_PASSWORD: q1w2e3r4
volumes:
- ./uploads:/listmonk/uploads:rw
db:
image: postgres:17-alpine
container_name: listmonk_db
restart: unless-stopped
ports:
- "127.0.0.1:5432:5432"
networks:
- listmonk
environment:
<<: *db-credentials
healthcheck:
test: ["CMD-SHELL", "pg_isready -U listmonk"]
interval: 10s
timeout: 5s
retries: 6
volumes:
- type: volume
source: listmonk-data
target: /var/lib/postgresql/data
networks:
listmonk:
volumes:
listmonk-data:
EOF
说明:
x-db-credentials锚点统一管理数据库账号口令,app与db两处复用;LISTMONK_ADMIN_USER/LISTMONK_ADMIN_PASSWORD:首次以空库启动时自动创建超级管理员,免去网页初始化步骤(演示值admin/q1w2e3r4,生产请用强口令);db的 5432 端口只绑定127.0.0.1,仅本机可连,不暴露公网;./uploads挂载到/listmonk/uploads用于媒体上传(启用后需在后台 Settings → Media 把上传目录改为/listmonk/uploads);healthcheck使用pg_isready -U listmonk,10 秒间隔、5 秒超时、最多重试 6 次。
3.2 启动服务
docker compose up -d
首次启动会拉取 listmonk/listmonk:v6.2.0 与 postgres:17-alpine 镜像、创建网络 listmonk_listmonk、创建数据卷 listmonk_listmonk-data,然后依次拉起 db 与 app。
3.3 查看服务状态
docker compose ps
实测回显(节选,省略启动时长字段):
NAME IMAGE SERVICE STATUS PORTS
listmonk_app listmonk/listmonk:v6.2.0 app Up 0.0.0.0:9000->9000/tcp
listmonk_db postgres:17-alpine db Up (healthy) 127.0.0.1:5432->5432/tcp
两个服务均 Up,db 的健康检查为 healthy,app 的 9000 端口映射到宿主机所有网卡的 9000。
3.4 检查启动日志
docker compose logs app
实测关键日志(节选):
connecting to db...
running upgrade...
no upgrades to run. Database is up to date.
initialized email (SMTP) messenger: @mailhog
http server started on [::]:9000
no upgrades to run. Database is up to date.:--install --idempotent在空库完成首次安装、--upgrade检查无待执行迁移;initialized email (SMTP) messenger: @mailhog:内置默认 SMTP 投递通道已初始化(名称@mailhog,此时指向默认占位 SMTP,实际发信需在后台 Settings 配置,见《快速入门与集成示例》);http server started on [::]:9000:HTTP 服务就绪。
四、部署验证
4.1 Web 登录验证
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:9000/
实测回显:
200
浏览器打开 http://<服务器IP>:9000/admin,用环境变量中设置的管理员账号登录(本文演示:admin / q1w2e3r4),能进入管理后台即部署成功。
4.2 API 验证
先创建一个 API 用户(登录后台 Admin → Users 新建类型为 API 的用户,请求体要点为 "type": "api"、"status": "enabled"、"user_role_id": 1),创建成功后响应中的 password 字段即 48 位 API Token。实测创建的演示用户:
{"data":{"id":5,"username":"composeapi","password":"6g9QyvVZFFvcf4LmLuutiU1B3rYw7sNHzth0WvVxF3rsEsNx","name":"Compose API","type":"api","status":"enabled","user_role":{"id":1,"name":"Super Admin","permissions":["campaigns:manage","templates:manage","roles:get","settings:get","settings:manage","subscribers:get_all","campaigns:get_all","campaigns:get_analytics","campaigns:send","bounces:manage","webhooks:post_bounce","media:get","templates:get","subscribers:get","subscribers:import","campaigns:get","campaigns:manage_all","bounces:get","media:manage","users:get","users:manage","lists:get_all","lists:manage_all","roles:manage","settings:maintain","subscribers:manage","subscribers:sql_query","tx:send"]}}}
用 Token 验证 API:
curl -s -o /dev/null -w "%{http_code}\n" -u "composeapi:6g9QyvVZFFvcf4LmLuutiU1B3rYw7sNHzth0WvVxF3rsEsNx" http://localhost:9000/api/lists
实测回显:
200
4.3 数据库表结构确认
首次启动的 --install 已在 PostgreSQL 中建好全部业务表(实测共 16 张,节选):
bounces、campaign_lists、campaign_media、campaign_views、campaigns、
link_clicks、links、lists、media、subscribers、...
可通过 docker exec listmonk_db psql -U listmonk -d listmonk -c '\dt' 自行查看完整表清单。
五、配置项说明
5.1 环境变量逐项
compose 中 app 服务注入的环境变量与 config.toml 配置键一一对应,命名规则为 LISTMONK_段__键(段与键之间是双下划线):
| 环境变量 | 对应配置键 | 实测值 | 说明 |
|---|---|---|---|
LISTMONK_app__address | app.address | 0.0.0.0:9000 | 监听地址,容器内必须 0.0.0.0 才能映射到宿主机 |
LISTMONK_db__host | db.host | db | compose 网络内数据库服务名 |
LISTMONK_db__port | db.port | 5432 | 数据库端口 |
LISTMONK_db__user | db.user | listmonk | 数据库账号 |
LISTMONK_db__password | db.password | listmonk | 数据库口令 |
LISTMONK_db__database | db.database | listmonk | 数据库名 |
LISTMONK_db__ssl_mode | db.ssl_mode | disable | compose 内网直连无需 TLS |
LISTMONK_db__max_open | db.max_open | 25 | 最大连接数 |
LISTMONK_db__max_idle | db.max_idle | 25 | 最大空闲连接数 |
LISTMONK_db__max_lifetime | db.max_lifetime | 300s | 连接最长存活时间 |
LISTMONK_ADMIN_USER | —(特殊变量) | admin | 首次空库启动自动创建的超管用户名 |
LISTMONK_ADMIN_PASSWORD | —(特殊变量) | q1w2e3r4 | 首次空库启动自动创建的超管密码 |
⚠️ 注意:v6 版本起 SMTP 发信配置不再支持用
LISTMONK_smtp__*环境变量注入,必须通过后台 Settings 或 Settings API 配置(实测验证与原理解释见《配置参数详解》第六章)。
5.2 docker compose config 渲染确认
用 docker compose config 渲染最终生效的编排配置,可核对环境变量是否按预期注入。实测渲染节选:
name: listmonk
services:
app:
environment:
LISTMONK_ADMIN_PASSWORD: q1w2e3r4
LISTMONK_ADMIN_USER: admin
LISTMONK_app__address: 0.0.0.0:9000
LISTMONK_db__database: listmonk
LISTMONK_db__host: db
LISTMONK_db__max_idle: "25"
LISTMONK_db__max_lifetime: 300s
LISTMONK_db__max_open: "25"
LISTMONK_db__password: listmonk
LISTMONK_db__port: "5432"
LISTMONK_db__ssl_mode: disable
LISTMONK_db__user: listmonk
TZ: Asia/Shanghai
image: listmonk/listmonk:v6.2.0
5.3 数据卷与网络
docker volume ls
实测回显(节选):
local listmonk_listmonk-data
docker network ls
实测回显(节选):
listmonk_listmonk bridge
数据库名卷 listmonk_listmonk-data(默认命名规则为 项目名_卷名)承载全部 PostgreSQL 数据;compose 项目网络 listmonk_listmonk 提供 app 到 db 的服务名解析。
六、数据持久化与重启验证
数据落在命名卷中,重启服务后数据不丢失。实测重启并验证:
docker compose restart
重启完成后再次调用 API(凭据同 4.2 节):
curl -s -o /dev/null -w "%{http_code}\n" -u "composeapi:6g9QyvVZFFvcf4LmLuutiU1B3rYw7sNHzth0WvVxF3rsEsNx" http://localhost:9000/api/lists
实测回显:
200
重启后 API 正常响应、此前创建的数据完整可用,持久化验证通过。
七、常见问题
7.1 修改 LISTMONK_ADMIN_USER/PASSWORD 后管理员没变
这两个变量只在首次以空库启动时生效,用于自动创建超级管理员;数据库初始化完成后,再修改环境变量不会更新已有账号。如需改密码,登录后台 Admin → Users 修改即可。
7.2 媒体上传后文件不在宿主机
compose 已把 ./uploads 挂载到 /listmonk/uploads,但 Listmonk 默认上传目录不是它。需登录后台 Settings → Media,把上传路径改为 /listmonk/uploads 后保存,此后上传的文件才会落到宿主机目录。
7.3 首次启动 app 反复重启
多为数据库未就绪导致。db 服务定义了 pg_isready 健康检查,等待其转为 healthy 后 docker compose restart app 即可;若日志出现数据库连接被拒(connection refused),确认 LISTMONK_db__host 填的是 compose 服务名 db 而不是 localhost。
7.4 9000 端口被占用
将 compose 中 ports 的宿主侧改为其他端口(如 "19000:9000"),重启 compose 后用新端口访问。
八、升级与卸载
8.1 版本升级
官方启动命令中的 --upgrade --yes 保证了升级的自动化:修改 compose 中的镜像 tag 后重建 app 服务即可。以从 v6.1.0 升级到 v6.2.0 为例:
sed -i 's|listmonk/listmonk:v6.1.0|listmonk/listmonk:v6.2.0|' docker-compose.yml
docker compose up -d app
实测升级日志(节选):
2026/10/17 00:35:06.902686 main.go:106: v6.2.0 (ef0a7587 2026-06-26T10:21:29Z, linux/amd64)
2026/10/17 00:35:06.953000 main.go:165: running upgrade...
2026/10/17 00:35:06.957679 upgrade.go:80: running migration v6.2.0
2026/10/17 00:35:06.995526 upgrade.go:98: upgrade complete
upgrade complete 即迁移完成。注意:数据库迁移不会自动回滚——回滚版本需要换回旧镜像 tag 并恢复升级前的数据库备份(备份恢复实操见《进阶实战与运维》)。
8.2 卸载清理
docker compose down
该命令停止并移除两个服务与 compose 网络;数据库名卷 listmonk_listmonk-data 默认保留。如确认不再需要数据,追加 -v 一并删除卷:
docker compose down -v
卸载后可用 docker volume ls 核对卷已不存在,宿主机上的部署目录与 ./uploads 目录按需删除。
九、参考链接
- Listmonk 官方 Docker Compose 文件:https://github.com/knadh/listmonk/blob/master/docker-compose.yml
- Listmonk 安装文档:https://listmonk.app/docs/installation/
- GitHub 仓库:https://github.com/knadh/listmonk
- Docker Hub 镜像页:https://hub.docker.com/r/listmonk/listmonk
- PostgreSQL 17 镜像页:https://hub.docker.com/_/postgres