Unattended Upgrades on Ubuntu: Patches, Reboots, and Docker

devopsdockersecurityself-hosting
Unattended Upgrades on Ubuntu: Patches, Reboots, and Docker

Unattended upgrades installs Ubuntu security updates daily, but by default it never reboots, so a patched kernel doesn't take effect. It also skips packages from third-party repositories, including Docker's. Check both gaps on your server, then choose a reboot window and decide how you'll patch Docker.

I tested this on Ubuntu 24.04 and 26.04 in systemd-booted containers under WSL2, with Docker 29.9. A reboot in that setup is a container restart with no kernel boot, so a real VPS will take longer to come back than the times below.

What Does It Upgrade by Default?

Only Ubuntu's own security updates, and the ESM pockets if you have Ubuntu Pro. Check that it's turned on:

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

If either value is 0 or missing, run sudo dpkg-reconfigure -f noninteractive unattended-upgrades.

The origins live in /etc/apt/apt.conf.d/50unattended-upgrades. Here is the default on 24.04, which is the same on 26.04:

Unattended-Upgrade::Allowed-Origins {
	"${distro_id}:${distro_codename}";
	"${distro_id}:${distro_codename}-security";
	"${distro_id}ESMApps:${distro_codename}-apps-security";
	"${distro_id}ESM:${distro_codename}-infra-security";
};

The -updates pocket isn't listed, so ordinary bug-fix updates wait for you.

Two timers drive it. apt-daily-upgrade.timer installs updates at 06:00 server time plus up to 60 minutes of random delay, and apt-daily.timer refreshes package lists at 06:00 and 18:00 plus up to 12 hours. So don't expect a fix to land the minute Ubuntu publishes it.

How Do You See What It Would Do?

A dry run changes nothing and explains every decision:

sudo unattended-upgrade --dry-run --debug 2>&1 \
  | grep -E '^Allowed origins|^Packages that will be upgraded|docker-ce'
Allowed origins are: o=Ubuntu,a=noble, o=Ubuntu,a=noble-security, o=UbuntuESMApps,a=noble-apps-security, o=UbuntuESM,a=noble-infra-security
Checking: docker-ce ([<Origin component:'stable' archive:'noble' origin:'Docker' label:'Docker CE' site:'download.docker.com' isTrusted:True>])
adjusting candidate version: docker-ce=5:29.9.2-1~ubuntu.24.04~noble
Checking: docker-ce-cli ([<Origin component:'stable' archive:'noble' origin:'Docker' label:'Docker CE' site:'download.docker.com' isTrusted:True>])
adjusting candidate version: docker-ce-cli=5:29.9.2-1~ubuntu.24.04~noble
Packages that will be upgraded: libpcre2-8-0

Real runs log to /var/log/unattended-upgrades/unattended-upgrades.log, and the package manager's output goes to unattended-upgrades-dpkg.log beside it.

Why Doesn't It Patch Docker?

Look at that output again. Docker 29.9.3 was available, but its origin isn't allowed, so the tool held docker-ce at 29.9.2. After a real run, it was still pending:

apt list --upgradable
docker-ce-cli/noble 5:29.9.3-1~ubuntu.24.04~noble amd64 [upgradable from: 5:29.9.2-1~ubuntu.24.04~noble]
docker-ce/noble 5:29.9.3-1~ubuntu.24.04~noble amd64 [upgradable from: 5:29.9.2-1~ubuntu.24.04~noble]

Docker 29.9.3, released November 3, 2026, lists fixes for several CVEs, and so do many of the releases before it. Ubuntu's security updates won't bring you any of them.

Dokploy servers have a related wrinkle. Its installer asks for Docker 28.5.0 and falls back to the latest version only if that one isn't available, so a default install starts well behind. Check Dokploy's release notes before you upgrade Docker there. On an older install, also check your Traefik version. In my own earlier testing, traefik:v3.5 couldn't talk to Docker 29 at all, and every route returned 404, while the current installer pins v3.6.25.

