Back to tutorials
Tutorial

Set Up Automated Security Updates on Ubuntu VPS

Set up automatic security updates on an Ubuntu VPS with safe unattended-upgrades, reboot handling, and clear verification steps.

By Anurag Singh
Updated on Oct 26, 2026
Category: Tutorial
Share article
Set Up Automated Security Updates on Ubuntu VPS

Patching isn’t hard. Remembering to patch is. If you run production workloads on a VPS—WordPress, a Node app, an API, a mail relay—the challenge isn’t how to update. It’s that weeks pass, a kernel CVE drops, and your backlog wins.

This tutorial shows how to set up automatic security updates on an Ubuntu VPS with unattended-upgrades. You’ll also add sensible reboot handling. And you’ll verify results from logs, not assumptions. The goal is simple: ship security fixes quickly without turning maintenance into roulette.

What you’ll build (and what you won’t)

  • Daily security patching for Ubuntu packages (security origin only by default).
  • Clear logging and email (optional) so you can audit what changed.
  • Controlled reboots for kernel/glibc updates using a maintenance window.
  • Verification steps to confirm patching works and services stay healthy.

You won’t enable unattended upgrades for every package here. That’s a separate operational decision.

Security-only covers major risks with fewer surprises.

Prerequisites and quick safety checks

You’ll need:

  • An Ubuntu VPS (20.04+ works; Ubuntu 22.04/24.04 are common in 2026).
  • Root access (or a sudo user).
  • 10 minutes of focused time.

If you’re still choosing infrastructure, start with a VPS you can manage end-to-end. A HostMyCode VPS fits this workflow well because you have full OS access and no shared-hosting limitations.

Before you change anything, confirm you have disk space and that APT is clean:

df -h
sudo apt-get update
sudo apt-get -y upgrade --dry-run

If apt reports broken packages, stop and fix that first.

Automated patching should not be the first maintenance task on a neglected server.

Understand the moving parts (so you can debug later)

Ubuntu unattended security patching usually comes down to three pieces:

  • unattended-upgrades: installs approved updates automatically.
  • apt-daily.timer and apt-daily-upgrade.timer: systemd timers that run update checks and upgrades.
  • Logs in /var/log/unattended-upgrades/ and APT history in /var/log/apt/.

Your job is straightforward. Allow the right origins and pick conservative behavior.

Then prove it works.

Step 1: Install and enable unattended-upgrades

Install the package and a companion tool that reports changes:

sudo apt-get update
sudo apt-get install -y unattended-upgrades apt-listchanges

Enable unattended upgrades using Ubuntu’s helper:

sudo dpkg-reconfigure -plow unattended-upgrades

Select Yes when prompted.

Verify the timers exist and are scheduled:

systemctl list-timers | grep -E 'apt-daily|apt-daily-upgrade'

You should see both timers listed.

Step 2: Restrict updates to security (default you can live with)

Edit the origins configuration:

sudo nano /etc/apt/apt.conf.d/50unattended-upgrades

Find Unattended-Upgrade::Allowed-Origins. On some releases it’s Origins-Pattern.

In either case, make sure security updates are allowed.

A typical security-only setup looks like this (adjust variables as needed, but keep the -security entry):

Unattended-Upgrade::Allowed-Origins {
        "${distro_id}:${distro_codename}-security";
        // Optional: "${distro_id}:${distro_codename}-updates";
};

If your release uses Origins-Pattern, ensure security is included:

Unattended-Upgrade::Origins-Pattern {
        "origin=${distro_id},suite=${distro_codename}-security";
};

Why you care: adding -updates increases change volume. It’s not automatically “wrong.”

It does mean more packages, more restarts, and more chances to hit a dependency shift at a bad time. Security-only is the safest fix for patch drift.

Common mistake: the security origin is commented out. Timers fire, logs appear, and nothing gets installed.

Step 3: Set safe unattended behavior (logging, cleanups, and no surprise reboots)

In the same file (/etc/apt/apt.conf.d/50unattended-upgrades), set options that work well on web and app servers:

// Keep history so you can audit changes
Unattended-Upgrade::MinimalSteps "true";
Unattended-Upgrade::Remove-Unused-Dependencies "true";
Unattended-Upgrade::Remove-New-Unused-Dependencies "true";

// Automatically fix interrupted dpkg runs
Unattended-Upgrade::AutoFixInterruptedDpkg "true";

// If a package asks about restarting services, do it without prompting.
// This prevents upgrades from hanging.
Unattended-Upgrade::Automatic-Reboot "false";
Unattended-Upgrade::Automatic-Reboot-WithUsers "true";

