Automatic updates with unattended-upgrades on Debian and Ubuntu

Linux releases get updates often, and security updates should be installed promptly. Debian and Ubuntu use the APT system, and while it is relatively easy to install all pending updates manually, the admin may not remember to do it or prefers sleeping at night instead of checking for updates. This article is mainly for server installations.

Updating and installing packages manually using apt upgrade is still possible when using unattended-upgrades. If an upgrade started by unattended-upgrades happens to be running when apt is used from the command line, the apt system informs the user an operation is already in progress and the user must wait until it finishes before continuing with issuing apt commands.

An easy way for busy admins

Install unattended-upgrades, check it is enabled, and monitor their working from log files.

apt install unattended-upgrades
dpkg-reconfigure -plow unattended-upgrades

The dpkg-reconfigure -command shows dialog box asking yes or no to automatically download and install stable security updates. Check it is answered yes.

unattended-upgrades checks for updates twice daily at random times, and installs stable security updates.

Monitor what is happening by reading log files in directory /var/log/unattended-upgrades/ and file /var/log/dpkg.log.

Where to find documentation

The configuration file /etc/apt/apt.conf.d/50unattended-upgrades has documentation in the comments. This document refers to that file from now on as 50unattended-upgrades.

The readme file /usr/share/doc/unattended-upgrades/ has useful instructions. It can be read with command zless (available from package gzip). This document refers to that file from now on as README.

Debian wiki has a page

Ubuntu server docs page has a chapter "Automatic Updates" about unattended-upgrades.

Man page of unattended-upgrade, man unattended-upgrade.

Advanced configuration

Using the easy way you will notice not all upgrades are installed automatically. You may also want more control on what is happening automatically in addition to installing updates.

The configuration file /etc/apt/apt.conf.d/50unattended-upgrades has documentation included in the comments, so read the file to examine what configurations are available. Very useful is configuring unattended-upgrades to send e-mails when something happens.

It is important to know that the configuration file is created by the unattended-upgrades package installation or upgrade, so when unattended-upgrades itself is upgraded or when going to the next OS version edits done in this file cause conflicts that must be resolved manually. The documentation file README suggest creating file 52unattended-upgrades-local instead of modifying the original configuration file.

If you want, you can check file /etc/apt/apt.conf.d/20auto-upgrades that it contains these lines:

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

If you ran the dpkg-reconfigure -command and answered yes the lines should be there. The lines control enabling unattended-upgrades.

Send e-mail

For sending e-mail to work, the host must have a working e-mail system that can send e-mails. Verify that first.

Enable sending e-mail from unattended-upgrades by editing the configuration file 52unattended-upgrades-local (create the file if it does not exist in directory /etc/apt/apt.conf/). Copy the line

//Unattended-Upgrade::Mail "";

from 50unattended-upgrades, uncomment it, and add the target e-mail address between the "-quotes.

There is also a setting to configure if e-mail is always sent when unattended-upgrades do an upgrade, or only on errors.

// Set this value to "true" to get emails only on errors. Default
// is to always send a mail if Unattended-Upgrade::Mail is set
//Unattended-Upgrade::MailOnlyOnError "false";

If you want to change the setting, copy the lines to 52unattended-upgrades-local, uncomment the setting line and change "false" to "true".

Checking with

unattended-upgrade --dry-run -d

is a good idea after modifying the configuration file.

At least on Debian 10, 11, and Ubuntu 22.04, unattended-upgrades installation makes a symbolic link unattended-upgrades to unattended-upgrade in directory /usr/bin/ and/or /bin/, so both commands work the same.

$ ls -lhi /bin/unattended-upgrade*
11404505 -rwxr-xr-x 1 root root 98K tammi  15  2022 /bin/unattended-upgrade
11407087 lrwxrwxrwx 1 root root  18 tammi  15  2022 /bin/unattended-upgrades -> unattended-upgrade

Add repository

Adding a repository to automatically update from is done by adding lines to Unattended-Upgrade::Origins-Pattern. There is documentation about this in the configuration file.

The README instructs the settings in the later configuration file 52unattended-upgrades-local to override the default settings. I tried and found setting Unattended-Upgfade::Origins-Pattern does not completely override what was set in the default file, instead, it is added to the defaults. So it is not necessary to copy the complete default Unattended-Upgrade::Origins-Pattern, it can be added to.

For example, the package goaccess does not upgrade automatically when it is installed from Official GoAccess Repository. It would upgrade automatically if it were installed from the usual Debian repository (it is available from both). Adding GoAccess repository to the Origins-Pattern makes unattended-upgrades do the upgrade.

Examine the situation with apt list --upgradable:

root@posti:~# LANG=C apt list --upgradable 
Listing... Done
goaccess/unknown 2:1.6.3-buster amd64 [upgradable from: 2:1.6.2-buster]
php-tcpdf/buster-backports 6.5.0+dfsg1-1~bpo10+1 all [upgradable from: 6.3.5+dfsg1-1~bpo10+1]

So there are two packages that did not get upgraded automatically by unattended-upgrades. Examining goaccess shows it comes from GoAccess Official Repository (and an older version from the usual Debian repository).

root@posti:~# LANG=C apt policy goaccess
  Installed: 2:1.6.2-buster
  Candidate: 2:1.6.3-buster
  Version table:
     2:1.6.3-buster 500
        500 buster/main amd64 Packages
 *** 2:1.6.2-buster 100
        100 /var/lib/dpkg/status
     1:1.2-4+b10 500
        500 buster/main amd64 Packages
        500 buster/main amd64 Packages

