← All posts
OperationsNov 4, 2026· 7 min read

Ubuntu unattended-upgrades: security patches without surprise reboots

Set up Ubuntu unattended-upgrades to apply security patches automatically, control reboots, and know when something goes wrong.

By · Updated

If you run Ubuntu servers without a dedicated ops team, you face a quiet dilemma: apply security patches manually and fall weeks behind, or turn on automatic updates and worry that a reboot will drop your app at 2 am. Ubuntu's unattended-upgrades package solves the first problem without forcing the second, but only if you configure it properly. This guide shows you exactly what to install, what to change, and what to watch so automatic patching stays under control.

What unattended-upgrades actually does

unattended-upgrades is an apt wrapper that runs on a timer, checks a defined list of package origins, downloads and installs matching updates, and optionally cleans up old kernels. Out of the box on Ubuntu 20.04 and later it is installed but not always fully enabled. It applies only packages from the `Ubuntu:focal-security` origin (or your release equivalent), not every pending update. That means your application packages stay pinned unless you explicitly add more origins.

Reboots are never automatic unless you tell it so. The package can write a file to signal that a reboot is needed, but it will not reboot the machine until you configure a reboot time. That is the setting most people miss, and it is why their servers accumulate pending reboots for months.

Install and enable it

First check whether the package is already installed and whether the apt-daily timers are running.

# Check if already installed
dpkg -l unattended-upgrades

# Check the systemd timers that drive it
systemctl status apt-daily.timer apt-daily-upgrade.timer

# Install if missing
sudo apt install unattended-upgrades apt-listchanges -y

# Enable and start
sudo dpkg-reconfigure -plow unattended-upgrades
# Answer 'Yes' when prompted

# Confirm the service file was written
cat /etc/apt/apt.conf.d/20auto-upgrades
# Expected output:
# APT::Periodic::Update-Package-Lists "1";
# APT::Periodic::Unattended-Upgrade "1";

# Run a dry-run to see what would be upgraded today
sudo unattended-upgrade --dry-run --debug 2>&1 | grep -E 'Packages|upgradeable|error'

The `--dry-run` pass is worth running every time you change configuration. It prints which packages match, which are held back, and whether any errors occur, without touching anything.

The settings that actually matter

The main configuration file is `/etc/apt/apt.conf.d/50unattended-upgrades`. Open it and look for three sections.

**Allowed origins.** The default block includes `${distro_id}:${distro_codename}-security`. Leave that in. If you also want bug-fix updates from `-updates`, uncomment that line too. Do not uncomment `-proposed` or `-backports` on production machines.

**Packages to never touch.** The `Unattended-Upgrade::Package-Blacklist` list accepts exact names and regular expressions. Add anything you deploy yourself and anything with a known migration risk, for example: `"mysql-server", "nginx", "php.*"`. Held packages (those pinned with apt-mark hold) are automatically skipped regardless.

**Reboot behaviour.** Three settings control this:

  • `Unattended-Upgrade::Automatic-Reboot "false";` -- set to `"true"` only if a scheduled reboot is acceptable.
  • `Unattended-Upgrade::Automatic-Reboot-WithUsers "false";` -- when true, reboots even if users are logged in. Leave false.
  • `Unattended-Upgrade::Automatic-Reboot-Time "03:00";` -- the time window used if automatic reboots are on. Pick your quietest hour.

If you keep `Automatic-Reboot false`, you are responsible for rebooting after a kernel or libc update. The file `/var/run/reboot-required` appears when a reboot is pending. Checking for that file in a nightly alert is enough to stay on top of it.

Rule of thumb: let unattended-upgrades handle security origins automatically; reboot on your schedule during a maintenance window rather than letting the machine decide.

Reading the logs to confirm it is working

unattended-upgrades writes to `/var/log/unattended-upgrades/unattended-upgrades.log`. A successful run looks like this:

# Tail the last 30 lines after the daily timer fires (~6 am by default)
sudo tail -30 /var/log/unattended-upgrades/unattended-upgrades.log

# Lines to look for:
# INFO Starting unattended upgrades script
# INFO Packages that will be upgraded: libssl3 openssl
# INFO All upgrades installed

# If something failed:
sudo grep -i 'error\|warning\|failed' /var/log/unattended-upgrades/unattended-upgrades.log | tail -20

# Check whether a reboot is currently pending
test -f /var/run/reboot-required && echo 'REBOOT NEEDED' || echo 'No reboot pending'

# See which packages triggered it
cat /var/run/reboot-required.pkgs 2>/dev/null

If the log file does not exist or has not been written in the last 24 hours, the timer is probably not running. Check `systemctl list-timers apt-daily-upgrade.timer` and look at the NEXT and LAST columns.

What to alert on

Automatic patching creates a new class of thing to watch: silent failures. The package runs unattended, so you will not notice if it stops working until a CVE lands on an unpatched machine. Set these checks:

  • **Reboot pending for more than 7 days.** `/var/run/reboot-required` exists and its modification time is older than 7 days. Anything beyond that is a kernel update sitting unapplied.
  • **Log file not updated in 48 hours.** If `/var/log/unattended-upgrades/unattended-upgrades.log` has not changed in 48 hours, the daily timer has stalled.
  • **'error' or 'failed' in the log.** A grep on the log file at the end of each day catches broken apt locks, missing keys, or held dependencies that blocked the run.
  • **Available security updates older than 24 hours.** Run `apt-get -s upgrade 2>/dev/null | grep -c '^Inst'` to count pending upgrades. If this is non-zero and the package is supposed to be handling them, something is held back that you need to review.
  • **Disk space below 20% on `/`.** apt downloads and unpacks packages before removing the old version. A full disk is the most common cause of a mid-upgrade failure.

These thresholds are conservative. A reboot pending for one day is fine; pending for two weeks is a risk. An upgrade log that stalled for 24 hours might just be a quiet patch day; 48 hours with no entry usually means a broken timer.

How Opservo watches this for you

Checking five log files and modification times across a fleet of servers by hand does not scale. Opservo, the AI ops engineer for teams without an SRE, surfaces pending reboots, storage pressure and service failures as plain-English alerts with one-click fixes. Its Health Standard scores each server across Storage, Maintenance and Reliability and names the exact rule and current value behind every lost point, so you know whether a reboot-required file is new or has been sitting there for two weeks. The agent installs in about 30 seconds with one command and opens no inbound ports, so adding it to a production machine carries no exposure.

Invite the reader to install the Opservo agent (one command, free for 2 servers, no card) to get automatic alerts for pending reboots, stalled upgrade timers, and low disk space across their fleet. — one command installs a read-only agent and your first findings arrive in five minutes: start free. Related: guides how to check disk space on linux.