Story / scenario opener
You install Fedora Silverblue or Kinoite and expect updates to happen quietly in the background. Instead, the system sits at a purple screen asking you to reboot, or you notice the update service is disabled by default. You want the machine to patch itself without constant terminal sessions, but you also want to avoid a reboot interrupting a video call or a long compile job.
What is actually happening
Atomic desktops do not modify the running filesystem in place. Traditional dnf upgrade patches files directly, which leaves the system in a partially updated state until a reboot. rpm-ostree works differently. It downloads an entirely new, verified boot tree, mounts it as a read-only layer, and marks it as the next default boot target. The running system stays exactly as it was until you restart. This transactional model guarantees a consistent state, but it shifts the update workflow. You cannot just apply patches and keep working. You must reboot to switch to the new tree.
The rpm-ostreed-automatic service bridges that gap. It polls the configured repositories on a schedule, downloads the new tree in the background, and triggers a reboot only when the system meets safety conditions. By default, it waits for the machine to be idle, for all users to log out, or for a configured time window to pass. This prevents the service from kicking you out of a running session. Think of it like a library book reservation system. The new version is checked out and placed on your desk, but you keep reading the old copy until you decide to swap them. The daemon handles the reservation and the swap timing.
How to enable and configure automatic updates
The service ships with Fedora Atomic but starts disabled. You need to enable it and adjust the reboot policy to match your workflow.
First, enable the background daemon. This command starts the service immediately and ensures it survives reboots.
sudo systemctl enable --now rpm-ostreed-automatic.service
# Enables the background update poller and starts it in the current session
# The --now flag avoids a separate start command
# systemd will now run the daemon at boot without further intervention
The default configuration applies a conservative reboot policy. The service will not reboot while a user is logged in or while the system is actively processing tasks. You can adjust this behavior by editing the main configuration file. Configuration files in /etc/ are user-modified. Files in /usr/lib/ ship with the package. Edit /etc/. Never edit /usr/lib/.
Open the configuration file with your preferred editor.
sudo nano /etc/rpm-ostreed.conf
# Opens the main rpm-ostree daemon configuration
# Changes here override the upstream defaults without breaking package updates
# The file uses standard INI syntax with sections and key-value pairs
Locate the [AutomaticUpdates] section. You will see two keys that control reboot behavior.
[AutomaticUpdates]
AutomaticReboot=true
# Allows the daemon to trigger a reboot after a successful update
# Set to false if you prefer to reboot manually after seeing the pending screen
AutomaticRebootTime=any
# Controls when the reboot is allowed. 'any' means idle or logged out
# Change to 'never' to disable automatic reboots entirely
# Change to a specific time like '03:00' to restrict reboots to a maintenance window
Save the file and restart the daemon to apply the new policy.
sudo systemctl restart rpm-ostreed-automatic.service
# Reloads the configuration file into the running daemon
# The next polling cycle will respect the new reboot window
# No manual intervention is required to pick up the change
The daemon polls for updates every twelve hours by default. You can change the interval by adding AutomaticUpdateInterval=3600 to the same section. The value is in seconds. A shorter interval means more frequent network checks and slightly higher CPU usage during the polling window. Trust the package manager. Manual file edits drift, snapshots stay.
Verify it worked
Check the service state and recent activity. The systemctl status command shows the active state, the main PID, and the last few journal lines in one view. Always check status before restarting.
systemctl status rpm-ostreed-automatic.service
# Confirms the service is active and running
# Shows the last few log lines to verify configuration loaded correctly
# Look for 'Active: active (running)' and no red error markers
You can also force a dry run to see if updates are available without triggering a download.
rpm-ostree upgrade --check
# Queries the repositories for available updates without downloading
# Returns a list of pending packages if an update exists
# Exits with code 0 if the system is already up to date
Watch the background polling in real time by reading the journal. The x flag adds explanatory context to log lines and the e flag jumps to the end. Most sysadmins type journalctl -xeu rpm-ostreed-automatic muscle-memory style when debugging background services.
-- Boot 8f2a1c9d4e5b6f7a8c9d0e1f2a3b4c5d --
Oct 12 09:14:22 fedora rpm-ostreed[1234]: Downloading updates...
Oct 12 09:14:25 fedora rpm-ostreed[1234]: Staging deployment...
Oct 12 09:14:28 fedora rpm-ostreed[1234]: Successfully staged new deployment
Oct 12 09:14:28 fedora rpm-ostreed[1234]: Waiting for safe reboot window...
# ...output truncated for clarity
Run rpm-ostree status to see which boot tree is currently active and which one is marked as default. The output lists deployments in reverse chronological order. The top entry is the running system. The second entry is the pending update. Verify the commit hashes match the repository metadata before rebooting. Run journalctl first. Read the actual error before guessing.
Common pitfalls and what the error looks like
The pending reboot screen is the most common friction point. When an update downloads successfully, the system marks the new tree as default. The next boot will load the new tree, but the current session remains on the old tree. You will see a purple screen with a reboot prompt. This is not a crash. It is a safety feature. The system refuses to mix old and new binaries in the same session. Reboot before you debug. Half the time the symptom is gone.
Network interruptions during the download phase will leave the service in a retry state. You will see Failed to download payload or Connection timed out in the journal. The daemon automatically retries on the next polling cycle. You do not need to manually restart it. If the error persists, check your network manager status. nmcli dev status will show whether the interface is connected and whether DHCP completed.
Manual upgrades can interfere with the automatic daemon. If you run rpm-ostree upgrade in a terminal while the daemon is polling, you will see Error: another transaction is in progress. The rpm-ostree lock prevents concurrent modifications to the boot tree. Wait for the manual command to finish, or stop the daemon temporarily with sudo systemctl stop rpm-ostreed-automatic.service. Layered packages installed via rpm-ostree install will automatically replay across updates, but local configuration changes in /etc/ may be reset if the package maintainer ships a new default. Check /etc/ drift with rpm-ostree admin diff before applying major updates.
SELinux denials rarely block the update daemon, but they can appear if you modify the boot tree manually. Check journalctl -t setroubleshoot for a one-line summary of any denial. Read those before disabling SELinux. The daemon runs under a confined policy that allows repository access and tree deployment. Deviating from the standard workflow usually triggers the alert. If the boot menu is gone, GRUB rescue is your friend, not your enemy.
When to use automatic updates vs alternatives
Use rpm-ostreed-automatic when you want a set-and-forget workflow that respects system idle time and user sessions. Use rpm-ostree upgrade when you need to apply updates immediately and are ready to reboot on your own schedule. Use rpm-ostree replay when you have layered packages or local modifications that need to be preserved across the new boot tree. Stay on the upstream automatic daemon if you only deviate from the defaults occasionally.