Automatic security updates on Linux servers

Updated November 2026

Automatic updates close the gap between “a fix is published” and “the fix is on my server” from days to hours. Every major Linux distribution and FreeBSD ships a tool for it; this guide shows the exact settings for each and how to roll them out without surprise outages.

Should you automate?

For most internet-facing servers, yes, at least for security updates. Attackers often start scanning for a flaw within days of the fix. A server that installs security fixes every night is rarely the one that gets caught.

A common middle ground: install security updates automatically, keep feature updates manual, and reboot in a planned window. The sections below follow that pattern.

Debian and Ubuntu

The tool is unattended-upgrades. On Ubuntu it is normally installed already. On Debian, install and enable it:

sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades

Answer “Yes”. This writes /etc/apt/apt.conf.d/20auto-upgrades with these two lines (the number is “every N days”; 0 turns it off):

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

What gets installed is set in /etc/apt/apt.conf.d/50unattended-upgrades. Debian’s default pattern covers the security archive and stable point-release updates. Ubuntu’s default covers the release, its -security pocket and, if Ubuntu Pro is attached, the ESM security pockets; general -updates stay commented out. Packages from third-party repositories are not upgraded unless you add their origin.

Do not edit the shipped file. The upstream documentation recommends a local file that sorts later, so package updates do not conflict with your changes:

sudo nano /etc/apt/apt.conf.d/52unattended-upgrades-local
// Reboot by itself if /var/run/reboot-required exists after an upgrade
Unattended-Upgrade::Automatic-Reboot "true";
// Do not reboot while someone is logged in
Unattended-Upgrade::Automatic-Reboot-WithUsers "false";
// Reboot at 03:30 local time instead of "now" (the default)
Unattended-Upgrade::Automatic-Reboot-Time "03:30";
// Report by mail (needs a working mail setup, e.g. mailx + an MTA)
Unattended-Upgrade::Mail "ops@example.com";
Unattended-Upgrade::MailReport "only-on-error";
// Clean up old kernels so /boot does not fill up
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";

Automatic-Reboot is off by default. Turn it on only if an unplanned reboot at 03:30 is acceptable for that server. MailReport accepts always, only-on-error or on-change.

Test without changing anything, then read the log:

sudo unattended-upgrade --dry-run --debug
less /var/log/unattended-upgrades/unattended-upgrades.log

Service restarts on Ubuntu. Since Ubuntu 24.04 LTS, needrestart restarts affected services automatically after updates by default. Services it must never touch go in a file under /etc/needrestart/conf.d/, not in the main config.

RHEL, AlmaLinux, Rocky and Oracle Linux

RHEL 8, 9 and 10 and their rebuilds use dnf-automatic:

sudo dnf install dnf-automatic
sudo nano /etc/dnf/automatic.conf

Set the [commands] section for security-only installs:

[commands]
upgrade_type = security
download_updates = yes
apply_updates = yes

Then enable the timer that follows the config file:

sudo systemctl enable --now dnf-automatic.timer
systemctl list-timers 'dnf-automatic*'

Red Hat also ships timers with a fixed behavior that override apply_updates and download_updates: dnf-automatic-notifyonly.timer (report only), dnf-automatic-download.timer (download, do not install) and dnf-automatic-install.timer (download and install). Enable only one of them.

upgrade_type = security only works when the repository publishes advisory metadata. Check what it would pick up with sudo dnf updateinfo list --security. If that list is empty while updates exist, security filtering will install nothing.

Newer dnf-automatic versions also accept reboot = never | when-changed | when-needed and a reboot_command (default: shutdown -r +5 with a message). Check man dnf-automatic on your release before relying on it.

Fedora and DNF5

Fedora 41 and later use DNF5, and the automatic tool changed. The package is dnf5-plugin-automatic (it also provides the name dnf-automatic):

sudo dnf install dnf5-plugin-automatic
sudo cp /usr/share/dnf5/dnf5-plugins/automatic.conf /etc/dnf/automatic.conf
sudo nano /etc/dnf/automatic.conf
sudo systemctl enable --now dnf5-automatic.timer

The differences that catch people out:

[commands]
apply_updates = yes
upgrade_type = security
reboot = when-needed
reboot_command = "shutdown -r +5 'Rebooting after applying package updates'"

