Patch automation should reduce risk, not create mystery outages.
If you run Debian or Ubuntu systems, unattended-upgrades is the native way to apply security updates automatically. The problem is that many setups stop at “it’s enabled” and skip the operational bits: what exactly can update, when it runs, what happens on reboot-required updates, and how you verify outcomes.
This guide gives you a practical baseline you can defend in production.
Why this angle (and what this is not)
This is not another cron-vs-systemd explainer and not a firewall hardening guide.
This is about reliable patch governance for apt-based systems:
- explicit update policy (
Allowed-Origins/Origins-Pattern) - predictable scheduling behavior
- controlled reboot windows
- audit-friendly verification
1) Install and enable unattended-upgrades
Debian / Ubuntu
sudo apt update
sudo apt install -y unattended-upgrades apt-listchanges
sudo dpkg-reconfigure -plow unattended-upgrades
Why apt-listchanges? It gives you visibility into important package/news changes instead of blind upgrades.
2) Understand the two key config files
-
/etc/apt/apt.conf.d/20auto-upgrades→ whether/when periodic apt actions run -
/etc/apt/apt.conf.d/50unattended-upgrades→ what and how unattended upgrades are applied
Set daily checks/installs in 20auto-upgrades:
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
"1" means daily. "0" disables.
3) Define a safe update policy (security-first)
Start conservative: security updates first, then expand only if you can absorb change.
Tip: create a local override file so package updates don’t clobber your policy.
sudo cp /etc/apt/apt.conf.d/50unattended-upgrades \
/etc/apt/apt.conf.d/52unattended-upgrades-local
sudo nano /etc/apt/apt.conf.d/52unattended-upgrades-local
Debian-style example
Unattended-Upgrade::Origins-Pattern {
"origin=Debian,codename=${distro_codename},label=Debian-Security";
"origin=Debian,codename=${distro_codename}-security,label=Debian-Security";
};
Ubuntu-style baseline
Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}-security";
// Optional after validation period:
// "${distro_id}:${distro_codename}-updates";
};
Keep -updates commented until you’ve observed behavior on your workload.
4) Configure reboot behavior explicitly
Kernel/libc-related updates can require restarts or full reboot. Make this a policy decision, not an accident.
In your unattended config:
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "03:30";
If you cannot tolerate automatic reboot, set:
Unattended-Upgrade::Automatic-Reboot "false";
…and alert on /var/run/reboot-required so humans handle it during maintenance windows.
5) Tune timer behavior for laptops/ephemeral VMs
APT jobs are triggered by systemd timers (apt-daily.timer, apt-daily-upgrade.timer).
On hosts that are often powered off, missed runs may execute right after boot (default persistent timer behavior), which can surprise users and block package operations at login/startup.
If that hurts your workflow, override Persistent=false:
sudo systemctl edit apt-daily.timer
[Timer]
Persistent=false
Do the same for upgrade timer:
sudo systemctl edit apt-daily-upgrade.timer
[Timer]
Persistent=false
Reload + confirm:
sudo systemctl daemon-reload
systemctl cat apt-daily.timer
systemctl cat apt-daily-upgrade.timer
6) Dry-run and verification workflow (non-negotiable)
Before trusting automation, test it.
Dry-run
sudo unattended-upgrade --dry-run --debug
Logs you should check
sudo tail -n 200 /var/log/unattended-upgrades/unattended-upgrades.log
sudo tail -n 200 /var/log/unattended-upgrades/unattended-upgrades-dpkg.log
sudo grep -E "upgrade|unattended" /var/log/apt/history.log | tail -n 50
Timer/service status
systemctl status apt-daily.timer apt-daily-upgrade.timer --no-pager
systemctl list-timers --all | grep -E 'apt-daily|apt-daily-upgrade'
If something behaves unexpectedly, pause quickly:
sudo sed -i 's/"1"/"0"/g' /etc/apt/apt.conf.d/20auto-upgrades
Then investigate logs and policy.
7) Practical rollout pattern
- Week 1: security-only policy on non-critical nodes.
- Week 2: enable on production nodes with reboot window set.
-
Week 3+: optionally include
-updatesfor selected groups. - Keep a package blacklist for sensitive components requiring manual change control.
This keeps velocity high without sacrificing control.
Final take
unattended-upgrades is good by default, but great only when paired with explicit policy, predictable timing, and auditable verification.
Treat patching like an operational system, not a checkbox.
References
- Ubuntu Server documentation — Automatic updates: https://documentation.ubuntu.com/server/how-to/software/automatic-updates/
- Debian Wiki — PeriodicUpdates / UnattendedUpgrades: https://wiki.debian.org/UnattendedUpgrades
- Debian manpages —
unattended-upgrade(8): https://manpages.debian.org/unstable/unattended-upgrades/unattended-upgrade.8.en.html - Debian manpages —
apt.conf(5): https://manpages.debian.org/unstable/apt/apt.conf.5.en.html
Top comments (0)