Two practical points:

  • Service restarts: security updates can restart PHP-FPM, Nginx, and OpenSSH. That’s normal. What matters is scheduling and checking for failures.
  • Automatic reboot: keep it false here. You’ll handle reboots explicitly in the next step, on your terms.

For troubleshooting, confirm debug logging is disabled unless you need it:

Unattended-Upgrade::Debug "false";

Leave debug off for normal operations.

Step 4: Configure update schedules (systemd timers)

Ubuntu uses systemd timers. Defaults are fine for many hosts.

Production systems often benefit from a predictable window.

Inspect the current timer definitions:

systemctl cat apt-daily.timer
systemctl cat apt-daily-upgrade.timer

If you want a defined window (example: sometime between 02:00 and 03:00), create an override. Don’t edit vendor files.

Create an override for apt-daily-upgrade.timer:

sudo systemctl edit apt-daily-upgrade.timer

Add:

[Timer]
OnCalendar=
OnCalendar=*-*-* 02:15
RandomizedDelaySec=20m
Persistent=true

Reload and verify the new schedule:

sudo systemctl daemon-reload
sudo systemctl restart apt-daily-upgrade.timer
systemctl list-timers | grep apt-daily-upgrade

Common mistake: skipping the blank OnCalendar= line. That line clears the existing schedule.

Without it, you can end up with multiple triggers.

Step 5: Add reboot handling you can live with

Kernel and core library updates may require a reboot. If you ignore that, you end up with patched files but an old running kernel.

You can also keep old in-memory libraries until a restart.

Ubuntu signals this with:

  • /var/run/reboot-required present
  • /var/run/reboot-required.pkgs listing the packages that triggered it

You have two sensible options:

  • Notify-only: alert yourself, then reboot manually inside your window.
  • Auto-reboot in a window: reboot automatically if required, but only at a set time.

Option A (recommended): auto-reboot only inside a maintenance window

Create a small systemd service and timer. They check for reboot-required and reboot during your chosen window.

Create the script:

sudo nano /usr/local/sbin/reboot-if-required

Paste:

#!/usr/bin/env bash
set -euo pipefail

if [[ -f /var/run/reboot-required ]]; then
  logger -t reboot-if-required "Reboot required; rebooting now"
  /usr/sbin/shutdown -r +1 "Automatic reboot (security updates)"
else
  logger -t reboot-if-required "No reboot required"
fi

Make it executable:

sudo chmod 0755 /usr/local/sbin/reboot-if-required

Create a systemd service:

sudo nano /etc/systemd/system/reboot-if-required.service
[Unit]
Description=Reboot if Ubuntu reports reboot-required

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/reboot-if-required

Create a timer (example: 03:30 daily):

sudo nano /etc/systemd/system/reboot-if-required.timer
[Unit]
Description=Daily reboot-required check

[Timer]
OnCalendar=*-*-* 03:30
Persistent=true

[Install]
WantedBy=timers.target

Enable it:

sudo systemctl daemon-reload
sudo systemctl enable --now reboot-if-required.timer
systemctl list-timers | grep reboot-if-required

Verify logging:

journalctl -u reboot-if-required.service --no-pager -n 50

Operational tip: pick a time when a 1–2 minute interruption is acceptable.

For WordPress and PHP apps behind Nginx, that’s usually fine if caching and health checks are doing their job.

Option B: notify-only (email), no auto reboot

If you want manual control, enable email reports. That keeps “reboot required” from sitting unnoticed for weeks.

On many servers, sending mail requires an MTA or relay. If you already have a relay for your stack, reuse it.

If you don’t, follow HostMyCode’s guide for a safer SMTP relay approach: build a VPS SMTP relay with Postfix.

Then set these in 50unattended-upgrades:

Unattended-Upgrade::Mail "you@example.com";
Unattended-Upgrade::MailReport "only-on-error";

Use on-change if you want a message every time packages are upgraded.

Step 6: Run a controlled test (without waiting for tonight)

Don’t wait for the timer. Validate your settings now by running the same code path manually.

Start with a dry run and verbose output:

sudo unattended-upgrade --dry-run --debug

Look for lines that show allowed origins and candidate packages.

If it reports “No packages found that can be upgraded unattended,” that can be normal on a fully patched server. It can also mean your origins don’t match.

Then run an actual upgrade (it still respects your allowed origins):

sudo unattended-upgrade -v

Verify results in the logs:

sudo tail -n 80 /var/log/unattended-upgrades/unattended-upgrades.log
sudo tail -n 80 /var/log/apt/history.log

Finally, check whether a reboot is needed:

if [ -f /var/run/reboot-required ]; then echo "REBOOT REQUIRED"; else echo "No reboot required"; fi

Step 7: Verify your services didn’t break (quick checklist)

Security updates can restart daemons. Treat this as a normal maintenance event.

Do a quick health check right after upgrades.

  • Nginx: sudo nginx -t && sudo systemctl status nginx --no-pager
  • Apache: sudo apachectl configtest && sudo systemctl status apache2 --no-pager
  • PHP-FPM: sudo systemctl status php*-fpm --no-pager
  • Database: sudo systemctl status mysql --no-pager or sudo systemctl status postgresql --no-pager
  • Disk pressure: df -h (a full disk can leave upgrades half-applied)

If you want a practical hardening baseline for Nginx + PHP-FPM after patching is under control, see: secure Nginx + PHP-FPM on a VPS.

Step 8: Add monitoring so you notice failures

Unattended patching usually fails in boring ways. Common causes are DNS issues, mirror timeouts, or a disk that slowly fills.

The risky part is silence.

At minimum, watch:

  • CPU and RAM spikes after restarts
  • Disk space and inode usage
  • Service uptime after the maintenance window

A practical setup for VPS operators is Netdata plus an uptime checker. HostMyCode has a walkthrough here: build alerts with Netdata + uptime checks.

Troubleshooting common unattended-upgrades problems

“unattended-upgrade” runs but installs nothing

  • Check your origins: grep -R "Allowed-Origins\|Origins-Pattern" -n /etc/apt/apt.conf.d/50unattended-upgrades
  • List upgradable packages: apt list --upgradable
  • Confirm security pocket exists: grep -R "-security" /etc/apt/sources.list /etc/apt/sources.list.d/*.list

Upgrades hang waiting for input

This is usually a maintainer prompt. The most common triggers are config file questions and service restart prompts.

  • Check logs: sudo tail -n 200 /var/log/unattended-upgrades/unattended-upgrades.log
  • Check dpkg state: sudo dpkg --configure -a
  • If the VPS is stuck mid-upgrade, fix it interactively once. Then keep AutoFixInterruptedDpkg enabled.

Reboot required, but it never happens

  • Confirm timer is enabled: systemctl status reboot-if-required.timer --no-pager
  • Confirm the script runs: sudo /usr/local/sbin/reboot-if-required
  • Check journald: journalctl -u reboot-if-required.service --no-pager -n 100

My website goes down after the reboot window

Start with evidence. Find what failed before you change anything else:

sudo systemctl --failed
sudo journalctl -p err -b --no-pager | tail -n 120

If your incident plan includes DNS cutovers and parallel hosting, keep this runbook handy: build a tested VPS recovery plan.

Security notes specific to VPS operators

  • Keep SSH stable: OpenSSH security updates can restart sshd, but existing sessions usually survive. Still, don’t schedule updates during your own SSH maintenance.
  • Don’t skip backups: automated updates are not a backup plan. If WordPress and your database live on the same VPS, test restores.
  • Separate concerns: if this server makes money, consider managed operations so patching, monitoring, and rollback have clear ownership.

Summary: a practical patching baseline for 2026

You now have security-only unattended upgrades running on a predictable schedule.

You also have a reboot strategy that waits for your window. And you know where to look to confirm updates actually installed.

If you’d rather not babysit this long term—especially for production WordPress or business apps—use managed VPS hosting from HostMyCode. If you want full control, a standard HostMyCode VPS gives you the access you need to run automatic security updates cleanly.

If your VPS patching has been stuck at “I’ll do it this weekend” for months, fix the process instead of relying on memory. Run this tutorial on a HostMyCode VPS, or hand off the operational load to managed VPS hosting so updates, monitoring, and reboots follow a controlled routine.

FAQ

Will automatic security updates reboot my Ubuntu VPS?

Not with the configuration above. Unattended upgrades install security patches, but reboots are handled by the separate timer you created (and only when /var/run/reboot-required exists).

Should I enable “-updates” as well as “-security”?

Security-only is the safest default for most VPS owners. If you need bugfix updates quickly, enable -updates. Expect more frequent package changes and restarts.

How do I confirm what packages were installed automatically?

Check /var/log/apt/history.log and /var/log/unattended-upgrades/unattended-upgrades.log. They include package names, versions, and timestamps.

What if unattended-upgrades breaks my app?

It’s uncommon with security-only origins, but it’s possible. The fastest path is to (1) check journalctl -p err -b, (2) roll back via package version pinning or restore from backup, and (3) narrow your maintenance window while tightening monitoring.

Does this replace a firewall or hardening?

No. Patching reduces exposure to known vulnerabilities. You still need basics like a firewall and a hardened web stack. If you haven’t done that yet, start with a baseline such as UFW and a hardened Nginx/PHP setup.

Set Up Automated Security Updates on Ubuntu VPS | HostMyCode