The update gap
You set up a Fedora workstation or a headless server. You run sudo dnf upgrade --refresh on a Tuesday. By Friday, a critical CVE drops in a core library. You are traveling, the machine is locked, and the patch window closes. Manual updates rely on routine. Routine breaks when you are busy, sick, or away. Leaving a system unpatched for days is an open invitation for automated scanners. Fedora provides a built-in solution that runs in the background, respects your package manager rules, and leaves a clear audit trail.
How the automatic update system actually works
The dnf-automatic package does not run a permanent daemon. It uses a systemd timer to wake up a service at a set interval. The timer checks the repository metadata. If new packages match your rules, the service downloads them and applies the transaction. Everything runs under the same dnf engine you use manually. The difference is the trigger and the configuration file.
Systemd timers are reliable because they survive reboots and handle missed runs gracefully. If the machine sleeps or loses power during the scheduled window, the timer catches up on the next boot. The service writes its output to the systemd journal. You can inspect every transaction, every skipped package, and every dependency resolution step. The configuration lives in /etc/dnf/automatic.conf. That path follows the standard Linux convention. User modifications go in /etc/. Package defaults ship in /usr/lib/. Never edit the /usr/lib/ copy. Your changes will vanish on the next package update.
Most administrators type journalctl -xe muscle-memory style when debugging services. The x flag adds explanatory text and the e flag jumps to the end. You will use that pattern heavily when reviewing automatic update logs. The timer itself does not install packages. It only triggers the dnf-automatic-install.service unit. That separation keeps the scheduling logic independent from the package manager state. Trust the package manager. Manual file edits drift, snapshots stay.
Install and activate the timer
Here is how to install the package and start the scheduling mechanism. The command enables the timer and starts it immediately.
sudo dnf install -y dnf-automatic
# Install the automatic update package and its systemd units
sudo systemctl enable --now dnf-automatic-install.timer
# Enable the timer to survive reboots and start it right now
The --now flag combines enable and start. Systemd registers the timer in the default target. The timer defaults to running once a day. You can verify the schedule and the next trigger time.
systemctl status dnf-automatic-install.timer
# Show the current state, last trigger, and next scheduled run
systemctl list-timers dnf-automatic*
# List all automatic update timers and their intervals
Check the NEXT column in the output. If it says n/a, the timer is inactive or masked. Run the enable command again. Reboot before you debug. Half the time the symptom is gone.
Configure the update policy
The default configuration downloads and installs all updates. Most administrators prefer a security-only policy. Open the configuration file and adjust the [commands] section.
sudo nano /etc/dnf/automatic.conf
# Open the configuration file in your preferred terminal editor
Here is the configuration structure for a security-only policy. The file uses standard INI syntax. Comments start with #. Blank lines are ignored.
[commands]
# upgrade_type controls which packages the timer considers
# security applies only packages marked with security advisories
# default applies every available package update
upgrade_type = security
# apply_updates determines whether the service installs packages
# yes installs them automatically after download
# no only downloads them to the cache for manual review
apply_updates = yes
# emit_via controls where the service writes its status reports
# stdio sends output to the systemd journal for local inspection
# email sends a formatted report to the local mail queue
emit_via = stdio
# download_only is a legacy fallback. Keep it disabled.
download_only = no
Save the file and restart the timer. Systemd reads the configuration at startup. Restarting forces an immediate reload without waiting for the next scheduled run.
sudo systemctl restart dnf-automatic-install.timer
# Reload the timer so it picks up the new configuration immediately
If you want email notifications, change emit_via to email and configure a local MTA like postfix or msmtp. The service expects a working mail command in $PATH. If the mail command fails, the service logs a warning but continues. dnf upgrade --refresh is the normal weekly maintenance command for manual checks. dnf-automatic handles the background work. They are different commands. Do not conflate them.
Test the configuration without waiting
You do not need to wait for the daily trigger to verify your setup. Run the service manually in dry-run mode. This simulates the update process and prints the exact transaction it would execute.
sudo dnf-automatic --no-apply
# Run the update logic without installing anything
# Prints the package list and dependency resolution steps
Review the output carefully. Look for skipped packages, held dependencies, or repository errors. If the dry run looks correct, force an immediate update cycle.
sudo dnf-automatic
# Execute the full update cycle right now
# Downloads and installs packages matching your upgrade_type rule
The command blocks until the transaction finishes. It uses the same RPM transaction journal as manual dnf commands. You can cancel it with Ctrl+C, but let it finish to avoid a broken package state. A botched upgrade can leave you unable to boot. Run this from a backup VM first if you can.
Verify the updates applied
Automatic updates leave a clear trail in the systemd journal. Query the service unit directly to see what happened during the last run.
journalctl -u dnf-automatic-install.service --no-pager
# Show the full log for the automatic update service
# The --no-pager flag dumps everything to the terminal
Look for lines containing Downloading, Installing, and Complete. If you see Nothing to do, the repositories are up to date or your upgrade_type filter excluded all available packages. You can also check the package manager history to confirm the transaction.
dnf history list
# Display the last 20 dnf transactions
dnf history info <transaction-id>
# Show details for a specific automatic update run
Run journalctl first. Read the actual error before guessing.
Common pitfalls and error patterns
Automatic updates fail silently when the configuration conflicts with manual operations. The most common issue is running sudo dnf upgrade while the timer is active. dnf uses a lock file at /run/dnf.pid. If two instances run simultaneously, one aborts with a lock error. The timer will retry on the next scheduled run. Do not force the lock. Wait for the timer to finish or stop it manually.
Another frequent problem is the email notification path. If emit_via = email is set but no MTA is running, the service logs Failed to send notification email. The updates still apply. The email failure does not block the transaction. Check your mail queue with mailq or postqueue -p if messages pile up.
Desktop users sometimes install the install timer by mistake. The dnf-automatic-install.timer runs headless. It does not pause for user input. If a kernel update requires a reboot, the system will not prompt you. It will just wait. On a desktop, you want a notification instead of a silent background install. SELinux denials show up in journalctl -t setroubleshoot with a one-line summary. Read those before disabling SELinux. Automatic updates respect SELinux contexts. They do not bypass them.
Choose the right timer for your workload
Use dnf-automatic-install.timer when you are managing a server, a CI runner, or any machine that stays on and does not need user interaction during updates. Use dnf-automatic-notifyonly.timer when you are running a desktop environment and prefer a GNOME or KDE notification that asks for permission before installing. Use manual sudo dnf upgrade --refresh when you need to test updates in a staging environment first or when you manage a fleet with configuration management tools like Ansible. Stay on the upstream Workstation defaults if you only deviate from the package manager occasionally.