Should You Let It Upgrade Docker?

You can, with one line in a new file such as /etc/apt/apt.conf.d/51docker-origin:

Unattended-Upgrade::Allowed-Origins:: "Docker:${distro_codename}";

The dry run then reports Packages that will be upgraded: docker-ce docker-ce-cli. The cost is that the upgrade restarts the Docker daemon, so here's what happened to a running container, polling it from outside about every 100 ms:

SetupContainer after the upgradePort unreachable for
restart: unless-stoppedRestarted, new start time2.1 seconds in each of 3 runs
No restart policyStayed exitedUntil started by hand
unless-stopped with live-restoreKept running, same start time0.8 to 2.2 seconds across 3 runs

Earlier runs of the restart policy case took up to 4.6 seconds, so treat these as a rough size rather than a benchmark.

live-restore kept the container process running through the upgrade, but the published port still dropped for a second or two. So it shortens the gap without closing it. It's also unavailable on Dokploy, because it can't be combined with Swarm:

Error response from daemon: --live-restore daemon configuration is incompatible with swarm mode

I'd leave Docker out of unattended upgrades on a server with users, and patch it in a window you choose. Run this after reading the release notes, then check your containers:

sudo apt-get update
sudo apt-get install --only-upgrade docker-ce docker-ce-cli containerd.io
docker ps -a --format '{{.Names}}\t{{.Status}}'

If you do automate it, give every container a restart policy first, and accept a short outage at a random time between 06:00 and 07:00.

What Happens After a Kernel Update?

The kernel package installs, the old kernel keeps running, and a flag file appears. Installing a kernel created both of these:

cat /var/run/reboot-required /var/run/reboot-required.pkgs
*** System restart required ***
linux-image-6.8.0-147-generic
linux-base

The default config has Automatic-Reboot commented out, so nothing acts on that flag. Your server can report a patched kernel in dpkg -l for weeks while uname -r shows the vulnerable one still running. How to check a CVE on Ubuntu covers comparing the two.

Library updates are better behaved, because needrestart handles them without a reboot. When a run upgraded OpenSSL, the log showed this, and the SSH daemon came back with a new process ID:

Restarting services...
 systemctl restart ssh.service systemd-journald.service unattended-upgrades.service
Service restarts being deferred:
 systemctl restart systemd-logind.service

How Do You Turn On Automatic Reboots?

Add two lines to a new file such as /etc/apt/apt.conf.d/52reboot:

Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "04:00";

The next run schedules the reboot instead of doing it:

WARNING Found /var/run/reboot-required, rebooting
WARNING Shutdown msg: b"Reboot scheduled for Fri 2026-11-06 04:00:00 UTC, use 'shutdown -c' to cancel."

Four details from testing and the tool's source are worth knowing:

  • Always set a time. Without Automatic-Reboot-Time, the code defaults to now, so the server reboots immediately after the morning run. The example in the config file shows 02:00, but that line is commented out.
  • The time is the next occurrence. Updates install around 06:00, so a 04:00 reboot happens 21 to 22 hours later. A critical kernel fix stays inactive for that long.
  • It only checks the flag. A run with No packages found that can be upgraded still rebooted, because the flag was present from an earlier install.
  • Logged-in users don't stop it. Automatic-Reboot-WithUsers defaults to true, so your open SSH session won't delay a reboot.

To cancel a scheduled reboot, run sudo shutdown -c.

What Comes Back After a Reboot?

Containers with a restart policy come back, and the others don't. The reboot took the port down for 10.1 seconds in one run and 3.1 in another, and docker ps -a then showed this:

norestart Exited (0) 17 seconds ago
web Up 8 seconds

web has restart: unless-stopped, and norestart has no policy.

The firewall state split the same way. UFW came back on its own, and so did rules in /etc/ufw/after.rules, but a DOCKER-USER rule I'd added by hand was gone, which matters if you rely on that fix for Docker and UFW.

So check these before you turn on reboots:

