Configuring Automatic Security Updates on CentOS Stream 9 with dnf-automatic: Auto-Patch Vulnerabilities and Get Email Notifications

CentOS tutorial - IT technology blog
CentOS tutorial - IT technology blog

Neglecting Security Patches — A Risk Not Worth Taking

There’s a common reality in small DevOps teams: the server runs smoothly for months, then everyone forgets about security patch updates. When an incident occurs, looking back at the logs reveals a vulnerability that was publicly disclosed three months ago with a patch already available.

I’ve encountered this situation myself. My company still has a few servers running CentOS 7, and migrating to AlmaLinux is something I’ve already handled — but while waiting for the migration, I needed an automated security patching mechanism without having to SSH into each machine every week. After trying a few approaches, dnf-automatic is my most trusted choice for RHEL-based servers, especially CentOS Stream 9.

In this article, I’ll walk through the complete setup: installation, configuring it to apply only security updates, and enabling email notifications so you know what gets patched each day.

What is dnf-automatic and Why Use It?

dnf-automatic is the official tool from the DNF ecosystem, designed to automate package updates. Unlike running dnf update manually, it integrates directly with systemd timers — no need for custom cron jobs or complex wrapper scripts.

Advantages over other solutions:

  • Granular control: choose to only download, only apply security updates, or update everything
  • Built-in email notifications: no need to pipe output externally
  • Systemd timer: runs on schedule, with logging and retry if the system is offline
  • Random delay: prevents multiple servers from hitting the mirror repo simultaneously

I typically run it in apply security updates only mode — the safest option for production environments, avoiding the risk of a package update breaking the application.

Hands-On: Step-by-Step Installation and Configuration

Step 1: Install dnf-automatic

This package is available in the default CentOS Stream 9 repository, install it directly:

sudo dnf install -y dnf-automatic

Check the version and default configuration file:

dnf-automatic --version
cat /etc/dnf/automatic.conf

Step 2: Configure automatic.conf

The main configuration file is located at /etc/dnf/automatic.conf. Let’s walk through each important section:

sudo cp /etc/dnf/automatic.conf /etc/dnf/automatic.conf.bak
sudo nano /etc/dnf/automatic.conf

Settings to adjust in the [commands] section:

[commands]
# Download security updates only, don't apply immediately
# Use this for environments that require review first
# upgrade_type = security
# download_updates = yes
# apply_updates = no

# --- Or: Apply security updates automatically (recommended for production) ---
upgrade_type = security
download_updates = yes
apply_updates = yes

# Random delay up to 60 minutes — prevents all servers from updating at the same time
random_sleep = 3600

The [emitters] section — configure how notifications are sent:

[emitters]
# Send notifications via email (requires SMTP or local MTA)
emit_via = email

# Only send email when there are updates (avoids daily spam)
# available: always, never, only-if-updated
email_to = [email protected]
email_from = [email protected]
email_host = localhost
# If using a different port (e.g., Gmail SMTP):
# email_host = smtp.gmail.com
# email_port = 587

The [base] section — general settings:

[base]
debuglevel = 1
# Log path
# /var/log/dnf.log automatically captures dnf output

Step 3: Enable the systemd Timer

dnf-automatic comes with 3 different timers; choose the one that fits your needs:

# List available timers
ls /usr/lib/systemd/system/dnf-automatic*.timer

# dnf-automatic.timer          — apply updates (use this one)
# dnf-automatic-download.timer — download only, don't apply
# dnf-automatic-install.timer  — alias for the first one

Enable the timer for applying security updates:

# Enable and start the timer
sudo systemctl enable --now dnf-automatic.timer

# Check status
systemctl status dnf-automatic.timer
systemctl list-timers dnf-automatic*

Sample output when the timer is running correctly:

NEXT                         LEFT     LAST                         PASSED  UNIT
Wed 2026-07-02 06:42:15 JST  18h left Tue 2026-07-01 06:12:03 JST  5h ago  dnf-automatic.timer

Step 4: Configure Email Notifications via Postfix (Local MTA)

If the server doesn’t have an MTA, install Postfix to send emails via a relay:

sudo dnf install -y postfix mailx
sudo systemctl enable --now postfix

Quick email test:

echo "Test from CentOS Stream 9" | mail -s "dnf-automatic test" [email protected]

If the server needs to relay through Gmail or an external SMTP server, add the relay configuration to /etc/postfix/main.cf:

# Add to the end of /etc/postfix/main.cf
relayhost = [smtp.gmail.com]:587
smtp_use_tls = yes
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_security_options = noanonymous
smtp_tls_CAfile = /etc/ssl/certs/ca-bundle.crt
# Create credentials file
echo "[smtp.gmail.com]:587 [email protected]:app-password" | sudo tee /etc/postfix/sasl_passwd
sudo postmap /etc/postfix/sasl_passwd
sudo chmod 600 /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db
sudo systemctl restart postfix

Note: Gmail requires an App Password (not your main password). Go to Google Account → Security → App passwords to create one.

Step 5: Manual Test Before Enabling Automation

Always run a manual test once to confirm the configuration is correct:

# Run dnf-automatic immediately, without waiting for the timer
sudo dnf-automatic /etc/dnf/automatic.conf

# View detailed logs
sudo journalctl -u dnf-automatic -f

# Or trigger the timer immediately
sudo systemctl start dnf-automatic

Check the log to see if any updates were applied:

sudo cat /var/log/dnf.log | grep -E "(Upgraded|Installed|security)"

# View update history
sudo dnf history list | head -20

Step 6: Adjust the Schedule (Optional)

By default, the timer runs at 6 AM with a random delay. To change the time, override the timer:

sudo systemctl edit dnf-automatic.timer

Add the override content (for example, to run at 3 AM):

[Timer]
OnCalendar=
OnCalendar=*-*-* 03:00:00
RandomizedDelaySec=1800
sudo systemctl daemon-reload
sudo systemctl restart dnf-automatic.timer

Practical Tips from Real-World Experience

  • Kernel updates: Security updates sometimes include the kernel. If you don’t want an auto-reboot, consider using kernel-livepatch or excluding the kernel: add exclude=kernel* to the [base] section of automatic.conf and handle kernel updates manually during a maintenance window.
  • Stage first: For critical production systems, use download_updates = yes, apply_updates = no mode — updates will be pre-downloaded, and you just need to run dnf update --cacheonly during the maintenance window.
  • Monitoring: Beyond email, you can add alerts via Slack/Telegram by creating a systemd service wrapper that sends a webhook after dnf-automatic completes.
  • Multiple servers: For large fleets, I recommend combining with Ansible to push automatic.conf configurations uniformly, rather than SSH-ing into each machine.

Conclusion

Setting up dnf-automatic takes about 15 minutes but saves a significant amount of effort down the line. The most important thing is choosing the right upgrade_type = security — patching only security vulnerabilities without touching feature updates that could cause breaking changes.

Once enabled, I typically leave it alone for a few weeks before checking the logs again — email notifications will alert you if anything happens. This is the most practical approach for production servers where the team doesn’t have time for regular manual patching.

Share: