phpList 3.6.17 Docker Compose 部署指南

使用 Docker Compose 编排部署 phpList 3.6.17 官方镜像:一键启动与自动初始化、MariaDB 数据持久化重建验证、环境变量表、等价 docker run 命令与 SMTP 发送配置要点。

phpListphpList2026/10/26

phpList 3.6.17 Docker Compose 部署指南

目标:使用 Docker Compose 编排部署 phpList 3.6.17 官方镜像,组合 MariaDB 10.11 数据库与 MailHog 邮件测试捕获器,完成一键启动、自动数据库初始化、管理员登录验证、数据持久化重建验证与等价 docker run 命令对照,并给出环境变量表与 SMTP 发送配置要点。

一、环境信息

项目内容
Docker / Compose 版本Docker 29.9.2 / Docker Compose v5.6.1(docker --version、docker compose version 实测)
phpList 版本3.6.17(官方最新稳定版,2026-10-26 实查 GitHub Releases)
phpList 镜像phplist/phplist:3.6.17(Docker Hub 官方镜像,累计拉取 393,258 次,镜像最后更新 2026-10-24)
数据库镜像mariadb:10.11
邮件测试捕获器mailhog/mailhog:v1.0.1(仅用于开发验证收信,生产环境替换为真实 SMTP 服务器)
端口规划Web 管理后台 8128,MailHog Web 界面 8129(示例值,按宿主机空闲端口调整)
容器网段10.89.58.0/24(显式指定,避免与既有内网网段冲突)
演示账号管理员 admin / q1w2e3r4,数据库 phplist / q1w2e3r4

phpList 官方镜像的特点:镜像启动脚本会自动完成「等待数据库就绪 → 初始化数据库结构(建表)→ 初始化多语言包 → 创建管理员 → 启动 cron 与 Apache」的全流程,无需手工执行安装向导。

二、镜像选型

2.1 phpList 官方镜像

phpList 官方在 Docker Hub 维护 phplist/phplist 镜像(2026-10-26 查询 Docker Hub API:累计拉取 393,258 次,最后更新 2026-10-24),tag 列表覆盖 3.6.x 与 3.7.0 预发布线。生产部署建议锁定小版本号 tag(本例 3.6.17),不要使用 latest,以便版本可追溯、可回滚。

镜像内部约定(来源官方仓库 docker/ 目录与启动日志实测):

  • 应用代码位于 /var/www/phpList3/public_html/lists/(与源码包手工部署的 /var/www/lists 不同,注意路径差异);
  • 配置文件为 /etc/phplist/config.php,由镜像内置模板生成,核心取值来自环境变量(模板关键代码实测):
$database_host = getenv('DB_HOST');
$database_name = getenv('DB_NAME');
$database_user = getenv('DB_USER');
$database_password = getenv('DB_PASSWORD');
$mailhost = getenv('MAILHOST');
define('PHPMAILERHOST', $mailhost);
define('TEST', 0);
define('MANUALLY_PROCESS_QUEUE', 0);

可见镜像版默认 TEST=0(真实发送)且 MANUALLY_PROCESS_QUEUE=0(队列由内置 cron 自动处理),与源码包手工安装的默认值不同。

2.2 数据库与邮件捕获器镜像

  • MariaDB 10.11:phpList 官方兼容 MySQL / MariaDB,10.11 为成熟 LTS 分支,实测建表与全功能无兼容问题;
  • MailHog v1.0.1:轻量 SMTP 测试捕获器,提供 1025 端口收信与 8025 端口 Web 界面查看邮件,适合部署验证阶段使用。生产环境务必把 MAILHOST 指向真实邮件服务器或专业 ESP,MailHog 只收不发。

三、部署步骤

3.1 编写 docker-compose.yml

创建部署目录并写入编排文件(本例完整文件,实测可用):

mkdir -p /opt/phplist && cd /opt/phplist
vim docker-compose.yml
name: phplist-3-6-17-stack

services:
  phplist-db:
    image: mariadb:10.11
    container_name: phplist-3-6-17-db
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: q1w2e3r4
      MYSQL_DATABASE: phplistdb
      MYSQL_USER: phplist
      MYSQL_PASSWORD: q1w2e3r4
    volumes:
      - db_data:/var/lib/mysql
    networks:
      - phplist-net

  mailhog:
    image: mailhog/mailhog:v1.0.1
    container_name: phplist-3-6-17-mailhog
    restart: always
    ports:
      - "8129:8025"
    environment:
      MH_SMTP_BIND_ADDR: 0.0.0.0:25
    networks:
      - phplist-net

  phplist:
    image: phplist/phplist:3.6.17
    container_name: phplist-3-6-17-web
    depends_on:
      - phplist-db
      - mailhog
    restart: always
    volumes:
      - upload_images:/var/www/phpList3/public_html/images
    ports:
      - "8128:80"
    environment:
      DB_HOST: phplist-db
      DB_USER: phplist
      DB_PASSWORD: q1w2e3r4
      DB_NAME: phplistdb
      ADMIN_NAME: admin
      ADMIN_PASSWORD: q1w2e3r4
      ADMIN_EMAIL: admin@example.com
      HOSTNAME: localhost
      PORT: 80
      MAILHOST: mailhog
    networks:
      - phplist-net

