Ubuntu 22.04 安装 phpList 3.6.17 指南
在 Ubuntu 22.04 上以 LAMP 方式手工安装 phpList 3.6.17:源码包部署、数据库准备、config.php 配置、初始化向导、SMTP+CLI 发信链路验证与发送失败排障实录。
Ubuntu 22.04 安装 phpList 3.6.17 指南
目标:在一台全新 Ubuntu 22.04 服务器上,以 LAMP(Apache + PHP + MariaDB)方式手工安装 phpList 3.6.17:完成官方源码包下载部署、数据库准备、config.php 最小配置、Apache 站点配置、Web 初始化向导与管理员账号创建,并打通「SMTP 投递 + 命令行发送 + 队列处理」的完整发信链路,最后沉淀本次实测中踩到的发送失败排障实录。
一、环境信息
- 操作系统:Ubuntu 22.04.5 LTS(
/etc/os-release实测回显PRETTY_NAME="Ubuntu 22.04.5 LTS") - phpList 版本:3.6.17(官方最新稳定版;GitHub Releases 的
releases/latest于 2026-10-26 查询时重定向至v3.6.17。注意:SourceForge 上已出现3.7.0目录,但对应的是 3.7.0-RC5 预发布线(发布于 2026-08-10,与 GitHubv3.7.0-RC5同期),GitHub 上不存在v3.7.0正式 tag,生产安装请认准 3.6.17) - 组件版本(安装后
dpkg -l实测回显):
| 组件 | 版本 |
|---|---|
| apache2 | 2.4.52-1ubuntu4.25 |
| libapache2-mod-php | 2:8.1+92ubuntu1 |
| php | 2:8.1+92ubuntu1 |
| php8.1-mysql / xml / mbstring / imap / curl / gd / zip | 8.1.2-1ubuntu2.28 |
| mariadb-server | 1:10.6.23-0ubuntu0.22.04.1 |
- 网络端口规划:Web 服务监听 8130(示例值,避免与已有站点冲突;生产可直接用 80),MariaDB 3306,SMTP 发送测试捕获器 1025
- 演示账号:管理员
admin/q1w2e3r4,数据库账号phplist/q1w2e3r4 - 下载渠道说明:官方 SourceForge 直连实测可用(⚠️ 注意 SourceForge 的
3.7.0目录是 RC 预发布,稳定版请使用3.6.17路径)
二、安装前准备
2.1 更新系统并安装依赖
phpList 3.6.17 是标准 PHP 应用,依赖 Web 服务器、PHP 及其扩展、MariaDB。执行:
apt-get update
apt-get install -y apache2 mariadb-server php libapache2-mod-php \
php8.1-mysql php8.1-xml php8.1-mbstring php8.1-imap \
php8.1-curl php8.1-gd php8.1-zip
安装完成后核对版本(实测回显节选):
php -v | head -1
PHP 8.1.2-1ubuntu2.28 (cli) (built: Oct 19 2026 18:54:45) (NTS)
apache2 -v | head -1
mysql --version
Server version: Apache/2.4.52 (Ubuntu)
mysql Ver 15.1 Distrib 10.6.23-MariaDB, for debian-linux-gnu (x86_64) using EditLine wrapper
确认 PHP 模块已被 Apache 加载(实测回显):
apachectl -M 2>/dev/null | grep php
php_module (shared)
2.2 启动并验证基础服务
在标准 Ubuntu 服务器上:
systemctl enable --now apache2 mariadb
验证监听端口:
ss -ltn | grep -E ':(80|8130|3306)'
实测回显(本例 Apache 配置为监听 8130,见 4.2 节;MariaDB 默认监听 3306):
LISTEN 0 80 127.0.0.1:3306 0.0.0.0:*
LISTEN 0 511 0.0.0.0:8130 0.0.0.0:*
⚠️ 提示:若服务器未启用 systemd(如最小化安装环境),可用
service apache2 start与service mariadb start替代,service apache2 status实测回显* apache2 is running。
2.3 创建数据库与账号
phpList 安装向导只会建表,不建库。先手工创建数据库与专用账号:
mysql -e "CREATE DATABASE phplistdb CHARACTER SET utf8mb4;"
mysql -e "CREATE USER 'phplist'@'localhost' IDENTIFIED BY 'q1w2e3r4';"
mysql -e "GRANT ALL PRIVILEGES ON phplistdb.* TO 'phplist'@'localhost';"
mysql -e "FLUSH PRIVILEGES;"
以上语句执行成功时无输出。验证(实测回显):
mysql -e "show databases"
Database
information_schema
mysql
performance_schema
phplistdb
sys
mysql -e "show grants for 'phplist'@'localhost'"
Grants for phplist@localhost
GRANT USAGE ON *.* TO `phplist`@`localhost` IDENTIFIED BY PASSWORD '*0971389F8E7F1AEB999104BDA7A0FA145087F348'
GRANT ALL PRIVILEGES ON `phplistdb`.* TO `phplist`@`localhost`
三、安装 phpList 3.6.17
3.1 下载官方源码包
从 SourceForge 官方项目页下载 3.6.17 稳定版(实测直连可用,约 23 MB,耗时 7.2 秒):
cd /root
wget -O phplist-3.6.17.tgz "https://sourceforge.net/projects/phplist/files/phplist/3.6.17/phplist-3.6.17.tgz/download"
实测回显(节选尾部):
22700K .......... .......... .......... .......... .......... 99% 21.9M 0s
22750K .......... .......... .......... .......... .......... 99% 34.2M 0s
22800K .......... ........ 100% 53.8K=7.2s
2026-10-26 10:50:01 (3.09 MB/s) - 'phplist-3.6.17.tgz' saved [23365673/23365673]
⚠️ 注意:SourceForge 的
files/phplist/3.7.0/目录目前放置的是 3.7.0 预发布(RC5)产物,稳定版请认准3.6.17路径。官方 GitHub Releases(github.com/phpList/phpList3)不提供 tgz 附件,源码包以 SourceForge 为准。
3.2 校验与解压
校验文件完整性(实测回显):
ls -la phplist-3.6.17.tgz
sha256sum phplist-3.6.17.tgz
-rw-r--r-- 1 root root 23365673 Aug 9 15:30 phplist-3.6.17.tgz
bcc790fd451862f03f2a0476d8ce9e8a794211d946613e0f7415dd4cde08e3d8 phplist-3.6.17.tgz
查看包内顶层结构(实测回显):
tar -tzf phplist-3.6.17.tgz | head -3
phplist-3.6.17/
phplist-3.6.17/public_html/
phplist-3.6.17/public_html/index.html
解压:
tar -xzf phplist-3.6.17.tgz
3.3 部署到 Web 目录并设置权限
将包内 public_html 目录部署为 /var/www/lists(phpList 官方推荐的应用路径名):
mv /root/phplist-3.6.17/public_html /var/www/lists
chown -R www-data:www-data /var/www/lists
ls /var/www/lists
实测回显:
admin
api.php
base
config
dl.php
images
index.html
index.php
js
lt.php
styles
texts
updater
ut.php
目录说明:admin/ 是管理后台,config/ 存放配置文件,其余为订阅前台与静态资源。
四、配置 phpList 与 Apache
4.1 编写最小配置文件 config.php
phpList 的配置文件是 config/config.php(发布包中为精简模板)。编辑 /var/www/lists/config/config.php,核心改动如下(与实测生效文件一致):
// 数据库连接(对应 2.3 节创建的库与账号)
$database_host = 'localhost';
$database_name = 'phplistdb';
$database_user = 'phplist';
$database_password = 'q1w2e3r4';
// SMTP 发送服务器。留空则使用 PHP mail() 函数;
// 本例指向本机 1025 端口的测试捕获器(见 6.1 节),生产环境替换为真实 SMTP 服务器
define('PHPMAILERHOST', '127.0.0.1');
define('PHPMAILERPORT', 1025);
// 必须改为 0 才会真实发送;默认值为 1(仅模拟发送,不投递)
define('TEST', 0);
⚠️ 发布包默认带
define('TEST', 1);,官方注释明确说明这是防止「未确认配置就意外发信」的保护开关。忘记改成 0 时,队列会走模拟流程、邮件不会真实投出,这是新装环境最常踩的坑之一。
如需退信处理与更多高级参数,可参考同目录下 900 余行的 config_extended.php,将所需段落复制进 config.php(参数详解见本专栏《phpList 3.6.17 配置参数详解》)。
4.2 配置 Apache 站点(端口 8130)
本例让 Apache 监听 8130 并以 /var/www 为站点根,使应用通过 http://<服务器IP>:8130/lists/ 访问。
修改监听端口(/etc/apache2/ports.conf):
sed -i 's/^Listen 80/Listen 8130/' /etc/apache2/ports.conf
修改默认站点(/etc/apache2/sites-enabled/000-default.conf)两处:
<VirtualHost *:8130>
DocumentRoot /var/www
(生产环境若使用 80 端口,保持 Listen 80 与 <VirtualHost *:80> 即可,其余步骤相同。)
4.3 重启并验证 Web 服务
apachectl configtest
实测回显:
Syntax OK
apachectl restart
ss -ltn | grep 8130
实测回显:
LISTEN 0 511 0.0.0.0:8130 0.0.0.0:*
验证管理后台可访问(实测回显):
curl -sI http://127.0.0.1:8130/lists/admin/ | head -2
HTTP/1.1 200 OK
Date: Mon, 26 Oct 2026 10:47:11 GMT
五、初始化向导与管理员账号
5.1 访问初始化向导
首次访问 http://127.0.0.1:8130/lists/admin/,phpList 会自动跳转到数据库初始化向导(页面标题 phpList :: phpList :: Initialise the database,页面 footer 标识 Powered-By: phplist version 3.6.17)。
向导页面提供「创建管理员」表单,字段包括:管理员登录名(adminname)、组织名称(orgname)、管理员密码(adminpassword)、管理员邮箱(adminemail)。
⚠️ 排障提示:若数据库此前已被初始化过(例如向导被重复访问、或曾用命令行
-pinitialise初始化过),再次访问向导会出现Database error 1050 ... Table 'phplist_xxx' already exists ... failed的建表报错,并提供「Upgrade instead?」与「Force Initialisation (will erase all data!)」两个选项。此时不要点 Force(会清空数据),直接登录即可;全新库则不会出现该现象。
5.2 提交初始化并创建管理员
在向导表单中填入:
- 管理员登录名:
admin - 组织名称:
example - 管理员密码:
q1w2e3r4 - 管理员邮箱:
admin@example.com
提交后系统自动完成建表(60 余张 phplist_* 表)、写入默认系统配置,并创建管理员账号。初始化成功后页面转入登录入口。
5.3 登录后台验证
提交管理员凭证登录(实测回显):
curl -s -c /root/b1ck.txt -d "login=admin&password=q1w2e3r4" \
"http://127.0.0.1:8130/lists/admin/?page=login" \
-o /root/login_resp.html -w "login POST http_code: %{http_code}\n"
login POST http_code: 200
携带会话 Cookie 访问后台首页(实测回显):
curl -s -b /root/b1ck.txt "http://127.0.0.1:8130/lists/admin/?page=main" | grep -oE "<title>[^<]*</title>"
<title>phpList :: phpList :: main</title>
登录成功,浏览器访问 http://<服务器IP>:8130/lists/admin/ 即可进入管理后台(账号 admin / q1w2e3r4)。
六、发信链路验证(SMTP + CLI)
以下步骤在服务器本机完成,验证「创建活动 → 队列处理 → SMTP 投递」链路。
6.1 启动本地 SMTP 捕获器
生产环境中 PHPMAILERHOST 指向真实邮件服务器;本机验证可用 Python 自带的 aiosmtpd 起一个只收不发、把邮件打印到终端的调试 SMTP 服务:
apt-get install -y python3-aiosmtpd
python3 -u -m aiosmtpd -n -l 127.0.0.1:1025 > /root/smtpd.log 2>&1 &
验证端口就绪(实测回显):
python3 -c "import socket;s=socket.create_connection(('127.0.0.1',1025),3);print(s.recv(64).decode().strip())"
220 mail.example.com Python SMTP 1.4.2
6.2 安装命令行包装脚本
phpList 的命令行入口是 admin/index.php,官方发布包自带 bin/phplist 包装脚本。为便于使用,创建 /usr/local/bin/phplist(内容与实测生效脚本一致):
cat > /usr/local/bin/phplist <<'EOF'
#!/bin/bash
# phpList 命令行入口:用户参数在前,-c 指定配置文件在后
/usr/bin/php /var/www/lists/admin/index.php $* -c /var/www/lists/config/config.php
EOF
chmod +x /usr/local/bin/phplist
验证版本(实测回显):
phplist --version
phpList - phpList version 3.6.17 (c) 2000-2026 phpList Ltd, https://www.phplist.com
⚠️ 实测注意:包装脚本中
$*(用户参数)必须放在-c之前。phpList 的命令行参数解析会把key=value形式的参数写入请求上下文,若-c在前,部分子命令的参数会被吞掉,出现「Cannot find config file」之类的误导性报错。命令行默认以 root 运行即可;若在
config.php中配置了$commandline_users白名单,则仅白名单内的系统用户可运行(详见《phpList 3.6.17 常用 CLI 命令详解》)。
6.3 准备列表与订阅者,创建测试发送
通过 Web 后台(http://<服务器IP>:8130/lists/admin/,账号 admin / q1w2e3r4)完成两项准备:
- 进入 Lists 页面,创建列表
demo-list; - 进入 Users 页面,添加测试订阅者
user1@example.com、user3@example.com(保持 confirmed 状态),并加入demo-list。
编写测试正文并创建发送活动(-l 指定列表名,-s 指定主题,-f 指定发件人地址,正文从标准输入读入):
printf "Hello team,\n\nThis is a CLI delivery test from phpList 3.6.17.\n" > /root/test-body.txt
phplist -psend -s FromFlagCheck -l demo-list -f admin@example.com < /root/test-body.txt
实测回显:
phpList - phpList version 3.6.17 (c) 2000-2026 phpList Ltd, https://www.phplist.com
Message with subject FromFlagCheck was sent to "demo-list"
⚠️ 实测注意:
-f必须紧跟一个完整词(如admin@example.com),且主题等参数值中避免再出现-x形式的词——phpList 会按空格重新分词解析参数,拆散的参数会被错误归属(本系列实测中-s "From via -f flag"就曾导致主题被截成From via、flag被-f吞掉)。
6.4 处理队列并验证收信
处理发送队列(实测回显):
phplist -pprocessqueue
phpList - phpList version 3.6.17 (c) 2000-2026 phpList Ltd, https://www.phplist.com
phpList - Recently sent : 0
phpList - Started [0.0007750000] (123)
phpList - Sending in batches of 1,000 emails [0.0000490000] (124)
phpList - Processing has started, [0.0001540000] (127)
phpList - One campaign to process. [0.0002800000] (129)
phpList - Processing campaign 7 [0.0012610000] (146)
phpList - Looking for subscribers [0.0005420000] (151)
phpList - Found them: 2 to process [0.0005740000] (157)
phpList - sent 1 ETA Mon 26 Oct 10:44 sending 59388 msg/hrphpList - sent 2 ETA Mon 26 Oct 10:44 sending 66503 msg/hrphpList - Processed 2 out of 2 subscribers [0.1029420000] (223)
phpList - Script stage: 5 [0.0020420000] (236)
phpList - 2 messages sent in 0.11 seconds (64524 msgs/hr) [0.0002160000] (240)
phpList - Finished this run [0.0008410000] (245)
查看 SMTP 捕获器收到的邮件(实测回显,/root/smtpd.log):
---------- MESSAGE FOLLOWS ----------
Date: Mon, 26 Oct 2026 10:44:00 +0000
To: user1@example.com
From: "admin@example.com" <admin@example.com>
Subject: FromFlagCheck
Message-ID: <xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx@localhost.localdomain>
X-phpList-version: 3.6.17
...
------------ END MESSAGE ------------
邮件真实投出、From 头正确,发送链路验证完成。
七、排障实录
7.1 全部发送失败:Invalid address (Sender)
现象:phplist -pprocessqueue 日志出现 2 failed (will retry later)、2 sendemail returned false、2 failed_sent,且伴随 Warning: script never reached stage 5,SMTP 捕获器一无所获。
定位:processqueue 的标准输出不给出根因,需查数据库事件日志:
mysql phplistdb -e "select entered,left(entry,130) from phplist_eventlog order by id desc limit 6"
实测回显:
entered left(entry,130)
2026-10-26 10:41:04 Warning: script never reached stage 5\nThis may be caused by a too slow or too busy server \n
2026-10-26 10:41:04 Finished this run
2026-10-26 10:41:04 2 failed (will retry later)
2026-10-26 10:41:04 Processed 2 out of 2 subscribers
2026-10-26 10:41:04 Error sending email to user3@example.com Invalid address: (Sender): webmaster@127.0.0.1:8130
2026-10-26 10:41:04 Error sending email to user1@example.com Invalid address: (Sender): webmaster@127.0.0.1:8130
根因:phpList 初始化时会把若干默认值写入数据库配置表(phplist_config),其中发件人默认值为 noreply@[DOMAIN],[DOMAIN] 占位符取自初始化时的访问域名。本例初始化时用了带端口的 127.0.0.1:8130,于是默认发件人被拼成 noreply@127.0.0.1:8130——这是非法邮箱地址;退信信封(Sender)同样回退到 webmaster@127.0.0.1:8130,PHPMailer 地址校验直接失败,整封邮件发送中断(实测回显数据库配置值):
item value
domain 127.0.0.1:8130
message_from_address noreply@[DOMAIN]
message_from_name Webmaster
解决:
- 保证
config.php中配置了退信信封地址$message_envelope(合法邮箱即可,例如listbounces@example.com),这是 Sender 的可靠来源,缺失时才会回退到非法默认值; - 命令行发送时用
-f显式指定发件人(见 6.3 节),或在后台「设置」中把活动默认发件人(campaignfrom_default)改写为合法地址;Web 向导正常初始化时会把管理员邮箱自动写入该默认值。
验证:补齐配置后重跑 phplist -pprocessqueue,队列自动重试上次标记 failed_sent 的订阅者,实测回显 2 messages sent in 0.11 seconds (66174 msgs/hr),SMTP 捕获器收到完整邮件,From 头正常。
7.2 从头为空的 From
现象:邮件能投出,但收到的邮件 From: 头为空(实测捕获到 From: 后无任何内容),此类邮件在真实邮件服务器上大概率被拒收或进垃圾箱。
根因:From 头来自活动自身的发件人字段(fromfield)。命令行 -psend 不带 -f 时,fromfield 由数据库配置 message_from_name + message_from_address 拼接,本例拼出 Webmaster noreply@127.0.0.1:8130——地址部分非法,phpList 将其置空后仍然投递,产生无效邮件。
解决:见 7.1 的第 2 条;带 -f admin@example.com 重发后,实测 From 头为 "admin@example.com" <admin@example.com>,问题消失。
7.3 重复初始化:Table already exists
现象与处理:见 5.1 节排障提示——数据库已初始化时向导会报 Database error 1050 ... already exists,此时直接登录后台即可,切勿点「Force Initialisation」清空数据。
八、常见问题与后续文档
Q1:队列跑完显示 sent 但收不到邮件?
按顺序检查:① config.php 是否仍是默认 define('TEST', 1)(模拟发送,不真实投递);② PHPMAILERHOST/PHPMAILERPORT 是否指向可达的 SMTP 服务(端口写错会直接连接失败);③ 查 phplist_eventlog 表定位真实错误(参见 7.1 节)。
Q2:向导页面空白或报 PHP 函数缺失?
多为 PHP 扩展不全。本例实测所需扩展集合为:mysql、xml、mbstring、imap、curl、gd、zip(对应 php8.1-* 包),逐项核对 dpkg -l | grep php8.1。
Q3:如何实现定时无人值守发送?
将 processqueue、processbounces 挂入 crontab,并把 MANUALLY_PROCESS_QUEUE 设为 0 禁止后台手动触发,详见本专栏《phpList 3.6.17 常用 CLI 命令详解》。
Q4:安装方式如何选择? 手工 LAMP 安装适合已有 PHP 运行环境的服务器;容器化环境可直接使用官方镜像编排部署,见《phpList 3.6.17 Docker Compose 部署指南》。产品定位与选型背景可先阅读 《phpList 3.6.17 介绍与选型指南》。