WP-Cron 替代——WordPress 内置的 WP-Cron 是一个出名的性能杀手。它不是一个真正的系统级定时任务:每次有人访问你的网站,WordPress 才检查“有没有到期的任务要跑”。这意味着高并发时可能触发多次、低流量时根本不会跑、PHP 执行超时直接中断。生产环境必须做 WP-Cron 替代。

为什么 WP-Cron 需要替代
WordPress 的 WP-Cron 依赖页面访问触发。一个 2C2G 的 VPS 跑三个站,用户每次 F5 都在赌“这次会不会撞上 wp-cron.php”。替代 WP-Cron 的三个原因:
- 性能:每次请求都可能触发 PHP 进程执行定时任务,拖慢响应
- 可靠性:凌晨没人访问,定时发布文章根本发不出去
- 可控性:没有日志、没有重试、不知道任务到底跑了没
禁用了 WP-Cron 必须有 WP-Cron 替代方案,否则定时发布、插件更新、自动备份全部停摆。我在一台 2C2G 的 VPS 上跑三个 WordPress 站,之前在高峰期遇到过 wp-cron.php 被触发 4 次导致 PHP-FPM 全部占满的情况——就是因为没做 WP-Cron 替代。改成外部定时触发后,PHP 进程数稳定在 5-8 个,再也没有突然飙到 30+。下面两个 WP-Cron 替代方案,选一个。
WP-Cron 替代方案一:systemd timer(推荐)
systemd timer 是生产环境最干净的 WP-Cron 替代。零依赖、自带日志、可以精确到秒、支持失败重试。适用于任何 Linux 服务器。
Step 1:禁用 WP-Cron
在 wp-config.php 里加一行,彻底关掉内置 WP-Cron:
define('DISABLE_WP_CRON', true);
保存后,所有 WordPress 定时任务(定时发布、更新检查、备份插件)都不会自动执行了。这正是我们做 WP-Cron 替代的目的——换成可控的外部触发器。
Step 2:创建 systemd service 文件
sudo tee /etc/systemd/system/wp-cron.service << 'EOF'
[Unit]
Description=WordPress Cron Trigger
After=network.target
[Service]
Type=oneshot
User=www-data
ExecStart=/usr/bin/curl -sS -o /dev/null -w "%%{http_code}"
-H "User-Agent: WordPress/wp-cron"
https://你的域名/wp-cron.php?doing_wp_cron=1
EOF
Step 3:创建 systemd timer 文件
sudo tee /etc/systemd/system/wp-cron.timer << 'EOF'
[Unit]
Description=WordPress Cron Timer - Every 5 Minutes
Requires=wp-cron.service
[Timer]
OnCalendar=*:0/5
Persistent=true
Unit=wp-cron.service
[Install]
WantedBy=timers.target
EOF
Persistent=true 保证如果服务器在触发时刻是关机的,开机后立即补跑一次。这是 WP-Cron 替代方案的一个关键配置。
Step 4:启用并验证
sudo systemctl daemon-reload
sudo systemctl enable --now wp-cron.timer
# 查看 timer 状态
sudo systemctl status wp-cron.timer
# 看每次执行的返回码
sudo journalctl -u wp-cron.service -f
如果日志里每 5 分钟出现一次 HTTP 200,WP-Cron 替代就完成了。以后看日志只需要一条命令:journalctl -u wp-cron.service --since "1 hour ago"
WP-Cron 替代方案二:宝塔面板计划任务
如果你已经在用宝塔面板,这个 WP-Cron 替代方案更直观——图形界面,不需要碰 systemd。
- 宝塔面板 → 计划任务 → 添加
- 任务类型:Shell 脚本
- 任务名称:WordPress Cron
- 执行周期:每 5 分钟
- 脚本内容:
#!/bin/bash
/usr/bin/curl -sS -o /dev/null -w "%{http_code}n"
-H "User-Agent: WordPress/wp-cron"
https://你的域名/wp-cron.php?doing_wp_cron=1
>> /www/wwwroot/cron-logs/wp-cron.log 2>&1
先创建日志目录:sudo mkdir -p /www/wwwroot/cron-logs。然后点“执行”手动跑一次,到 /www/wwwroot/cron-logs/wp-cron.log 确认输出是 200。
WP-Cron 替代:两个方案对比
| systemd timer | 宝塔计划任务 | |
|---|---|---|
| 依赖 | 无,纯 Linux 系统功能 | 需要宝塔面板 |
| 日志 | journalctl 统一管理 | 手动指定日志文件 |
| 精确度 | 可以到秒级 | 最短 1 分钟 |
| 失败重试 | 支持 OnFailure | 不支持 |
| 迁移 | 两个文件 scp 到新机器就能用 | 需要在面板里重新创建 |
| 推荐场景 | 任何 Linux 服务器 | 已用宝塔、不想碰命令行 |
WP-Cron 替代常见问题
curl 返回 000 或 403
返回 000 通常意味着连接失败——域名解析不到或者 Nginx 没响应。排查:
# 确认域名能解析到本机
dig +short 你的域名
# 如果解析不到,加 hosts
echo "127.0.0.1 你的域名" >> /etc/hosts
curl -v https://你的域名/wp-cron.php?doing_wp_cron=1
403 是 Nginx 安全规则拦截——检查有没有屏蔽空 User-Agent、有没有拦截本地 IP(127.0.0.1)、wp-cron.php 有没有被 Nginx 规则禁止访问。我们已经加了 User-Agent: WordPress/wp-cron 绕过空 UA 拦截。
定时任务在执行,但文章没有定时发布
先确认 WP-Cron 替代确实在跑:看日志里 HTTP 200 是否每 5 分钟出现。如果 200 正常但定时文章没发,可能是 cron 事件队列出了问题。用 WP-CLI 检查:
wp cron event list --path=/www/wwwroot/你的域名
wp cron event run --due-now --path=/www/wwwroot/你的域名
多个 WordPress 站怎么管理
一台服务器上有多个站都做了 WP-Cron 替代,两种做法:
- 每个站一个 systemd timer,文件命名用站点前缀区分(site-a-cron.timer、site-b-cron.timer)
- 一个统一脚本,把所有站的 wp-cron.php URL 写进数组循环 curl,一个 timer 管所有站
总结
WP-Cron 替代是 WordPress 生产环境必须做的事。禁用了内置 WP-Cron 之后,定时发布、备份、更新才不会在每次页面访问时随机触发——代价就是你必须自己搭一个外部触发器。两个 WP-Cron 替代方案:systemd timer 适合任何 Linux 环境,零依赖、有 journalctl 日志、支持精确到秒和失败重试,是我个人推荐的生产方案;宝塔计划任务 适合已经有面板的环境,图形化操作省心。选哪个看你的习惯,但必须选一个——禁用了不补,定时文章永远发不出去。
如果你在做服务器优化,这两篇可能对你有用:Nginx FastCGI Cache 完整指南、Linux BBR 加速。