Unattended Security Updates on Ubuntu
Patching isn't hard. Remembering to apt-get upgrade on a dozen machines is, and I skip it whenever I'm busy, which is always. Ubuntu's unattended-upgrades does it for me: install security updates, reboot at a quiet hour if needed, mail a summary.
This is Ubuntu 18.04 (16.04 has the same files), limited to the security pocket, with controlled reboots and a blacklist for packages that need a human. Reports need some way for the server to send mail, like the mailx SMTP setup or a local Postfix relay.
Turning it on
Most Ubuntu server images already have it:
sudo apt-get install -y unattended-upgrades apt-listchanges
sudo dpkg-reconfigure -plow unattended-upgrades
Choose "Yes" at the prompt. This writes /etc/apt/apt.conf.d/20auto-upgrades:
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
Values are in days: refresh lists daily, run the upgrader daily. On 18.04 two systemd timers drive it, apt-daily.timer (downloads) and apt-daily-upgrade.timer (installs), not cron.
What to upgrade
The main config is /etc/apt/apt.conf.d/50unattended-upgrades. The default Allowed-Origins already limits it to security updates; I check that only that line and ESM (if applicable) are active and the rest are commented out:
Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}-security";
"${distro_id}ESM:${distro_codename}";
// "${distro_id}:${distro_codename}-updates";
// "${distro_id}:${distro_codename}-proposed";
// "${distro_id}:${distro_codename}-backports";
};
Enabling -updates adds bug-fix releases too. I leave it on for general-purpose web servers and off for database hosts, which I upgrade deliberately.
Packages that need a human
Some things shouldn't upgrade unless someone is watching: the database server, a kernel on a host with out-of-tree modules, anything with a manual migration step.
Unattended-Upgrade::Package-Blacklist {
"mysql-server";
"mysql-server-5.7";
"postgresql-10";
"linux-image-";
"docker-ce";
};
Entries are regexes anchored at the start, so linux-image- matches every kernel package. Blacklisting the kernel is a trade-off: its security fixes wait for my maintenance window. On hosts where a surprise reboot is unacceptable, I'll take that.
Reboots and cleanup
Further down the same file:
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
Unattended-Upgrade::Remove-Unused-Dependencies "true";
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-WithUsers "false";
Unattended-Upgrade::Automatic-Reboot-Time "04:30";
Automatic-Reboot only reboots when /var/run/reboot-required exists, which a kernel or libc update creates. WithUsers "false" skips the reboot if anyone is logged in, so a late-night troubleshooting session doesn't get cut off. With the kernel blacklisted, reboots almost never trigger anyway.
Mail reports
Unattended-Upgrade::Mail "ops@example.com";
Unattended-Upgrade::MailOnlyOnError "true";
MailOnlyOnError keeps the inbox quiet; you hear about it only when a package fails to configure. I set it to false for the first couple of weeks to see what's being applied. Reports go out via the local mail command, so mailutils, bsd-mailx or s-nail must be installed and set up to relay.
Timer schedule
The default timers fire at random times to spread load on the mirrors. I want a predictable window across a fleet, so I override the upgrade timer:
sudo systemctl edit apt-daily-upgrade.timer
[Timer]
OnCalendar=
OnCalendar=*-*-* 04:00
RandomizedDelaySec=20m
The empty OnCalendar= clears the packaged value before setting yours. Reload with sudo systemctl daemon-reload and check systemctl list-timers apt-daily*.
Dry run
This shows what would happen without changing anything:
sudo unattended-upgrade --dry-run --debug
It lists the allowed origins, every candidate package, and whether it's blacklisted. After the first real run, read the logs:
sudo tail -n 50 /var/log/unattended-upgrades/unattended-upgrades.log
sudo tail /var/log/unattended-upgrades/unattended-upgrades-dpkg.log
systemctl status apt-daily-upgrade.timer shows the next scheduled trigger.
Notes
Allowed origins are: ...thenNo packages found that can be upgraded unattended, whileapt list --upgradableshows security updates: origin strings don't match. Compareapt-cache policyo=anda=fields with what you wrote; on 18.04 it must beUbuntu:bionic-security.- The upgrader never runs and
systemctl list-timersshows the timer inactive:APT::Periodic::Unattended-Upgradeis0. Rerundpkg-reconfigureor edit20auto-upgrades. E: Could not get lock /var/lib/dpkg/lock-frontend:apt-dailywas running when you ranapt-getby hand. Wait a minute.- No mail arrives:
/usr/bin/mailis missing.apt-get install bsd-mailxand set up relay;Unable to send mailin the log confirms it. - A service restarted during the update window and nobody expected it:
needrestart(on 18.04) restarting services with updated libraries. Set$nrconf{restart} = 'l';in/etc/needrestart/needrestart.confto list instead.
It's no substitute for a real patch schedule, but it shrinks the gap between "patch released" and "someone got round to it" from weeks to a day.