Security updates fix known vulnerabilities (CVEs) in the kernel, the libraries and the installed services. On an exposed server, applying them quickly is the first line of defence. Each distribution provides a way to target only these patches, without pulling in functional version upgrades.
This guide shows the commands that work, and takes apart two widespread recipes that patch nothing at all while giving the reader the impression of having secured the machine. That is worse than no patch: it is an imaginary patch. All outputs were captured on 30 September 2026 on Debian 13, Ubuntu 24.04 and AlmaLinux 10.2.
What you will learn
- Tell security updates apart from regular updates
- List the available security patches on Debian/Ubuntu and on RHEL
- Apply only the security patches, with verified commands
- Configure automatic updates without them doing more than intended
- Check that a patch is really installed, and whether a reboot is required
- Recognise the two commands that patch nothing despite appearances
In what context?
Security updates are critical in any infrastructure:
- A critical CVE is published for OpenSSL or the kernel, and you must patch within hours.
- Your web server is exposed to the Internet, and every outdated package widens the attack surface.
- Compliance imposes a maximum patching delay (30 days for the CIS or ANSSI frameworks).
- You manage a fleet of servers and must automate without risking a regression.
- Before an audit, you must prove that the system is up to date on critical CVEs.
Regular updates and security updates
| Type | Contents | Regression risk | Urgency |
|---|---|---|---|
| Security | CVE fixes, targeted patches | Low (minimal changes) | High |
| Bugfix | Fixes for functional bugs | Medium | Medium |
| Feature | New features, version upgrades | High | Low |
In production, the strategy fits in one sentence: apply security automatically, and schedule the rest in a maintenance window.
A fourth case falls completely outside this table: the major version upgrade of the distribution, for instance from Debian 12 to Debian 13. It is not an update, it is a migration, with its preparations and its traps (network interface names may change, /etc/sysctl.conf stops being read, a badly stopped MariaDB database becomes unrecoverable). It cannot be automated: see Debian 13 "Trixie" (in French).
On Debian and Ubuntu
List the available security patches
Start by refreshing the package catalogue. This command changes nothing on the system:
sudo apt updateTo see what is security-related, filter on the origin of the package, because that is what carries the information:
apt list --upgradable 2>/dev/null | grep -i securitylibssl3t64/noble-security 3.0.13-0ubuntu3.6 amd64 [upgradable from: 3.0.13-0ubuntu3.4]openssl/noble-security 3.0.13-0ubuntu3.6 amd64 [upgradable from: 3.0.13-0ubuntu3.4]The -security suffix in the suite name (noble-security on Ubuntu, stable-security on Debian 13, which shows bsdutils/stable,stable-security) is what tells a security patch apart from a regular update.
The command that patches nothing
Here is the recipe found everywhere, and on this very site until this review:
# ❌ DO NOT DO THIS: this command installs nothingsudo apt-get upgrade -y -o Dir::Etc::SourceList=/etc/apt/sources.list \ -o Dir::Etc::SourceParts=/dev/nullThe idea looks clever: restrict APT to sources.list alone by neutralising the rest. It does not work, and the lab proves it. In simulation, measured on 30 September 2026:
Ubuntu 24.04 Debian 13apt-get -s upgrade 36 packages 24 packagesapt-get -s upgrade -o Dir::Etc::SourceList=... 0 packages 0 packagesDozens of updates available, zero applied. The reason is that the repositories have moved to the deb822 format: the real sources live in /etc/apt/sources.list.d/ubuntu.sources (or debian.sources), and /etc/apt/sources.list only contains comments on Ubuntu 24.04, when it has not simply disappeared, as in the Debian 13 image. The command therefore points to an empty file, and SourceParts=/dev/null excludes the file that matters. APT no longer sees any repository, so it has nothing to install.
The worst part is not that it fails, it is that it fails silently: it returns 0, shows no error, and you leave the server believing it is patched.
The method that works
The only tool that really knows what a security update is on Debian and Ubuntu is unattended-upgrades. It reads the origin of the packages, not their name.
sudo apt install unattended-upgradessudo unattended-upgrades --dry-run -vAllowed origins are: o=Ubuntu,a=noble, o=Ubuntu,a=noble-security, o=UbuntuESMApps,a=noble-apps-security, o=UbuntuESM,a=noble-infra-securityPackages that will be upgraded: gzip libncursesw6 libtinfo6 ncurses-base ncurses-bin perl-base tarRemove --dry-run to apply for real. But first read the Allowed origins line: it hides a trap.
Configure automatic updates
Automating security on Debian and Ubuntu takes four steps, and the automation is only reliable if all four are done: install the package, restrict the origins, enable periodic execution, then check that the list of origins matches the intent. Skipping the second step gives an automation that also applies functional updates.
-
Install the package.
apt-listchangesis useful to receive the details of what changed.Terminal window sudo apt install unattended-upgrades apt-listchanges -
Restrict to security patches. It is the step most tutorials skip, and it is the most important one.
Terminal window sudo nano /etc/apt/apt.conf.d/50unattended-upgrades// Ubuntu 24.04 (on Debian 13, likewise comment out the first line of Origins-Pattern)Unattended-Upgrade::Allowed-Origins {// "${distro_id}:${distro_codename}"; // commented out: no functional updates"${distro_id}:${distro_codename}-security";};Unattended-Upgrade::Automatic-Reboot "false";Unattended-Upgrade::Mail "admin@example.com";Unattended-Upgrade::Remove-Unused-Dependencies "true";Option Recommendation in production Allowed-Origins(Ubuntu) orOrigins-Pattern(Debian)security only, the main repository line commented out Automatic-Rebootfalse: a reboot is scheduled, not sufferedMailan address someone really reads, otherwise the automation is blind Remove-Unused-Dependenciestrueto avoid piling up orphaned packages -
Enable the service. Without this command, the configuration exists but nothing runs it.
Terminal window sudo dpkg-reconfigure -plow unattended-upgrades -
Check that the result matches the intent. It is the only proof that counts: the
Allowed originsline must only contain security origins (noble-securityon Ubuntu,label=Debian-Securityon Debian).Terminal window sudo unattended-upgrades --dry-run -v | grep "Allowed origins"systemctl status apt-daily-upgrade.timer
Check what was applied
grep "^Upgrade:" /var/log/apt/history.log | tail -5sudo tail -20 /var/log/unattended-upgrades/unattended-upgrades.logThe first file logs all the APT operations, the second only those of the automation. Comparing the two reveals updates applied by hand, outside the procedure. Do filter on ^Upgrade:: each transaction lists its packages there in the form Upgrade: tzdata:amd64 (2026b-0+deb13u1, 2026c-0+deb13u1), old then new version, whereas a grep " upgrade " only returns the Commandline: line of an apt upgrade typed by hand.
On RHEL, Rocky and AlmaLinux
List the security patches
DNF, for its part, understands the notion of a security patch natively, because Red Hat publishes advisories (errata) that link a package to a CVE:
sudo dnf updateinfo list securityALSA-2026:59380 Moderate/Sec. attr-2.6.0-1.el10_2.x86_64ALSA-2026:67886 Moderate/Sec. coreutils-single-9.5-8.el10_2.1.x86_64ALSA-2026:33124 Moderate/Sec. coreutils-single-9.5-8.el10_2.x86_64Each line carries an advisory identifier (RHSA at Red Hat, ALSA at AlmaLinux, RLSA at Rocky) and a severity. It is this metadata that makes targeting possible, and reliable.
Apply only the security patches
The --security option restricts the transaction to the packages covered by an advisory, and severity narrows it further when only the most urgent must go out now:
sudo dnf update --securityTo handle only the most urgent ones, filter by severity:
sudo dnf update --security --sec-severity=Critical| Severity | When to apply |
|---|---|
Critical | immediately, without waiting for the maintenance window |
Important | within 48 hours |
Moderate | scheduled maintenance window |
Low | next maintenance |
Automate with dnf-automatic
On the RHEL side, the automation is called dnf-automatic and follows the same logic as on Debian: a package, a configuration file to restrict, a systemd timer to enable. Its shipped configuration is not limited to security either, and it does not even install anything as long as apply_updates stays at no.
-
Install the automation.
Terminal window sudo dnf install dnf-automatic -
Restrict it to security, in
/etc/dnf/automatic.conf:[commands]upgrade_type = securityapply_updates = yes[emitters]emit_via = email,stdio[email]email_from = root@localhostemail_to = admin@example.comThe key is
upgrade_type = security: its default value isdefault, which applies everything. The file shipped on AlmaLinux 10.2 also carriesapply_updates = no: without switching it toyes, the automation downloads without installing. -
Enable the timer, otherwise the configuration stays a dead letter.
Terminal window sudo systemctl enable --now dnf-automatic.timersystemctl status dnf-automatic.timer
Check what was applied
sudo dnf history listsudo dnf history info lastdnf history is richer than its APT equivalent: each transaction can be undone with dnf history undo <id>, which offers a real rollback after an unfortunate update.
Check the patch level of a system
Is a specific package up to date?
Faced with a security advisory that names a package, the first question is simple: is the installed version the latest one published by the repositories? Each family answers it with one command, which compares the installed version with the candidate.
apt-cache policy opensslopenssl: Installed: 3.0.13-0ubuntu3.6 Candidate: 3.0.13-0ubuntu3.6If Installed equals Candidate, the package is up to date.
dnf list --installed openssldnf check-update opensslIf check-update returns nothing and exits with code 0, the package is up to date. A code 100 means an update exists.
Do you need to reboot?
A patch to the kernel, glibc or systemd only takes effect after a reboot. The method differs by family.
[ -f /run/reboot-required ] && cat /run/reboot-required.pkgsThe file only exists if a package requested a reboot, and the second one names the culprits. Do use /run/: /var/run is only a symbolic link inherited from the past.
sudo dnf needs-restarting -recho "exit code: $?"There are two forms, and mixing them up costs a command not found error. The dnf needs-restarting subcommand comes from the python3-dnf-plugins-core package, already installed on an AlmaLinux 10.2: it works without adding anything and answers Reboot should not be necessary. on an up-to-date machine, measured in the lab. The standalone command needs-restarting, without the dnf prefix, comes from yum-utils (which the dnf-utils virtual dependency also resolves) and is not installed by default.
The exit code carries the answer as much as the text: 1 if a reboot is required, 0 otherwise. In a script run with set -e, the command therefore stops execution at the precise moment it has something to report. Test the code rather than ignoring it:
if ! dnf needs-restarting -r; then echo "reboot required"fiFinally, there is no /run/reboot-required file on RHEL: it is a Debian reflex that does not carry over.
Update policy in production
| Environment | Security | Functional | Reboot |
|---|---|---|---|
| Dev / Test | automatic, immediate | automatic | automatic |
| Staging | automatic, immediate | weekly | scheduled |
| Production | automatic, security only | maintenance window, after validation in staging | maintenance window |
The rule that holds in production: security is automated, functional updates are scheduled, reboots are decided. The three are distinct decisions, and confusing them is the most frequent source of incidents related to updates.
Three safeguards complete the setup. Receive the reports by email, and read them: an automation whose output nobody reads is a blind automation. Test functional updates in staging before production. And do not postpone reboots indefinitely: an unapplied kernel patch protects against nothing.
Troubleshooting
Most problems come from a command that fails silently, or from an automation configured but never triggered. The table starts from the visible symptom.
| Symptom | Probable cause | Solution |
|---|---|---|
apt update fails on a key | Repository key expired or missing | Put the key in /etc/apt/keyrings/ and declare it with Signed-By:. apt-key is gone from Debian 13, and only deprecated on Debian 12 and Ubuntu 24.04. |
| The "security only" command installs nothing | sources.list is empty (deb822 format) | Go through unattended-upgrades, the only tool that reads the origin of packages |
dnf update --security does nothing on Fedora | Fedora publishes no security advisories | Use plain dnf update |
needs-restarting: command not found | Standalone command missing by default on RHEL | Use dnf needs-restarting, or dnf install yum-utils |
| unattended-upgrades also applies functional updates | The main suite line is active by default | Comment it out in 50unattended-upgrades |
| The automation never runs | Timer not enabled | systemctl enable --now apt-daily-upgrade.timer (or dnf-automatic.timer) |
| Update blocked by a conflict | Held package or broken dependency | apt --fix-broken install, or dnf distro-sync |
| Interrupted transaction | Outage during the operation | dpkg --configure -a, or dnf check then dnf distro-sync |
Key points
- Security updates fix CVEs: they come first, with a low regression risk.
- Two widespread recipes patch nothing, silently and returning 0: the APT command with
Dir::Etc::SourceList(sources.listis empty with deb822), anddnf --securityon Fedora (which publishes no security advisory). - On Debian and Ubuntu, the only tool that really identifies security updates is
unattended-upgrades: it reads the origin of packages, not their name. - Its default configuration is not limited to security, on Ubuntu as on Debian: the main suite line also allows functional updates. Comment it out in production.
- On RHEL and its derivatives,
dnf update --securityworks because Red Hat publishes advisories linking package and CVE.--sec-severity=Criticaltargets urgency. - On RHEL,
dnf needs-restarting -rworks out of the box, but the standaloneneeds-restartingcommand requiresyum-utils./run/reboot-requireddoes not exist: it is a Debian reflex. - After a kernel patch,
uname -rstill shows the old one until you reboot. An up-to-date server running a vulnerable kernel is a failed audit. - In production: security is automated, functional updates are scheduled, reboots are decided.
Knowledge check
Check that the essentials of this guide are acquired. The questions only cover what has just been explained here.
Knowledge check
Check what you have learned with this interactive quiz
How it works
- The timer starts when you click Start
- Multiple choice, true/false and short answer questions
- You can move between questions
- Detailed results are shown at the end
Starts the quiz and the timer
Review
(0/0)Score by domain
A domain groups several guides and gets several questions, so its score is more reliable than a per-topic score, which often rests on a single question.
Summary
Strengths
No topic passed at 80% on at least two questions yet.
Weak areas
No topic below the pass mark.
Recommended next
Hints before you try again?
Continue the course: Start a Linux service automatically at boot (systemctl enable)
A new full quiz with random questions
Work again only on the questions you missed