SUSE and openSUSE

SUSE delivers fixes as patches with a category (security, recommended, optional) and a severity. To install only security patches by hand:

sudo zypper list-patches --category security
sudo zypper --non-interactive patch --category security --with-interactive

If zypper exits with code 103, it updated itself first; run the same command again. sudo zypper needs-rebooting exits with 102 when a reboot is suggested.

SLES 15 and Leap 15 with YaST: run sudo yast2 online_update_configuration (package yast2-online-update-configuration), pick Daily, and under “Filter by Category” select Security. SUSE’s guide notes that these automatic updates never reboot the system.

openSUSE Leap 16 and Tumbleweed: the os-update package runs daily from os-update.timer. Put only the values you change in /etc/os-update.conf:

sudo zypper install os-update
echo 'UPDATE_CMD="security"' | sudo tee /etc/os-update.conf
echo 'REBOOT_CMD="none"' | sudo tee -a /etc/os-update.conf
sudo systemctl enable --now os-update.timer

With REBOOT_CMD="none" it only prints that a reboot is needed; the default auto reboots through rebootmgr or systemctl reboot.

Any SUSE release, including SLES 16: a small systemd timer of your own works everywhere. Create /etc/systemd/system/zypper-security.service:

[Unit]
Description=Install SUSE security patches
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
SuccessExitStatus=102 103
ExecStart=/usr/bin/zypper --non-interactive patch --category security --with-interactive --auto-agree-with-licenses
ExecStart=/usr/bin/zypper --non-interactive patch --category security --with-interactive --auto-agree-with-licenses

--with-interactive stops zypper from skipping patches that need a reboot, such as kernel fixes; without it, non-interactive mode skips them. The second run installs anything left after a zypper self-update. Then /etc/systemd/system/zypper-security.timer:

[Unit]
Description=Daily SUSE security patches

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

[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable --now zypper-security.timer

Alpine Linux

Alpine has no security-only filter, but stable branches only get security patches for the versions they ship, so upgrading within a branch is low-risk. Use the cron daemon’s daily directory. The default root crontab runs /etc/periodic/daily at 02:00. As root:

cat > /etc/periodic/daily/apk-upgrade <<'EOF'
#!/bin/sh
apk update -q && apk upgrade -q
EOF
chmod +x /etc/periodic/daily/apk-upgrade
rc-update add crond default
rc-service crond start

A new linux-lts or linux-virt kernel still needs a reboot, which this script does not do.

FreeBSD

The base system and packages update separately. For the base system, add this line to /etc/crontab:

@daily  root  freebsd-update cron

freebsd-update cron waits a random 1 to 3,600 seconds, downloads any patches and mails root. It does not install them. Apply them as root and, if a kernel patch was included, reboot (the last command reboots the server):

freebsd-update install
freebsd-version -k; uname -r   # different? reboot
shutdown -r now

freebsd-update rollback undoes the last install. On FreeBSD 15 systems installed with base packages (pkgbase, a tech preview), update the base with pkg upgrade -r FreeBSD-base instead.

For third-party packages, a daily vulnerability check is a safe first step; schedule the upgrade itself in your maintenance window:

0 5 * * *  root  pkg audit -F
30 3 * * 2 root  pkg upgrade -y

pkg does not restart services; restart them afterwards (see Restarts and reboots).

Roll out safely

  1. Staging first. Point one or two test servers, which run the same packages as production, at the same repositories and let them update a day earlier. Most breakage shows up there.
  2. Stagger production. Split servers into groups with different timer times, so one bad update never hits every node of a cluster at once.
  3. Set a maintenance window. Use timer times (03:30, Automatic-Reboot-Time, OnCalendar) that match the window your users expect, and never reboot all members of a cluster together.
  4. Monitor results. Send reports somewhere a person reads them, alert on failed timer runs (systemctl list-timers, systemctl status) and on servers that need a reboot for more than a few days.
  5. Know how to go back. Take a snapshot before risky windows; know dnf history undo, freebsd-update rollback or your snapshot tool before you need them.
  6. Do not stop at automation. A critical, actively exploited flaw should be patched by hand the same day; see Emergency patching.

Automation does not fix an unsupported release. Once your release is end-of-life, the timers keep running but no new fixes arrive. Check your release on the Linux and Unix pages.

Sources