Unpatched software is one of the most common attack vectors in cloud VPS environments. When a critical vulnerability is disclosed, the window between public disclosure and active exploitation can be measured in hours. Automatic security updates ensure patches are applied as soon as they become available, dramatically reducing your exposure.
Note: Automatic updates apply to security patches only. Kernel updates typically require a reboot. Consider live-patching solutions such as KernelCare, Canonical Livepatch, or kpatch to avoid scheduled reboots.
Quick Reference
| Distribution | Tool | Package Manager | Update Method |
|---|---|---|---|
| Ubuntu / Debian | unattended-upgrades | apt | Built-in |
| RHEL / AlmaLinux / Rocky | dnf-automatic | dnf | Built-in |
| CentOS Stream 9 | dnf-automatic | dnf | Built-in |
| Fedora | dnf-automatic | dnf | Built-in |
| openSUSE / SLES | zypper + cron | zypper | Cron-based |
| Arch Linux | pacman + timer | pacman | Manual setup |
Prerequisites
- Root or sudo access to the VPS instance
- A working network connection with DNS resolution configured correctly
- Package repositories enabled and reachable — run a manual update first to confirm
- A valid email address or notification endpoint (optional but recommended) for update alerts
- A recent snapshot or backup of the VPS before enabling automatic updates for the first time
Ubuntu and Debian
Ubuntu and Debian use the unattended-upgrades package, which integrates tightly with APT. Ubuntu ships with this pre-installed on most cloud images, while Debian may require manual installation.
Installation
sudo apt update
sudo apt install -y unattended-upgrades apt-listchangesConfiguration
Edit /etc/apt/apt.conf.d/50unattended-upgrades:
Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}-security";
};Unattended-Upgrade::Origins-Pattern {
"origin=Debian,codename=${distro_codename}-security,label=Debian-Security";
};Optional: Automatic Reboot
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "03:00";Optional: Email Notifications
Unattended-Upgrade::Mail "admin@example.com";
Unattended-Upgrade::MailReport "on-change";Remove Unused Dependencies
Unattended-Upgrade::Remove-Unused-Dependencies "true";
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";Enable the Update Timer
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
APT::Periodic::Download-Upgradeable-Packages "1";
APT::Periodic::AutocleanInterval "7";Alternatively, enable defaults interactively: sudo dpkg-reconfigure -plow unattended-upgrades
Verification
# Dry-run to confirm configuration
sudo unattended-upgrades --dry-run --debug
# Check logs for past updates
cat /var/log/unattended-upgrades/unattended-upgrades.log
journalctl -u apt-daily-upgrade.service
# Check timer status
systemctl status apt-daily-upgrade.timerRHEL, AlmaLinux, and Rocky Linux
These distributions use dnf-automatic to handle automated package updates, wrapping DNF with a systemd timer.
Installation
sudo dnf install -y dnf-automaticConfiguration
Edit /etc/dnf/automatic.conf:
[commands]
upgrade_type = security
apply_updates = yes
download_updates = yesEmail Notifications
[emitters]
emit_via = email
[email]
email_from = root@yourvps.example.com
email_to = admin@example.com
email_host = localhostFor logging only (no email), set emit_via = stdio and review output in the journal.
Enable and Verify
sudo systemctl enable --now dnf-automatic-install.timer
# Verify
sudo systemctl status dnf-automatic-install.timer
sudo dnf updateinfo list security
journalctl -u dnf-automatic-install.service💡 Timer variants: dnf-automatic.timer (download only), dnf-automatic-install.timer (download and install), dnf-automatic-notifyonly.timer (notify only). Use the -install variant for fully automatic patching.
CentOS Stream 9
CentOS Stream 9 follows the same dnf-automatic workflow as RHEL. Install dnf-automatic, configure /etc/dnf/automatic.conf with upgrade_type = security and apply_updates = yes, then enable the dnf-automatic-install.timer.
The only notable difference is that CentOS Stream tracks slightly ahead of RHEL releases, so security patches may appear in the repositories a few days earlier.
Fedora
Fedora also uses dnf-automatic with the same configuration file and timer structure as RHEL. Fedora's faster release cycle means security updates are frequent.
sudo dnf install -y dnf-automatic
sudo nano /etc/dnf/automatic.conf
# Set: upgrade_type = security, apply_updates = yes
sudo systemctl enable --now dnf-automatic-install.timersudo systemctl list-timers dnf-*
sudo dnf updateinfo list security⚠️ Fedora Lifecycle: Fedora releases are supported for approximately 13 months. Ensure you upgrade to the next release before end-of-life using sudo dnf system-upgrade.
openSUSE and SLES
openSUSE Leap, Tumbleweed, and SUSE Linux Enterprise Server use zypper. Automatic security updates can be configured using a systemd timer or a cron job.
Method 1: Systemd Timer (Recommended)
[Unit]
Description=Automatic zypper security patch
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/bin/zypper --non-interactive patch --category security[Unit]
Description=Daily security patch timer
[Timer]
OnCalendar=*-*-* 03:30:00
RandomizedDelaySec=1800
Persistent=true
[Install]
WantedBy=timers.targetsudo systemctl daemon-reload
sudo systemctl enable --now zypper-security-update.timerMethod 2: Cron Job
echo "30 3 * * * root /usr/bin/zypper --non-interactive patch --category security 2>&1 | logger -t zypper-auto" | sudo tee /etc/cron.d/zypper-securityVerification
sudo systemctl status zypper-security-update.timer
sudo zypper list-patches --category security💡 In enterprise SLES environments managed by SUSE Manager, automatic patching is typically handled through the management server's scheduling system rather than local zypper timers.
Arch Linux
⚠️ Rolling Release Warning: Arch does not offer security-only updates. An automatic update applies all available package upgrades, which may include major version bumps. Test in a staging environment first and always maintain current backups.
[Unit]
Description=Automatic pacman system upgrade
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/bin/pacman -Syu --noconfirm[Unit]
Description=Daily system upgrade timer
[Timer]
OnCalendar=*-*-* 04:00:00
RandomizedDelaySec=1800
Persistent=true
[Install]
WantedBy=timers.targetsudo systemctl daemon-reload
sudo systemctl enable --now pacman-update.timer
# Verify
sudo systemctl status pacman-update.timer
journalctl -u pacman-update.service --since todayPost-Configuration Best Practices
Handling Kernel Updates and Reboots
- Scheduled reboots: Configure auto-reboot (where available) during a maintenance window such as 3:00 AM
- Live kernel patching: Use KernelCare, Canonical Livepatch, or kpatch for high-availability workloads
- Reboot detection: Install
needrestart(Debian/Ubuntu) orneeds-restarting(RHEL family) to identify when reboots are required
Monitoring and Alerting
- Review systemd timer logs weekly with
journalctl - Configure email notifications to receive alerts when patches are applied or errors occur
- Use external monitoring (Uptime Kuma, Prometheus, or your provider's monitoring) to detect unexpected downtime
Backup Strategy
Take VPS snapshots on a regular schedule, ideally before the update window. Tools like restic or borgbackup provide file-level backup redundancy.
Excluding Packages
- Ubuntu/Debian: Add packages to
Unattended-Upgrade::Package-Blacklistin50unattended-upgrades - RHEL/Fedora: Add
exclude = package_nameunder[commands]inautomatic.conf - openSUSE/SLES: Use zypper locks:
zypper addlock package_name - Arch: Add packages to the
IgnorePkgline in/etc/pacman.conf
Troubleshooting
Timer Not Active
Confirm the timer unit is enabled and scheduled:
systemctl list-timers --all | grep -i auto
systemctl list-timers --all | grep -i dnf
systemctl list-timers --all | grep -i zypperIf not listed, re-enable with systemctl enable --now followed by the timer unit name.
Updates Failing Silently
Check the journal for error output:
journalctl -u unattended-upgrades.service --since yesterday
journalctl -u dnf-automatic-install.service --since yesterdayCommon causes: stale repository metadata, disk space exhaustion, or dpkg/rpm lock conflicts from a concurrent manual operation.
Package Conflicts
If an update fails due to a dependency conflict, the tool will skip conflicting packages and log the error. Resolve manually and the next automatic run picks up the remaining updates.
Network Issues
If the VPS cannot reach package repositories, updates will fail. Verify DNS resolution and outbound HTTPS connectivity. Ensure outbound access to your distribution's mirror network is permitted in your firewall configuration.
Testing Your Configuration
- Run the update tool manually in dry-run or verbose mode to confirm it targets the correct repositories
- Verify the systemd timer (or cron job) is active and scheduled for the expected time
- Wait for one full cycle and check logs to confirm updates were applied without errors
- If email notifications are configured, confirm you receive the test notification
- Confirm excluded packages remain at their current version after the update cycle
