My Server Journal

Letting Ubuntu patch itself with unattended-upgrades

A server I log into once a month should not be waiting a month for security updates. Ubuntu ships unattended-upgrades for exactly this; on a fresh LTS it is usually installed and half-configured. This is the other half.

Confirm it is on

sudo apt install unattended-upgrades
cat /etc/apt/apt.conf.d/20auto-upgrades

You want both lines set to "1":

APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";

If the file is missing, sudo dpkg-reconfigure -plow unattended-upgrades writes it.

What it upgrades

By default only the -security pocket, which is what I want: security fixes land on their own, and feature updates wait for a human. The relevant part of /etc/apt/apt.conf.d/50unattended-upgrades is the Allowed-Origins list; the security origin is enabled and the updates origin is commented out. I left it that way.

Two settings I did change in that file:

Unattended-Upgrade::Remove-Unused-Dependencies "true";
Unattended-Upgrade::Automatic-Reboot "false";

Removing unused dependencies stops old kernels from piling up in /boot, which on a small disk is a real failure mode. Automatic reboot stays off because I would rather choose when the server goes down, even for thirty seconds.

Knowing when a reboot is needed

A kernel update is applied to disk but the running kernel is the old one until reboot. The package manager leaves a marker:

ls /var/run/reboot-required && cat /var/run/reboot-required.pkgs

I check it when I log in. Ubuntu also prints the hint in the login banner, and needrestart (installed by default on 24.04) lists services still running old libraries after an upgrade. When the list is long or includes sshd, a reboot is simpler than restarting things one by one.

Reading what it did

sudo tail -n 40 /var/log/unattended-upgrades/unattended-upgrades.log

Every run is logged, including the runs that found nothing. The first time I looked I discovered the timer had been failing for weeks because the machine's clock was wrong enough that repository signatures looked expired. NTP fixed it; the log is the only reason I found out.

What this does not cover

Anything not installed through apt: a Go binary in /usr/local/bin, a Docker image, a pip package. Those need their own update routine, and forgetting that is how a "fully patched" server ends up running a two-year-old web server.