Security patches arrive daily. If you patch manually, you are always behind. Unattended-upgrades is the built-in mechanism on Debian and Ubuntu that automatically installs security updates without human intervention. Configured correctly, it keeps your VPS patched within hours of a CVE being fixed while avoiding the risk of a broken update taking down your production services. This guide covers setup, fine-tuning, monitoring, and the edge cases that trip people up.
How Unattended Upgrades Work
The unattended-upgrades package runs as a systemd timer (or cron job on older systems). It checks the apt package cache for available updates, filters them by origin (security, stable, backports), downloads the matching packages, and installs them. It can also automatically reboot the server if a kernel update was installed and email you a summary of what it did.
By default, Ubuntu Server and Debian install the package but only enable it for security updates. This is the correct starting point — security patches are tested and unlikely to break anything.
Step 1: Install and Enable
# Install the package (usually already present)
sudo apt install unattended-upgrades apt-listchanges -y
# Enable it for the first time
sudo dpkg-reconfigure -plow unattended-upgrades
# Select "Yes" when prompted
Verify the timer is active:
sudo systemctl status apt-daily-upgrade.timer
# Or check the timer schedule
sudo systemctl list-timers apt-daily-upgrade.timer
Step 2: Configure Update Sources
Edit /etc/apt/apt.conf.d/50unattended-upgrades. The critical section is the Unattended-Upgrade::Allowed-Origins block. A secure configuration for a production VPS:
Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}-security";
"${distro_id}ESMApps:${distro_codename}-apps-security";
"${distro_id}ESM:${distro_codename}-infra-security";
};
This limits automatic updates to security patches only. Do not add ${distro_codename}-updates unless you have a staging environment that tests updates before they reach production. A non-security package update can break your application stack.
Step 3: Blacklist Packages That Should Never Auto-Update
Some packages are too risky to update automatically. Add a blacklist in the same configuration file:
Unattended-Upgrade::Package-Blacklist {
"mysql-server";
"mysql-server-8.0";
"postgresql";
"redis-server";
"docker-ce";
"docker-ce-cli";
"containerd.io";
};
Database servers, container runtimes, and custom-compiled packages should be updated manually during a maintenance window. A database major version bump applied automatically at 3 AM is a fast path to an outage.
Step 4: Configure Automatic Reboots
Kernel security updates take effect only after a reboot. Unattended-upgrades can handle this automatically:
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "04:00";
Unattended-Upgrade::Automatic-Reboot-WithUsers "false";
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
Unattended-Upgrade::Remove-New-Unused-Dependencies "true";
The Automatic-Reboot-WithUsers setting is important: when set to false, the server will not reboot if a user is logged in via SSH. This prevents interrupting an active admin session. Set it to true only if you are confident nobody will be logged in at 4 AM.
If you run a service that needs a graceful shutdown before reboot, add a pre-reboot hook:
# /etc/kernel/postinst.d/zzz-pre-reboot
#!/bin/bash
# This script runs before the automatic reboot
systemctl stop my-custom-app
sleep 5
Step 5: Email Notifications
You need to know what unattended-upgrades is doing. Configure email reports:
Unattended-Upgrade::Mail "[email protected]";
Unattended-Upgrade::MailReport "on-change";
Unattended-Upgrade::SyslogEnable "true";
Unattended-Upgrade::SyslogFacility "daemon";
The on-change setting sends an email only when packages were actually installed, not every day. For email delivery, your VPS needs a functioning MTA. A minimal setup with msmtp or postfix relaying through an external SMTP server works well:
# Install a lightweight mail sender
sudo apt install msmtp msmtp-mta -y
# Configure /etc/msmtprc with your SMTP credentials
# Then test
echo "Test from unattended-upgrades" | mail -s "Test" [email protected]
Step 6: Dry Run and Verify
Before letting unattended-upgrades run on its own, simulate what it would do:
# Dry run — shows what would be installed without doing it
sudo unattended-upgrade --dry-run --debug
# Check the log for any issues
sudo tail -f /var/log/unattended-upgrades/unattended-upgrades.log
The dry run output lists every package that would be upgraded. Look for anything surprising — a kernel update on a system that should not reboot, or a database package that slipped past the blacklist.
Production Hardening Checklist
- Stagger the update time: Edit
/lib/systemd/system/apt-daily-upgrade.timeroverride to randomize the update window. This prevents every VPS in a fleet from updating simultaneously. - Monitor with Netdata or Prometheus: Track the
unattended-upgradeslog for errors. A failed update that goes unnoticed for weeks is worse than no update at all. - Test on a staging VPS first: If you run a custom application stack, mirror the configuration on a staging VPS and let unattended-upgrades run there for a week before enabling it on production.
- Keep a rollback plan: Unattended-upgrades does not create snapshots. If an update breaks your application, you need a way to roll back. Consider VPS snapshots from your provider or
apt-btrfs-snapshoton Btrfs filesystems. - Check
/var/run/reboot-required: After a kernel update, this file is created. Include a check for it in your monitoring.
Troubleshooting Common Issues
- Updates not running: Check the timer:
sudo systemctl list-timers apt-daily-upgrade.timer. If the timer is inactive, enable it:sudo systemctl enable --now apt-daily-upgrade.timer. - “dpkg was interrupted” errors: A previous update was interrupted. Run
sudo dpkg --configure -ato fix the package state, thensudo unattended-upgrade -dto retry. - Disk space exhaustion: Unattended-upgrades downloads packages to
/var/cache/apt/archives/. If disk space is tight, addUnattended-Upgrade::Remove-Unused-Dependencies "true";to clean up after each run. - Custom repositories: If you added third-party repositories (Docker, HashiCorp, etc.), their updates are not covered by default. Add their origin lines explicitly if you want them auto-updated — but this is generally not recommended for production.
Unattended-upgrades is the simplest security automation you can deploy on a VPS. It eliminates the gap between CVE disclosure and patch application, and it does so with a conservative, Debian-tested approach. For more on securing your VPS, visit our VPS hosting guides.

Leave a Reply
You must be logged in to post a comment.