volumes:
  db_data:
  upload_images:

networks:
  phplist-net:
    driver: bridge
    ipam:
      config:
        - subnet: 10.89.58.0/24

配置要点:

  • name: phplist-3-6-17-stack 显式声明项目名,多套部署并存时避免项目名冲突;
  • db_data 卷持久化数据库文件,upload_images 卷持久化后台上传的图片与模板资源;
  • MAILHOST 直接写服务名 mailhog(同一 Docker 网络内置 DNS 解析);接真实 SMTP 时改为对应主机名或 IP;
  • MailHog 通过 MH_SMTP_BIND_ADDR=0.0.0.0:25 把内部 SMTP 端口对齐 25(phpList 侧不配置端口变量时默认按 25 连接),宿主机 8129 端口映射的是其 8025 Web 界面。

3.2 启动编排

docker compose up -d

查看栈状态(实测回显):

docker compose ps
NAME                     IMAGE                    STATUS             PORTS
phplist-3-6-17-db        mariadb:10.11            Up About a minute  3306/tcp
phplist-3-6-17-mailhog   mailhog/mailhog:v1.0.1   Up About a minute  1025/tcp, 0.0.0.0:8129->8025/tcp
phplist-3-6-17-web       phplist/phplist:3.6.17   Up About a minute  0.0.0.0:8128->80/tcp

3.3 自动初始化过程

首次启动时,phpList 容器日志完整记录初始化流程(docker logs phplist-3-6-17-web 实测回显,节选):

Initialising phpList, Please wait
Waiting for the Database to be available - 1/10
phpList - phpList version 3.6.17 (c) 2000-2026 phpList Ltd, https://www.phplist.com
phpList - Initialising phpList database structure.
Creating tables
Initialising table attribute
... ok
Initialising table user_attribute
... ok
Initialising table user
... ok
Initialising table list
... ok
Initialising table message
... ok
...(依次初始化共 60 余张 phplist_* 表,此处节选)
Initialising table i18n
... ok
Setting default configuration
Admin = admin
Admin Email = admin@example.com
phpList - uk
phpList - Initialising language uk
phpList - tr
phpList - Initialising language tr
...(依次初始化 30 余种语言包,此处节选)

流程说明:先最多等待数据库 10 轮(每轮 10 秒),建表后写入默认配置,ADMIN_NAME/ADMIN_EMAIL 环境变量在此环节自动登记为管理员,最后初始化多语言包并启动服务。日志尾部出现 READY 字样即初始化完成。

3.4 访问与登录验证

浏览器访问 http://<服务器IP>:8128/lists/admin/,用 admin / q1w2e3r4 登录。命令行验证(实测回显):

curl -s -c /tmp/ck.txt -d "login=admin&password=q1w2e3r4" \
  "http://127.0.0.1:8128/lists/admin/?page=login" \
  -o /dev/null -w "login POST http_code: %{http_code}\n"
curl -s -b /tmp/ck.txt "http://127.0.0.1:8128/lists/admin/?page=main" | grep -oE "<title>[^<]*</title>"
login POST http_code: 200
<title>phpList :: phpList :: main</title>

登录成功即部署完成。MailHog 收信界面在 http://<服务器IP>:8129(仅测试用途)。

四、数据持久化

4.1 持久化范围

数据载体说明
全部业务数据具名卷 db_data → /var/lib/mysql订阅者、列表、活动、统计、配置全在数据库内
上传图片/模板资源具名卷 upload_images → /var/www/phpList3/public_html/images后台上传的附件图片
应用代码镜像层升级版本即换镜像 tag

phpList 的业务数据全部落库,因此持久化的核心是数据库卷。

4.2 重建验证(实测)

对栈执行完整重建(容器删除重建、卷保留),验证数据不丢失:

docker compose down
docker compose up -d

等待约 30 秒初始化跑完后再次登录(实测回显):

NAME                     IMAGE                    STATUS
phplist-3-6-17-db        mariadb:10.11            Up 28 seconds
phplist-3-6-17-mailhog   mailhog/mailhog:v1.0.1   Up 28 seconds
phplist-3-6-17-web       phplist/phplist:3.6.17   Up 28 seconds
login POST http_code: 200
<title>phpList :: phpList :: main</title>

重建后管理员账号可直接登录、既有数据完整,持久化验证通过。注意:执行 docker compose down -v 会连卷一起删除,数据将不可恢复,生产操作务必区分 down 与 down -v。

五、环境变量表

phpList 镜像可识别的环境变量(来源:镜像内配置模板与初始化行为实测):

环境变量作用示例值
DB_HOST数据库主机名phplist-db
DB_NAME数据库名phplistdb
DB_USER数据库用户phplist
DB_PASSWORD数据库密码q1w2e3r4
MAILHOSTSMTP 发送服务器(写入 PHPMAILERHOST)mailhog(生产填真实 SMTP 主机)
ADMIN_NAME初始化时创建的管理员登录名admin
ADMIN_PASSWORD初始化时创建的管理员密码q1w2e3r4
ADMIN_EMAIL初始化时创建的管理员邮箱admin@example.com
HOSTNAME / PORT由启动脚本导出到命令行环境(镜像配置模板未直接消费,保留于官方编排示例)localhost / 80

