How to set dnf-automatic for security updates
Make your Rocky or AlmaLinux server update security patches by itself. Learn how to configure dnf-automatic, set systemd timers, and manage reboots without any surprises.
Wetin dnf-automatic dey do for Rocky Linux and AlmaLinux
dnf-automatic na how you go take get security updates wey dey run by imself for Rocky Linux and AlmaLinux. E be one small program, wey systemd timer dey start, wey dey read /etc/dnf/automatic.conf and apply wetin that file allow. To install am, you need just one command. The rest of this guide na about the settings wey go decide weda e go protect your server or just dey silent and no do anything.
If you come from Debian or Ubuntu, this one be the same work wey unattended-upgrades dey do for Ubuntu VPS. One difference dey wey important pass all the others: wetin the word "security" mean for the package manager. For Ubuntu, e be separate archive pocket. For RHEL family, e be metadata wey dem attach to published advisories, and that metadata fit miss or dey outdated. If you point dnf-automatic go repository wey no get advisory data, e no go install anything but e go still report say e succeed.
We write this guide for Rocky Linux 9 and AlmaLinux 9, wey dey use DNF 4 (DNF na the package manager for RHEL family), as of August 2026. The 10 releases don move go DNF5 and the names don change for there, so dem get their own section near the end. Every command wey dey below na one wey you suppose run for your own box, with the output wey you suppose expect near am.
Install dnf-automatic and read the config wey e come wit
To enable automatic updates na part of wetin you suppose do for the first ten minutes on a new VPS, immediately after you don create non-root user and setup firewall. If you never setup firewall, firewalld na wetin Rocky and AlmaLinux dey use, and few commands fit open SSH, open the port wey your site dey listen on, and make sure say dem still dey active after you reboot.
sudo dnf install -y dnf-automatic
rpm -q dnf dnf-automatic
systemctl is-enabled dnf-automatic.timersystemctl is-enabled go print disabled for fresh install, because to install the package no mean say e go start automatically. Na this one be the common reason why server wey "get dnf-automatic" no fit apply even one update.
The DNF version dey important for one option. The reboot setting show up for DNF 4.15, and Red Hat backport am enter dnf-4.14.0-6.el9 for November 2023 through advisory RHBA-2023:6645. Rocky 9 and AlmaLinux 9 rebuild that package, so any current box get am, but box wey you no touch since 2023 no go get am.
The config file na /etc/dnf/automatic.conf. The copy wey come wit the package list every option wey this build sabi, plus the default, wey dem comment out. Read am once before you edit am, because that file na the correct truth about your version.
Di two switches wey dey decide wetin go happen
download_updates and apply_updates inside di [commands] section dey decide how di tin go behave. Both of dem dey no by default for EL9 (enterprise Linux 9, wey be di base for Rocky 9 and AlmaLinux 9), so if you just enable dnf-automatic without edit anytin, e go only tell you wetin dey available.
- Both
no: dnf-automatic go report available updates but e no go change anytin for di box. download_updates = yeswithapply_updates = no: dem go download packages enter DNF cache. Di installation go come fast and e no go need network, but no change go happen dat night.- Both
yeswithupgrade_type = default: every update wey dey available go install, weda e be security update or not. - Both
yeswithupgrade_type = security: only packages wey dey inside security advisory dem go install.
One beta way to start for VPS wey dey face internet:
[commands]
upgrade_type = security
download_updates = yes
apply_updates = yes
random_sleep = 0
network_online_timeout = 60
reboot = nevernetwork_online_timeout na how many seconds di run go wait for network make e work before e give up, dis one dey important for box wey just boot. random_sleep na old way to spread load across plenty machines, but now na di timer dey do dat work. Run systemctl cat dnf-automatic.service to see di exact flags wey di service wey come wit di software dey use.
Make you prove say di file dey do wetin you tink, without waiting until 06:00:
sudo systemctl start dnf-automatic.service
sudo journalctl -u dnf-automatic.service -n 50 --no-pagerDi journal go show you wetin di run consider and wetin e do. You fit also force one behaviour from command line, wey go override di file for dat run only:
sudo dnf-automatic --downloadupdates --no-installupdatesWetin upgrade_type = security actually mean for Rocky and Alma
DNF no dey know weda update na security update by just checking version numbers. E dey read errata metadata: one file wey dem dey call updateinfo.xml wey dey inside the repository, where each advisory dey list the packages wey fix am. AlmaLinux dey publish dis one as ALSA advisories, Rocky dey publish dem as RLSA. upgrade_type = security go build filter from dat metadata and upgrade only the packages wey match.
Two things dey happen, and both of dem dey surprise people.
First, if metadata no dey, update no go happen. If the repository no get updateinfo.xml, the filter no go match anything and the process go end with dis line for the journal:
No security updates needed, but 3 updates availableThe server no get patch, and nothing go report say e fail. Check am yourself:
dnf updateinfo list --security
dnf check-updateIf dnf check-update list packages but dnf updateinfo list --security no print anything at all, e fit be say nothing wey dey pending get advisory, or the repository no get advisory data to read. Rocky and AlmaLinux both dey publish am, so for those two, if the list empty, e usually mean say nothing dey. CentOS Stream no dey publish am at all.
Second, security mode no be minimal change. dnf-automatic dey add the security filter and then e go run the normal upgrade path, so any package wey dey inside advisory go move to the newest version for the repository and e go carry im dependencies join body. The smaller step, wey be to move only to the earliest version wey fix the advisory, na dnf upgrade-minimal --security wey you go run by hand. dnf-automatic no get setting for dat one.
One more thing wey you must know about Rocky. Rocky dey generate im errata from Red Hat data through im own pipeline, and dat pipeline don lag behind. For September 2025, users report say the Rocky 9 BaseOS updateinfo.xml no move since December 2024, so --security bin miss recent advisories, and Rocky staff confirm say na known issue. If you dey depend on upgrade_type = security, compare the advisory list with recent RLSA announcements from time to time. For server where coverage dey important pass change control, upgrade_type = default on schedule wey you choose na the safer setting.
The systemd timer wey dey run am
sudo systemctl enable --now dnf-automatic.timer
systemctl list-timers dnf-automatic.timerlist-timers suppose print one row wey show NEXT time wey go reach for one day time. If the table empty, e mean say the timer no dey enabled, so nothing go ever run.
The timer wey come with the package dey fire for *-*-* 6:00 with RandomizedDelaySec=60m and Persistent=true. The random delay dey spread the load across one hour so say all server no go hit the mirror for the same second. Persistent=true mean say if machine off for 06:00, e go run the job wey e miss as soon as e boot, instead of make e skip the day.
Change the schedule with one drop-in file. No edit the unit wey come with the package, because if you upgrade the package, e go replace files wey dey inside /usr/lib/systemd/system.
sudo systemctl edit dnf-automatic.timer[Timer]
OnCalendar=
OnCalendar=*-*-* 03:30
RandomizedDelaySec=30mThe empty OnCalendar= line dey necessary. OnCalendar dey accumulate, so if you no reset am, you go keep the 06:00 entry and add another one, and the job go run twice every day. Confirm the result with systemctl list-timers dnf-automatic.timer and check the NEXT column. The same drop-in rules apply to any other thing wey you wan schedule, wey we don explain for writing systemd service and timer units.
Now the trap. The package get three more timers: dnf-automatic-notifyonly.timer, dnf-automatic-download.timer and dnf-automatic-install.timer. Each one dey start the same program with command-line flags, and those flags go override download_updates and apply_updates wey dey your config file. If you enable one of dem join dnf-automatic.timer, the job go run twice with two different behaviours, and e go look like say your config file no dey work. Enable one timer and check:
systemctl list-unit-files 'dnf-automatic*'How I go take know when dem install something?
emit_via for inside the [emitters] section dey control how dem dey report am. Under systemd, the stdio emitter dey write go the journal, and this one na the sure option because e no need any other thing make e work:
sudo journalctl -u dnf-automatic.service --since -7d --no-pagerThe motd emitter dey write the report inside /etc/motd and e dey replace wetin dey inside that file. If you dey keep login banner for there, no use this emitter.
The email emitter dey open SMTP (simple mail transfer protocol) connection go email_host for port email_port, wey be localhost and 25 by default. Fresh VPS no get anything wey dey listen for there, so the connection go fail and dem no go send any mail. Run ss -lnt | grep ':25' before you depend on am, and set up relay-only Postfix if you no see any output. When mail dey work, the subject go read Updates applied on 'web01'., and e go carry the name from system_name.
For any other thing, the command emitter dey give the report to your own program through standard input:
[emitters]
emit_via = stdio, command
system_name = web01.example.com
send_error_messages = yes
[command]
command_format = /usr/local/bin/notify-ops
stdin_format = {body}send_error_messages dey default to no, wey mean say if the run fail, e no go report anything at all. Make you turn am on. Patching system wey only dey announce when e succeed pass nothing, because when you no hear anything, you fit think say everything dey okay.
dnf-automatic no dey restart your services
If you install package, e go replace files for disk. Process wey don dey run go still keep the old code for memory, so patched library no go do anything for daemon wey start last month. That gap between when you install am and when e go start work na why unattended patching need restart policy, no be just install policy.
sudo dnf install -y dnf-plugins-core
dnf needs-restarting -s
dnf needs-restarting -r-s dey list the systemd services wey dia files change after dem start. -r dey answer one question, and e dey print one of two blocks:
Core libraries or services have been updated since boot-up:
* kernel
Reboot is required to fully utilize these updates.No core libraries or services have been updated since boot-up.
Reboot should not be necessary.-r no be deep analysis. E dey check fixed list of packages: kernel, kernel-core, kernel-rt, glibc, linux-firmware, systemd, dbus, dbus-broker, dbus-daemon and microcode_ctl. If dem install one of dem after the last boot, you go get the first answer. Add your own package names for file wey end with .conf under /etc/dnf/plugins/needs-restarting.d/ when something else for the box also need reboot before e go work.
One warning for scripts: dnf needs-restarting -r dey exit non-zero both when reboot dey needed and when the command itself fail, so you no fit use exit status alone know the difference. Read the output text.
To restart service na smaller move and usually na the correct one. Restart the SSH daemon from second SSH session wey already open, so bad config no go lock you out. New kernel na the case where only reboot fit help, because you no fit replace kernel wey dey run for inside. If you want sort updates for morning into those two buckets, which updates need a reboot and which only need a service restart go help you check the output package by package.
Containers na separate case, because dnf-automatic dey patch host packages and e no dey touch userland wey dey inside image, so box wey dey run Docker Engine on Rocky Linux or AlmaLinux also need make you pull images again and recreate containers before the fix go reach the code wey dey serve traffic.
Make the box dey reboot e-sef?
[commands]
reboot = when-needed
reboot_command = shutdown -r +5 'Rebooting after applying package updates'reboot = never na the default. when-changed dey reboot afta any update wey dem apply. when-needed dey reboot only wen the check wey dey inside needs-restarting -r tok say dem replace core package, na this one most pipo wey get single-server want, plus the timer window wey dem choose. The default reboot_command dey give users wey login five minutes warning thru shutdown, and you fit make the time long pass that one.
Settle two things before you turn this one on. Every service wey you depend on must start by e-sef wen the system boot, na this one dey usually be the wahala for Docker Compose stack wey you start by hand. And you need console or rescue access from your provider, because if kernel no gree boot, you no fit fix am thru SSH. If any of these two no dey, keep reboot = never and reboot by yourself afta you don read the journal.
Rocky, AlmaLinux and CentOS Stream: how dem differ
For Rocky 9 and AlmaLinux 9, everything wey we talk up there dey exactly the same, even the config path and the unit names. Both of dem dey publish errata, so upgrade_type = security get data wey you fit use filter. The old Rocky errata wey we talk about before na one of the few places wey dia day-to-day behaviour dey different, so if you never build the box, consider am join the compatibility promise and older-CPU support wey make the two different.
CentOS Stream na the exception, and e dey hard small. Stream repositories no get updateinfo.xml, so the security filter no fit ever match and every run go report No security updates needed. For Stream, use upgrade_type = default and accept say you go take every update. Stream self dey run ahead of RHEL, so that setting dey move pass for Stream box compared to the same setting for Rocky or AlmaLinux. That difference no be mistake of packaging, na the result of Red Hat 2020 decision to turn CentOS into rolling preview of RHEL, wey be the same decision wey make Rocky Linux and AlmaLinux show face.
Rocky 10 and AlmaLinux 10 move go DNF5, wey rename things. The upstream DNF5 documentation give the timer as dnf5-automatic.timer, put the defaults wey dem ship for /usr/share/dnf5/dnf5-plugins/automatic.conf while your overrides still dey for /etc/dnf/automatic.conf, set default download_updates to yes instead of no, and add distro-sync as upgrade_type. The advisory query na dnf advisory list, and dem keep updateinfo as alias. Confirm wetin your release actually install before you copy package or unit names from guide wey dem write for 9:
dnf list --available '*automatic*'
systemctl list-unit-files '*automatic*'Plenty guides wey dem publish for this topic still cover Rocky 8 only. The option set don grow since dem write those ones, so check the commented file for your own box instead of to trust old article.
Ways wey tin fit fail and di message wey you go see
Nothing dey run at all. systemctl list-timers dnf-automatic.timer go show empty table and systemctl is-enabled dnf-automatic.timer go show disabled. You install di package, but di timer no start.
Di job run but e no install anything. Di journal go show No security updates needed, but 3 updates available. Di security filter no match anything, either because nothing wey dey pending get advisory, or di repository no publish any advisory data.
One setting look like say dem ignore am. DNF go log unknown option for automatic.conf for debug level, den e go use di default. So if you spell word wrong, nothing go change and nobody go know. Write apply_update = yes and apply_updates go still dey no, so di box go download forever but e no go install. After you edit anything, run sudo systemctl start dnf-automatic.service and read di journal instead of you to just trust di file.
Di job dey run two times for one day. Two timers dey enabled. systemctl list-unit-files 'dnf-automatic*' go show you which one, and di extra ones dey pass flags wey dey override your config file.
No mail dey enter. Either nothing dey listen for port 25 for di email emitter, or send_error_messages still dey no and di only thing wey dem fit report na error.
One service wey you patch still dey show di old version. Di file for disk na new one, but di process wey dey memory na di old one. dnf needs-restarting -s go list di services wey you need restart.
FAQ
upgrade_type = security dey install only security updates for Rocky Linux?
Na only if you set upgrade_type = security for inside /etc/dnf/automatic.conf, and only if your repositories dey publish errata metadata. Rocky Linux and AlmaLinux both dey publish am, so the filter get advisories wey e fit match. The default wey dem ship na upgrade_type = default, wey dey install every update wey dey available once apply_updates = yes.
Why updateinfo.xml dey report "No security updates needed, but 3 updates available"?
DNF dey decide wetin be security update by reading updateinfo.xml from the repository, where each advisory dey list the packages wey fix the issue. When that metadata no dey or e don old, the security filter no go match anything even though normal updates still dey pending, and that one go produce that line. This one dey expected for CentOS Stream, because dem no dey publish errata at all. For Rocky or AlmaLinux, compare dnf updateinfo list --security with dnf check-update and check say your metadata dey current.
reboot go reboot my server after kernel update?
E no go reboot unless you tell am make e do am. The reboot option default na never. Set reboot = when-needed and the system go reboot only when the check wey dey behind dnf needs-restarting -r find say one core package like kernel or glibc don change since the last boot. reboot = when-changed go reboot after any update wey dem apply. Both of dem dey use reboot_command, wey default to shutdown -r +5 with one warning message for users wey login.
How I go change the time wey sudo systemctl edit dnf-automatic.timer dey run?
Run sudo systemctl edit dnf-automatic.timer and add one [Timer] section with an empty OnCalendar= line, then put your schedule, for example OnCalendar=*-*-* 03:30. The empty line dey important because OnCalendar dey accumulate, so if you leave am out, e go keep the 06:00 run wey dem ship and add another one. Verify with systemctl list-timers dnf-automatic.timer and check the NEXT column.
I still need to check server wey dey patch e-self?
Yes. emit_via dey install packages and e go stop there. E no dey restart daemons, and e no go report anything wey you go see unless emit_via point to one emitter wey you dey read. Set emit_via to stdio at least, turn on send_error_messages so failures go show, and run dnf needs-restarting -s after patch window to find services wey still dey run old code.