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

9,671

Solution 1

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

Solution 2

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.

Solution 3

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.

Solution 4

The unattended upgrade script in /etc/cron.daily/apt uses upgrade intervals expressed in days, so setting anything more frequent than one day is not possible.

You can use standard cron - put this in /etc/cron.d:

SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
0 0-23/4 * * * root   apt-get -q update && apt-get dist-upgrade -yq -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold"

Adjust the command to your needs.

Share:
9,671

Related videos on Youtube

nachtigall
Author by

nachtigall

Updated on September 18, 2022

Comments

  • nachtigall
    nachtigall over 1 year

    By default unattended-upgrades runs with cron.daily, that is at most on a daily basis. This can be a lot of time for attackers. I'd like to run it every 4 hours, how can I do this?

  • nachtigall
    nachtigall over 9 years
    I wonder why there is a dedicated unattended-upgrades package, if unattended upgrades can be done that simple?
  • nachtigall
    nachtigall over 9 years
    I think unattend-upgrades has an option to not automatically upgrade things that require a reboot, right? Like kernel, libc, etc. I think simply using this apt-get and cron might like to potential downtimes.
  • Krzysztof Kosiński
    Krzysztof Kosiński over 9 years
    unattended-upgrades just ships a configuration file for the script in /etc/cron.daily/apt. It has an option to reboot if required and has some custom logic that is only needed for intermittently active systems. Running the command from my post will not cause a reboot even if there is an update that requires it.
  • nachtigall
    nachtigall almost 8 years
    Are you using this in production? I don't have the time to set it up myself currently
  • nachtigall
    nachtigall almost 8 years
    Are you using this in production? I don't have the time to set it up myself currently, but would upvote and accept if you can confirm
  • minimalis
    minimalis almost 8 years
    Yes but only since 2 days ago, when I figured out the details. So this comes with the usual health warning that you should carry out your own testing :)
  • minimalis
    minimalis almost 8 years
    And yes there was a bug... the path needed to be set (at least on Ubuntu). I've also added a random sleep, to be a bit kinder to the upstream apt servers.
  • lorimer
    lorimer about 7 years
    I'm currently running debian jessie with systemd as init and unattended-upgrades installed, and unattended-upgrades is still triggered by cron (there is no systemd timer for it, and moving apt from /etc/cron.daily to /etc/cron.hourly works).
  • Rizwan Khan
    Rizwan Khan almost 6 years
    This command will update everything, not only security updates.
  • OrangeDog
    OrangeDog almost 6 years
    Is the unit apt-daily-upgrade?
  • hleroy
    hleroy about 3 years
    Great answer. Thank you for all the details regarding systemd timers configuration.