BeginnerServer & Linux BasicsUbuntuSecurityAPTSystem AdministrationAutomation
How To Set Up Automatic Security Updates with unattended-upgrades on Ubuntu 22.04
Tricknowtech Team 9 min read
Goal
By the end of this tutorial, your Ubuntu 22.04 server will automatically install security-origin package updates on a daily schedule via systemd timers, reboot itself at a fixed low-traffic time only when a kernel update actually requires it, and you'll know how to verify the whole pipeline with a dry run and the resulting logs.
Prerequisites
An Ubuntu 22.04 LTS server with a non-root user configured with sudo privileges, reachable over SSH
Basic familiarity with the command line and a terminal text editor such as nano
Root or sudo access to edit files under /etc/apt/apt.conf.d/
Let an AI agent do this for you
Copy a ready-made prompt for an AI coding assistant with terminal access to your server (Claude Code, Cursor, or similar) — it can carry out the steps below for you. Review what it plans to run before it executes anything.
Leaving a server's security patches to manual, occasional `apt upgrade` runs is one of the most common ways a box quietly falls behind on fixes for known vulnerabilities. Ubuntu ships a tool built specifically to close that gap: `unattended-upgrades`, a background service that checks for and installs security updates on a schedule without you having to log in and run anything.
This tutorial walks through installing `unattended-upgrades` on an Ubuntu 22.04 server, understanding exactly which package sources it is allowed to pull from, turning on the periodic APT timers that drive it, and — for updates that touch the running kernel — configuring a safe, predictable automatic reboot window. You'll finish by validating the whole setup with a dry run before trusting it to run unattended.
Step 1 — Installing unattended-upgrades
Start by refreshing the local package index and installing the `unattended-upgrades` package itself, along with `apt-listchanges`, which lets the tool summarize what changed in each package it installs. On many current Ubuntu 22.04 images `unattended-upgrades` is already installed by default, but running the install command is harmless and ensures you're on the version from your configured repositories.
Installing the package alone does not turn anything on — it just puts the binary and its default configuration files in place under `/etc/apt/apt.conf.d/`. The next two steps cover what those config files control and how to actually enable the periodic runs.
The file `/etc/apt/apt.conf.d/50unattended-upgrades` is where you control which package origins are eligible for automatic installation and how the tool behaves once it decides to act. Open it in a text editor to look at the defaults before changing anything.
Near the top you'll find the `Allowed-Origins` block, which is the single most important setting in this file — it's an allowlist of exactly which repositories `unattended-upgrades` is permitted to pull packages from. On a stock Ubuntu 22.04 install it looks roughly like this, with the general updates, proposed, and backports lines commented out by default so only security-relevant origins are active:
With this default, only security-origin packages are eligible — general point-release updates, backports, and proposed packages stay untouched unless you uncomment those lines yourself. Leaving general `-updates` commented out is the conservative, recommended posture for most servers: you get critical security patches automatically, while feature and bugfix updates still wait for you to review and apply them manually.
“Uncommenting the `-updates` line pulls in all standard package updates, not just security fixes, which increases the chance an automatic run changes application behavior unexpectedly. Only enable it if you specifically want that broader coverage and have monitoring in place to catch regressions.”
Further down the same file are a handful of other directives worth knowing about. `Unattended-Upgrade::Package-Blacklist` lets you list package names to exclude from automatic updates entirely (useful for something like a pinned database server version); `Unattended-Upgrade::Mail` can be set to an email address to receive a report after each run; and `Unattended-Upgrade::Remove-Unused-Kernel-Packages` controls whether old kernel packages get cleaned up automatically once they're no longer needed.
Step 3 — Enabling the periodic APT schedule
Having `unattended-upgrades` installed and configured doesn't run it on any schedule by itself — that's controlled by a separate file, `/etc/apt/apt.conf.d/20auto-upgrades`, which enables APT's periodic timers. Create or edit it directly:
bash
sudo nano /etc/apt/apt.conf.d/20auto-upgrades
Set the following two directives. `Update-Package-Lists` runs the equivalent of `apt update` once a day; `Unattended-Upgrade` triggers the actual upgrade pass using the origins allowed in `50unattended-upgrades`:
Instead of hand-editing this file, you can get the same result — plus an interactive prompt walking through the key options — by running `sudo dpkg-reconfigure --priority=low unattended-upgrades` and answering "Yes" when asked whether to enable automatic updates. Either approach writes the same two lines, so use whichever you're more comfortable with.
These settings are consumed by two systemd timers that ship with APT: `apt-daily.timer` (package list refresh) and `apt-daily-upgrade.timer` (the actual unattended-upgrade run). Confirm both are enabled and active:
bash
systemctl status apt-daily.timer apt-daily-upgrade.timer
Step 4 — Configuring automatic reboot for kernel updates
Security patches to the kernel or to core system libraries often require a reboot to fully take effect; until that reboot happens, the fix is downloaded and installed but not actually active. Back in `/etc/apt/apt.conf.d/50unattended-upgrades`, two directives control whether and when that reboot happens automatically.
Find `Unattended-Upgrade::Automatic-Reboot` and set it to `"true"`, then set `Automatic-Reboot-Time` to a fixed clock time during a low-traffic window for your workload — for example, 02:00 local server time:
A reboot is only ever scheduled at that time if `/var/run/reboot-required` actually exists — meaning an installed update genuinely needs one — so this setting doesn't force nightly reboots that aren't needed. `Automatic-Reboot-WithUsers` set to `"true"` allows the reboot to proceed even if other users are logged in via SSH at the time; set it to `"false"` instead if you'd rather it skip the reboot (and try again the next day) whenever someone else is connected.
“Verify the server's timezone with `timedatectl` before relying on Automatic-Reboot-Time — the value is interpreted in the system's local time, so a mismatched timezone can schedule the reboot during business hours instead of off-peak.”
If you'd rather review and reboot manually whenever a kernel update lands, leave `Automatic-Reboot` set to `"false"` (the default) and instead check for `/var/run/reboot-required` periodically, or watch for it in the automatic-updates log covered in the next step.
Step 5 — Testing the configuration with --dry-run
Before trusting any of this to run unattended for real, exercise it manually with the `--dry-run` flag, which reports exactly what it would download and install without making any changes to the system. Add `--debug` as well for verbose output showing which origins it evaluated and why each package was or wasn't selected.
bash
sudo unattended-upgrade --dry-run --debug
Read through the output for a line confirming which allowed origins were checked, and a list of any packages that would be upgraded. If the list is empty, that's expected on a system that's already fully patched — try running `sudo apt update` first, or wait until a real security advisory lands, to see it act on actual pending packages.
Once you're satisfied with the dry-run output, you can trigger a real run the same way (omit `--dry-run`) to confirm it installs updates correctly, or simply let the systemd timers from Step 3 fire on their normal schedule.
Step 6 — Checking logs after a run
Every unattended-upgrade run — scheduled or manual — writes a detailed record to `/var/log/unattended-upgrades/`. The two files there cover different levels of detail: a summary log and a raw dpkg transaction log.
`unattended-upgrades.log` is the one to check first — it records which packages were considered, which were installed, and whether a reboot was scheduled as a result. If you configured `Unattended-Upgrade::Mail` in Step 2, the same summary will also land in that mailbox after each run, which is worth doing on any server you don't log into daily.
Conclusion
You've installed `unattended-upgrades`, reviewed which package origins it's allowed to pull security patches from in `50unattended-upgrades`, enabled the periodic systemd timers that drive it via `20auto-upgrades`, and configured a fixed, low-traffic reboot window for updates that require one. A `--dry-run` pass confirmed the configuration works, and you know where to look afterward — `/var/log/unattended-upgrades/` — to confirm each scheduled run did what you expect.