说明:镜像模板还固定了 TEST=0(真实发送)、MANUALLY_PROCESS_QUEUE=0(cron 自动处理队列)、PHPMAILER_SECURE=0(明文 SMTP,可按需在自定义配置中调整)等默认值;如需覆盖更多参数(发件人地址、批量发送、退信处理等),可挂载自定义 config.php 覆盖 /etc/phplist/config.php,参数详解见《phpList 3.6.17 配置参数详解》。

六、等价 docker run 命令

不用 Compose 时,以下三条命令等价复现上述编排(先建网络,再按依赖顺序启动):

docker network create --subnet 10.89.58.0/24 phplist-net

docker run -d --name phplist-3-6-17-db --network phplist-net --restart always \
  -e MYSQL_ROOT_PASSWORD=q1w2e3r4 \
  -e MYSQL_DATABASE=phplistdb \
  -e MYSQL_USER=phplist \
  -e MYSQL_PASSWORD=q1w2e3r4 \
  -v db_data:/var/lib/mysql \
  mariadb:10.11

docker run -d --name phplist-3-6-17-mailhog --network phplist-net --restart always \
  -p 8129:8025 \
  -e MH_SMTP_BIND_ADDR=0.0.0.0:25 \
  mailhog/mailhog:v1.0.1

docker run -d --name phplist-3-6-17-web --network phplist-net --restart always \
  -p 8128:80 \
  -e DB_HOST=phplist-db -e DB_NAME=phplistdb \
  -e DB_USER=phplist -e DB_PASSWORD=q1w2e3r4 \
  -e ADMIN_NAME=admin -e ADMIN_PASSWORD=q1w2e3r4 \
  -e ADMIN_EMAIL=admin@example.com \
  -e HOSTNAME=localhost -e PORT=80 \
  -e MAILHOST=phplist-3-6-17-mailhog \
  phplist/phplist:3.6.17

生产建议仍使用 Compose:编排文件即文档,depends_on 保证启动顺序,升级回滚只需改 tag 后 docker compose up -d。

七、SMTP 发送配置要点

镜像部署下发送链路的三个关键点:

  1. SMTP 主机:MAILHOST 环境变量直接写入 PHPMAILERHOST。开发验证用 MailHog;生产填真实邮件服务器,若非 25 端口或需 TLS 认证,需通过自定义 config.php 追加 PHPMAILERPORT、PHPMAILER_SECURE 及 SMTP 认证配置。
  2. 发件人默认值:初始化时数据库默认发件人为 noreply@[DOMAIN],[DOMAIN] 取自初始化上下文的主机名。若主机名含端口等非法成分,发送会因 Sender 地址校验失败而全部退队(完整排障实录见《Ubuntu 22.04 安装 phpList 3.6.17 指南》第七节)。镜像部署下建议初始化完成后在后台「设置」中把默认发件人改为合法地址,或在自定义配置中显式设置 $message_envelope 与活动默认发件人。
  3. 队列处理:镜像默认 MANUALLY_PROCESS_QUEUE=0,内置 cron 自动跑队列,无需手工触发;修改队列节奏可调整镜像内 /etc/phplist/crontab 或改回手动模式。

八、常见问题

Q1:phpList 容器反复重启或日志停在 Waiting for the Database? 数据库未就绪。启动脚本最多等待 100 秒(10 轮 × 10 秒)后放弃。检查 DB_HOST 服务名拼写、数据库容器健康状态与 MYSQL_USER/MYSQL_PASSWORD 是否与 DB_USER/DB_PASSWORD 一致,修复后 docker compose restart phplist。

Q2:MailHog 容器意外退出(实测事件) 本次实测中 MailHog 容器曾以退出码 2 无日志异常地退出(最后一次日志为正常收信记录),重新启动后恢复正常、收信数据保留。该现象属于测试捕获器的偶发行为,编排中已配置 restart: always 自动拉起;生产环境本就不应依赖 MailHog,请使用真实 SMTP 服务器或专业 ESP。

Q3:后台上传图片 404 或丢失? upload_images 卷未挂载或路径写错。必须挂载到镜像内应用路径 /var/www/phpList3/public_html/images(注意不是源码包部署的 /var/www/lists/ 路径)。

Q4:端口 8128/8129 被占用? 改宿主机侧映射端口即可(ports: "8228:80"),容器内 80/8025 不动;若需固定容器网段避免与内网冲突,保留 ipam 显式 subnet 配置并避开既有网段。

Q5:如何从手工安装迁移到镜像部署? 数据库整体导出导入(mysqldump)是唯一关键步骤:phpList 业务数据全在库中,导入后在新环境核对 config 表中的域名相关项(domain、网站地址等)即可。部署方式与版本背景可先阅读 《phpList 3.6.17 介绍与选型指南》。