Running unattended-upgrade --dry-run -d shows what origins the not installed packages have. This may help figuring out what needs to be added to Origins-Pattern.

Examining the log from latest run of unattended upgrades shows what origins are considered when upgrading automatically:

2022-09-05 08:28:08,955 INFO Checking if system is running on battery is skipped. Please install
    powermgmt-base package to check power status and skip installing updates when the system
    is running on battery.
2022-09-05 08:28:08,960 INFO Initial blacklist : 
2022-09-05 08:28:08,960 INFO Initial whitelist: 
2022-09-05 08:28:08,960 INFO Starting unattended upgrades script
2022-09-05 08:28:08,960 INFO Allowed origins are: 

GoAccess repository is not there yet, so now I add it to /etc/apt/apt.conf.d/52unattended-upgrades-local.

As an aside, if you have installed unattended-upgrades on a laptop, consider installing powermgmt-base. Using that unattended-upgrades does not start upgrades when running on battery power, like the info message in log informs. If running on a server that is always running on line power, that info message is no longer shown with Unattended-Upgrade::OnlyOnACPower "false"; added to the configuration.

Unattended-Upgrade::Origins-Pattern {
// Taleman added GoAccess 2022-09-05
        "o=GoAccess Repository, n=buster, l=Official GoAccess Repository";
Unattended-Upgrade::OnlyOnACPower "false";

apt policy did not show field a for GoAccess, so I used o, n and l. Find info on these fields in README.

Variable substitution is supported for ${distro_id} that contains the output of lsb_release -i and ${distro_codename} that contains the output of lsb_release -c. So instead of n=buster I could have written n=${distro_codename}.

There were two packages not upgraded automatically, the other that is still not upgraded is php-tcpdf. It can of course be upgraded with apt upgrade but it can be added to unattended-upgrades to be automatically upgraded. The procedure is the same as for goaccess.

First examine the situation with apt policy php-tcpdf. That shows it is installed from Debian repository section buster-backports.

From unattended-upgrades.log it can be seen buster-backports is not among the allowed origins. It is in 50unattended-upgrades file but commented out. To enable it, copy the line

// "o=Debian Backports,a=${distro_codename}-backports,l=Debian Backports";

to 52unattended-upgrades-local inside the Origins-Pattern setting and uncomment.

After editing the file, check with unattended-upgrades --dry-run -d the added repository is now among the "Allowed origins" and php-tcpd is among the packages that will be upgraded.

Control times

Unattended-upgrades runs at random times to ease the load on repository servers. This is to avoid large load spikes that would happen if all hosts started doing updates at the same time. Think carefully if you decide to change this behavior. If you run your own repository or mirror repository, then the load spikes hit your repository server and you avoid annoying the admins of repositories on the Internet.

It is systemd that controls at what times unattended-upgrades starts. The file /lib/systemd/system/apt-daily.timer has Timer section that starts apt download activities twice daily with 12 hour random delay. I suggest you do not modify this, or have very good reasons for modifying.

The rest of the time configurations are done in the 50unattended-upgrades and 52unattended-upgrades-local files.

The setting Unattended-Upgrade::Update-Days controls days of week unattended-upgrades runs. The default is empty which means run every day. It can be configured to run for example only on Saturday and Sunday.

Automatic reboot

Unattended-upgrades can be set to reboot when the installed updates require a reboot. This can be configured to happen immediately or at a desired time. These configurations use settings

//Unattended-Upgrade::Automatic-Reboot "false";
//Unattended-Upgrade::Automatic-Reboot-WithUsers "true";
//Unattended-Upgrade::Automatic-Reboot-Time "02:00";	

Default is no automatic reboot. If you change the setting to "true", reboot happens immediately the upgrade is installed. Automatic-Reboot-Time can be set to do the reboot at a desired time if there are installed updates that require a reboot.

Blacklisting, Whitelisting

A blacklist prevents a package, that otherwise would be upgraded by unattended-upgrades, from getting upgraded. The setting Package-Blacklist contains regular expressions. If the package name matches, it is excluded from the automatic upgrade.

I have not used this feature, I think it may be more useful if running a development release where it makes sense to prevent automatic upgrade of critical packages. The 50unattended-upgrades configuration file provides examples of blacklisted packages.

The README tells about Package-Whitelist setting. The description says "Only packages that match the regular expressions in this list will be marked for upgrade.". It does not offer examples to clarify in which cases it would be desirable to set the whitelist. From my experiments, it looks like adding packages to whitelist means only those packages get automatically upgraded, nothing else.


Now you know what unattended-upgrades can do and how to make it do what you want.

There are cases where unattended-upgrades does not do the upgrade because the command apt upgrade keeps a package back. This happens when upgrading would remove a package or install a previously uninstalled package. To make the upgrade happen, do it yourself with command apt full-upgrade which can remove packages or install new previously uninstalled packages. If unattended upgrades is configured to send e-mail, the e-mail contains the line

Packages with upgradable origin but kept back:

A final example of 52unattended-upgrades-local from one of my hosts:

Unattended-Upgrade::Origins-Pattern {
// Taleman added 2022-09-05
        "o=GoAccess Repository, n=buster, l=Official GoAccess Repository";
        "o=Debian Backports,a=${distro_codename}-backports,l=Debian Backports";

Unattended-Upgrade::Mail "[email protected]";
Unattended-Upgrade::OnlyOnACPower "false";
Share this page:

3 Comment(s)