docker ps -a --format '{{.Names}}' | xargs docker inspect \
  --format '{{.Name}} {{.HostConfig.RestartPolicy.Name}}'

Anything that prints no won't return, and neither will a firewall rule that only exists in memory. Set up an alert from outside the server too, so that you hear about a reboot that fails.

Should You Enable Automatic Reboots?

On a single server with restart policies and external monitoring, I'd turn them on with a low-traffic time. A short planned outage is a better trade than a known kernel flaw running for weeks.

If you can't accept that, schedule a weekly reboot by hand and check the flag. Ubuntu Livepatch narrows the gap further by patching critical and high severity kernel flaws in place, and it's free on up to 5 machines for personal use. I didn't test it here, and Canonical says it isn't a replacement for rebooting.

Summary

Unattended upgrades does one job well, which is installing Ubuntu's security updates and restarting the services that depend on them. It doesn't reboot unless you ask, and it doesn't touch Docker's repository, so those are the two decisions to make yourself.

Set a reboot time, give every container a restart policy, and patch Docker on a schedule you choose. Then run --dry-run --debug once, so that you know what your server is actually doing instead of assuming it.

This fits with the rest of my Ubuntu server hardening checklist, and my self-hosting course builds the maintenance routine around it.

Thanks for reading.

And stay awesome!


Frequently Asked Questions

Does unattended-upgrades reboot Ubuntu automatically?

Not by default. The Automatic-Reboot setting ships commented out, so a patched kernel stays inactive until you reboot. Set Unattended-Upgrade::Automatic-Reboot to true and choose a time with Automatic-Reboot-Time. If you enable it without a time, the server reboots immediately after the run.

Does unattended-upgrades update Docker?

Not if you installed Docker from Docker's own repository. The default allowed origins only cover Ubuntu and Ubuntu ESM, so docker-ce stays on its current version. You can add Docker's origin, but a Docker upgrade restarts the daemon and your containers.

When does unattended-upgrades run?

The apt-daily-upgrade timer fires at 06:00 server time with up to 60 minutes of random delay. A separate apt-daily timer refreshes package lists at 06:00 and 18:00 with up to 12 hours of random delay.

How do I know if my Ubuntu server needs a reboot?

Check for the file /var/run/reboot-required. The file /var/run/reboot-required.pkgs lists the packages that asked for the reboot. Installing a kernel created both in testing.

Will my Docker containers come back after an automatic reboot?

Only if they have a restart policy. In testing, a container with restart unless-stopped came back on its own, while a container with no restart policy stayed exited and its port stopped answering.

How do I test unattended-upgrades without changing anything?

Run sudo unattended-upgrade --dry-run --debug. It prints the allowed origins, the packages it would upgrade, and why it skipped others. The logs for real runs are in /var/log/unattended-upgrades.

Browse all Self-Hosting guides →
Loading comments...

Whenever you're ready, there are 5 ways I can help you:

  1. Pragmatic Self-Hosting: Learn to deploy and run your apps on a VPS with Dokploy and Tailscale. Keep administration private, automate releases, and practice restoring backups, with source code and a runbook you can reuse.
  2. Pragmatic Clean Architecture: Join 5,000+ students in this comprehensive course that will teach you the system I use to ship production-ready applications using Clean Architecture. Learn how to apply the best practices of modern software architecture.
  3. Modular Monolith Architecture: Join 2,800+ engineers in this in-depth course that will transform the way you build modern systems. You will learn the best practices for applying the Modular Monolith architecture in a real-world scenario.
  4. Pragmatic REST APIs: Join 1,900+ students in this course that will teach you how to build production-ready REST APIs using the latest ASP.NET Core features and best practices. It includes a fully functional UI application that we'll integrate with the REST API.
  5. Patreon Community: Join a community of 5,000+ engineers and software architects. You will also unlock access to the source code I use in my YouTube videos, early access to future videos, and exclusive discounts for my courses.

The .NET Weekly

One practical .NET tip, every Saturday.

Join 66,000+ engineers who read it. Free, and you can unsubscribe any time.