How to run unattended-upgrades not daily but every few hours

The frequency of unattended-upgrades is determined in two steps:

  1. The system scheduler (e.g. systemd timers or cron/anacron), and
  2. APT::Periodic intervals.

A lower frequency in one of these will obstruct the higher frequency in the other, so be sure that settings are correct for both steps.

The second step (APT::Periodic intervals) requires apt version 1.5 or higher for frequencies higher than once per day. Debian 10 (buster) ships with apt 1.8.2, so that would be ok.

If you use an apt version below 1.5, for example Debian 9 (stretch), then the second step is going to be problematic. Scroll to the bottom of this answer to see if you would be willing to apply the ugly workaround suggested there, before you even start with step 1.

Also note that, just as with regular usage of apt, there is a distinction between update and upgrade/install. The first is about updating the list of available packages, while the second is about the upgrading of the packages. Again, make sure that you change settings for both.

1. The system scheduler

In both Debian 9 (stretch) and Debian 10 (buster), the process is started by the following two systemd timers:

  • apt-daily.timer, which via apt-daily.service calls /usr/lib/apt/apt.systemd.daily update to update the package lists (apt-get update), and
  • apt-daily-upgrade.timer, which via apt-daily-upgrade.service calls /usr/lib/apt/apt.systemd.daily install to install the upgrades (unattended-upgrade).

(The anacron job /etc/cron.daily/apt-compat still exists, but exits if it detects systemd. Without systemd, it will run /usr/lib/apt/apt.systemd.daily without sub-command, which means both update and install. See other answers or anacron documentation on changing the schedule if you don't use systemd.)

The systemd timers can be set to trigger at a higher frequency, in your example every four hours, by overriding the default schedule. First, for updating the package list:

$ sudo systemctl edit apt-daily.timer

This creates /etc/systemd/system/apt-daily.timer.d/override.conf. Fill it as follows:

[Timer]
OnCalendar=
OnCalendar=*-*-* 0,4,8,12,16,20:00
RandomizedDelaySec=15m

Then, for the actual upgrades 20 minutes later:

$ sudo systemctl edit apt-daily-upgrade.timer

[Timer]
OnCalendar=
OnCalendar=*-*-* 0,4,8,12,16,20:20
RandomizedDelaySec=1m

To check your work:

$ systemctl cat apt-daily{,-upgrade}.timer
$ systemctl --all list-timers apt-daily{,-upgrade}.timer

(Taken partly from Debian Wiki: UnattendedUpgrades.)

2. APT::Periodic intervals

The system scheduler calls the script /usr/lib/apt/apt.systemd.daily, which uses a filestamp-mechanism to determine when the requested action last ran. It compares this with the interval set for that action in APT::Periodic. You should normally find those settings in /etc/apt/apt.conf.d/20auto-upgrades:

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

I always thought the "1" value here simply meant True or On, but actually, it is the minimal interval between runs, expressed in days. If the script determines that less time has passed since the last time the requested action was performed, it will simply not perform the action, regardless of the fact that the system scheduler called for it.

Now, in apt 1.5~beta2, Paul Wise made it possible to define the interval in seconds, minutes and hours by adding suffixes s, m or h, so you could change /etc/apt/apt.conf.d/20auto-upgrades to:

APT::Periodic::Update-Package-Lists "3h";
APT::Periodic::Unattended-Upgrade "3h";

(Less than "4h", to account for the random delay in the system scheduler.)

Even better, he made it possible to set the interval to "always" to ensure that the action just gets performed when requested, no matter how much time has passed since the last run:

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

I prefer this, because you set this once and from then on you only need to interact with the system scheduler (systemd timers) if you want to change the frequency.

With apt <1.5

Debian 9 (stretch) ships with apt 1.4.9, so setting APT::Periodic intervals to "always" or "3h" as described in step 2 won't work. An interval of "0.1" days also does not work, by the way.

If you don't mind an ugly workaround, edit the script /usr/lib/apt/apt.systemd.daily to sideline the timestamp-mechanism by inserting return 0 in the check_stamp() function (use at your own risk!):

--- a/lib/apt/apt.systemd.daily
+++ b/lib/apt/apt.systemd.daily
@@ -82,10 +82,12 @@ check_stamp()
        debug_echo "check_stamp: interval=0"
        # treat as no time has passed
         return 1
     fi

+    return 0
+
     if [ ! -f $stamp ]; then
        debug_echo "check_stamp: missing time stamp file: $stamp."
        # treat as enough time has passed
         return 0
     fi

This way, the script will always think that the interval has passed, so it will run whatever actions are requested. This workaround should get overwritten when you upgrade apt, and then you can switch to using "always" as described above in step 2.

If you don't want to mess with the script, consider a custom cron job as described in some of the other answers. In that case, you also don't need to worry about step 1 of this answer.


Old question, but saying this for anyone who might have the same issue i had:

On Ubuntu 16.04 (and probably other systemd systems) the unattended-upgrades is not triggered by cron anymore. Instead it uses systemd Timers.

In order to modify the run time(s) and the randomized delay, you need to modify/override the timers. More information can be found here: https://github.com/systemd/systemd/issues/3233


As Krzysztof points out, you'll need a separate cron entry for this.

It's probably best to call unattended-upgrade directly (it's a python script), to ensure package blacklists/whitelists, reboots and other details are handled appropriately.

For example:

echo "0 0-23/4 * * * root sleep $(( $RANDOM % 14400 ));PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin unattended-upgrade" > /etc/cron.d/unattended-upgrade

This will override the time period configured in /etc/apt/apt.conf.d/. This works because these checks aren't done within the unattended-upgrade script, they are done one level above in the calling script /usr/lib/apt/apt.systemd.daily.

The output will be logged to /var/log/unattended-upgrades/ as usual.