Nearly every VPS compromise we get called about traces back to the same root cause: a package that had a fix available for weeks, sometimes months, before someone finally exploited it. Not a zero-day, not a clever attacker — just a security patch that nobody got around to installing. If you're running a plain VPS without cPanel babysitting things for you, here's how to make sure that stops happening on its own.
Why "I'll Patch It This Weekend" Doesn't Work
Everyone means to run dnf update or apt upgrade regularly. Then a client emergency eats your Friday, the server keeps humming along fine, and three weeks pass. Meanwhile OpenSSL, sudo, or your kernel picked up a CVE with a public exploit and your VPS is sitting there exposed. Automating just the security-relevant patches closes that gap without you having to remember anything.
The One Thing You Should NOT Fully Automate
Full, unattended dnf update -y or apt upgrade -y across every package — including MySQL major versions, PHP, or a kernel that changes ABI — can break a running site with zero warning. What you actually want is security-only automatic updates, with everything else left for you to review and apply manually (or through your control panel). Every setup below is scoped that way.
AlmaLinux / Rocky Linux / CentOS Stream: dnf-automatic
This is the built-in tool on RHEL-family systems, including most cPanel VPS installs underneath the hood.
dnf install -y dnf-automatic
Edit /etc/dnf/automatic.conf and set these two values:
[commands]
upgrade_type = security
apply_updates = yes
Then enable the timer that actually runs it (not the raw service — the timer schedules it, staggered, once a day):
systemctl enable --now dnf-automatic.timer
systemctl status dnf-automatic.timer
Want notification-only, no auto-apply, so you get an email and decide yourself? Set apply_updates = no and configure the [emitters] section with emit_via = email plus your email_to address. That's a reasonable middle ground if you'd rather review a diff before it touches production.
Ubuntu / Debian: unattended-upgrades
Debian-family systems use a different package with the same idea.
apt update
apt install -y unattended-upgrades apt-listchanges
Run the interactive setup once:
dpkg-reconfigure --priority=low unattended-upgrades
Then check /etc/apt/apt.conf.d/50unattended-upgrades. By default, only the -security origin is enabled — leave it that way unless you specifically want -updates included too:
Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}-security";
};
Confirm the daily timer is actually enabled in /etc/apt/apt.conf.d/20auto-upgrades:
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
If You're Running cPanel/WHM
WHM's Update Preferences page controls how cPanel & WHM itself updates — the update tier (Stable, Release, Edge) and EasyApache rebuilds. It does not patch the underlying OS packages like OpenSSL, sudo, or the kernel. On a cPanel box you still need dnf-automatic configured exactly as above; the two systems patch completely different layers and neither substitutes for the other.
Handling Reboots for Kernel Updates
A security-only patch policy will still occasionally include a kernel CVE, and that only takes effect after a reboot. Two sane options:
- Notify, don't auto-reboot. Install
needrestart(RHEL) or let unattended-upgrades log which services need restarting, then reboot yourself during a maintenance window. This is what we recommend for anything running live traffic. - Auto-reboot in a defined low-traffic window. In
50unattended-upgrades, setUnattended-Upgrade::Automatic-Reboot "true";andUnattended-Upgrade::Automatic-Reboot-Time "04:30";. On dnf-automatic there's no built-in reboot trigger — you'd add a small cron job checkingneeds-restarting -rand rebooting only if it returns non-zero.
If your app can't tolerate a surprise 30-second reboot, take a snapshot before enabling auto-reboot, or stick with notify-only.
Verify It's Actually Running
Don't just trust the config file. Check the logs after the first scheduled run:
| System | Log to check | Dry-run command |
|---|---|---|
| AlmaLinux/Rocky | /var/log/dnf.log | dnf-automatic --timer |
| Ubuntu/Debian | /var/log/unattended-upgrades/unattended-upgrades.log | unattended-upgrade --dry-run --debug |
If the dry-run lists CVEs it intends to patch and the timer shows as active (waiting) in systemctl status, you're set.
Prevention Checklist
- Scope automation to security updates only — full unattended upgrades are how a routine patch takes down a production database at 3 a.m.
- Keep an eye on
needs-restarting -ror the unattended-upgrades log weekly, even with automation on, so you know when a reboot is overdue. - Pair this with a snapshot schedule — if a patch ever does cause a regression, you want a five-minute rollback, not a scramble.
- On a cPanel VPS, remember WHM's update tier and dnf-automatic are two separate systems and both need to be configured.
Frequently Asked Questions
Will this update PHP, MySQL, or my kernel to a new major version?
No, not with the security-only scope described here. Major version bumps for PHP, MySQL/MariaDB, or the kernel come through the full package channel and stay outside what security-only automation touches. You still control those upgrades manually or through WHM's MultiPHP Manager.
Is dnf-automatic safe to run on a live production server?
Yes, when scoped to upgrade_type = security. Security patches are narrowly targeted fixes, not feature changes, so the chance of a regression is low — much lower than the risk of leaving a known CVE unpatched.
How do I know which CVEs were actually patched?
Check the dnf or apt log after a run — both list the exact packages and versions applied. You can also grep /var/log/dnf.log for a specific date if you want to confirm a patch landed after a CVE announcement.
What if I'd rather approve updates manually instead of auto-applying?
Set apply_updates = no in dnf-automatic (or skip the auto-apply flag in unattended-upgrades) and configure email notifications instead. You'll get an alert listing what's available, then apply it yourself with a normal dnf update or apt upgrade once you've reviewed it.
Does this replace CSF, firewalld, or fail2ban?
No — automatic patching and a firewall solve different problems. Patching closes known vulnerabilities before they're exploited; a firewall and intrusion-prevention tool limit what can reach your server in the first place. Run both.
