Why I stopped cPanel auto-updates and schedule WHM upgrades manually
I've run dedicated servers for over a decade. I've seen every flavor of Linux, every version of cPanel, and the pain of a surprise upgrade at 3am.
Why I killed the auto-update daemon
I've run dedicated servers for over a decade. I've seen every flavor of Linux, every version of cPanel, and the pain of a surprise upgrade at 3am.
By default, cPanel installs /usr/local/cpanel/scripts/update --auto and runs it via whostart or a systemd timer. That sounds nice until it touches /usr/local/lib64/php, /usr/local/cpanel/3rdparty, or the Apache module stack.
One night, a cPanel auto-update bumped PHP from 8.2 to 8.3 without my consent. Two sites went down because a popular plugin wasn't compatible. The auto-updater didn't ask for a dry run. It didn't take a snapshot. It just changed things.
I switched to a manual schedule. I now run WHM upgrades on a Tuesday night window, after backups finish. No surprises.
Find and disable the auto-update timer
On Ubuntu 24.04 or AlmaLinux 9, cPanel installs a systemd timer under /etc/systemd/system/cpanel-updates.timer. Check it first:
systemctl list-timers | grep cpanel
You'll see something like:
Mon Jan 13 00:00:00 2025
Mon Jan 13 00:00:00 2025
...
cpanel-updates.timer (Sat Jun 21 00:00:00 2025)
If the timer exists, disable and stop it:
systemctl disable cpanel-updates.timer
systemctl stop cpanel-updates.timer
rm -f /etc/systemd/system/cpanel-updates.timer
Some versions also use a cron file. Check /var/spool/cron/root and /etc/cron.d:
ls -la /var/spool/cron/root
cat /var/spool/cron/root
If you find a line like /usr/local/cpanel/scripts/update --auto > /dev/null 2>&1, remove it or comment it out. I usually comment it so I can re-enable it later if needed:
echo '# /usr/local/cpanel/scripts/update --auto > /dev/null 2>&1' >> /var/spool/cron/root
Confirm the daemon is gone
Run this to be sure nothing is triggering updates in the background:
ps aux | grep -E 'update.*auto|cpanel.*update'
You should see only the cPanel updater process if you run it manually. If you see a daemon named cpanel-update-daemon or similar, kill it:
killall cpanel-update-daemon
Also check the cPanel status page for any scheduled tasks:
/usr/local/cpanel/scripts/uploaddir --list
That last one is a bit obscure, but sometimes cPanel stores scheduled tasks in the upload directory. If you see anything suspicious, delete it.
Set up a safe upgrade schedule
I prefer a weekly window on Tuesday night. Here's how to create a cron job that runs WHM upgrades with a pre-check and a post-check.
First, create a script at /usr/local/bin/whm-upgrade-safe.sh:
#!/bin/bash
set -euo pipefail
BACKUP_DIR="/backup/cpanel/last-upgrade"
LOG="/var/log/cpanel-upgrade.log"
DATE=$(date +%Y%m%d)
# Ensure backup directory exists
mkdir -p "$BACKUP_DIR"
# Pre-check: ensure no critical services are running
if systemctl is-active --quiet nginx; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] WARNING: nginx is active. Skipping upgrade." >> "$LOG"
exit 0
fi
if systemctl is-active --quiet httpd; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] WARNING: httpd is active. Skipping upgrade." >> "$LOG"
exit 0
fi
# Optional: take a snapshot before upgrade
# /usr/local/cpanel/scripts/snapshot --full --backup-dir="$BACKUP_DIR" --date="$DATE"
# Run the upgrade
/usr/local/cpanel/scripts/update --rebuild
# Post-check: verify services
if systemctl is-active --quiet nginx; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] OK: nginx is active after upgrade." >> "$LOG"
else
echo "[$(date '+%Y-%m-%d %H:%M:%S')] ERROR: nginx is inactive after upgrade." >> "$LOG"
fi
if systemctl is-active --quiet httpd; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] OK: httpd is active after upgrade." >> "$LOG"
else
echo "[$(date '+%Y-%m-%d %H:%M:%S')] ERROR: httpd is inactive after upgrade." >> "$LOG"
fi
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Upgrade completed or skipped." >> "$LOG"
Make it executable:
chmod +x /usr/local/bin/whm-upgrade-safe.sh
Now create a cron entry to run it every Tuesday at 03:00:
0 3 * * 2 /usr/local/bin/whm-upgrade-safe.sh
Add that line to /etc/cron.d/cpanel-weekly-upgrade or to /var/spool/cron/root. I prefer /etc/cron.d because it's easier to manage for multiple servers.
Test the script manually first
Before you let cron run it, test the script manually. Run it with -x to see debug output:
/usr/local/bin/whm-upgrade-safe.sh -x
Watch the log file:
tail -f /var/log/cpanel-upgrade.log
If the script exits with an error, check the cPanel error logs:
tail -100 /var/cpanel/errorlog
Also check journalctl for systemd messages:
journalctl -u cpanel-updates.timer -n 50
If you see an error about PHP version mismatch or a missing module, fix it before scheduling the upgrade.
Keep a rolling backup of the upgrade script
I store one copy of the upgrade script in a git repo. That way, if I change the logic, I can push a new version to all servers with a single commit.
Example git push:
git add /usr/local/bin/whm-upgrade-safe.sh
git commit -m "Update upgrade script for PHP 8.3 compatibility"
git push origin main
Then pull on all servers:
git pull origin main
This keeps your upgrade logic consistent across your fleet.
Monitor upgrade success/failure
After the cron job runs, check the log file:
cat /var/log/cpanel-upgrade.log
If you see "ERROR" entries, investigate immediately. You can also set up a simple alert using a monitoring tool like Nagios, Zabbix, or Prometheus. For example, alert if the log contains "ERROR" within the last hour.
One trick: parse the log with grep and send a Slack message if an error occurs:
grep -i 'ERROR' /var/log/cpanel-upgrade.log | while read line; do
curl -X POST -H 'Content-type: application/json' --data "{\"text\":\"cPanel upgrade error: $line\"}" $SLACK_WEBHOOK
done
Replace $SLACK_WEBHOOK with your actual webhook URL.
Final checklist before you disable auto-updates
- Disable the systemd timer and any cron jobs that run auto-updates.
- Remove or comment out any lines in
/etc/cron.dor/var/spool/cronthat call/usr/local/cpanel/scripts/update --auto. - Create a manual upgrade script that checks services before and after the upgrade.
- Schedule the script via cron for a low-traffic window (Tuesday 03:00).
- Test the script manually once before enabling it.
- Monitor the log file for errors after each run.
- Keep the upgrade script under version control.
By following these steps, you regain full control over when your cPanel/WHM stack is upgraded. No more midnight surprises, no more broken PHP versions, and no more lost sites.