The backup scenario
You upgraded from Fedora 40 to 42 and the desktop environment refuses to start. Or you accidentally ran rm -rf on a directory you thought was empty. Or your external SSD clicked and died during a long compile. The terminal is open, the cursor is blinking, and you realize you never thought about recovery until you needed it. Backing up Fedora is not about copying files to a USB stick and hoping for the best. It is about separating your data, your configuration, and your package state so you can rebuild without guessing.
What actually breaks when you skip backups
A Linux system is a collection of independent layers. Your personal files live in /home. Your system configuration lives in /etc. Your installed software lives in /usr and /var, managed by the package manager. When a system fails, you rarely need to restore everything at once. You usually need to recover one layer while rebuilding the others. Think of it like a house. The foundation is the operating system. The furniture and wiring are the packages. The blueprints and custom modifications are the configuration files. Your personal belongings are the data. If the roof leaks, you do not rebuild the foundation. You patch the roof and move the furniture. Fedora backups work the same way. You isolate what matters, preserve it, and rebuild what the package manager can recreate.
Run journalctl -xe first. Read the actual error before guessing.
Backing up user data and configuration
The most reliable way to mirror /home and /etc is rsync. It tracks file changes, preserves permissions, and skips unchanged data on subsequent runs. The --link-dest flag creates hard links to the previous backup directory. This saves disk space and makes incremental backups nearly instant. Unchanged files point to the same disk blocks. Only new or modified files consume additional storage. Hard links share the same inode. The filesystem counts references. When the last reference is deleted, the blocks are freed. This mechanism gives you point-in-time snapshots without duplicating gigabytes of identical data.
Here is how to set up a daily incremental backup script that targets your external drive.
#!/bin/bash
BACKUP_DEST="/mnt/backup-drive/fedora-backup"
DATE=$(date +%F)
# Create the target directory structure for today's snapshot
mkdir -p "$BACKUP_DEST/$DATE/home" "$BACKUP_DEST/$DATE/etc"
# Find the most recent previous backup to use as a hard link source
PREV_BACKUP=$(ls -t "$BACKUP_DEST" | head -n 1)
# Mirror home directories, preserving ownership and skipping broken symlinks
rsync -av --link-dest="$BACKUP_DEST/$PREV_BACKUP/home" /home/ "$BACKUP_DEST/$DATE/home/"
# Mirror system configuration, excluding volatile runtime files
rsync -av --link-dest="$BACKUP_DEST/$PREV_BACKUP/etc" --exclude='shadow' --exclude='gshadow' /etc/ "$BACKUP_DEST/$DATE/etc/"
The --exclude flags prevent copying password hashes that change frequently and serve no purpose in a cold backup. Config files in /etc/ are user-modified. Files in /usr/lib/ ship with the package. Edit /etc/. Never edit /usr/lib/. Your backup script should follow that same boundary. Manual file edits drift. Snapshots stay.
Capturing your software environment
Restoring files is useless if you cannot recreate the exact software stack. Fedora's package manager tracks every installation, update, and removal. You can export this history and your repository configuration to rebuild the environment later. This matters when a library update breaks a build tool or when you need to roll back to a specific version of a dependency. The dnf transaction log lives in /var/log/dnf.log, but exporting the current state gives you a clean, parseable list for automation.
Here is how to export your package list, repository definitions, and custom SELinux booleans.
# Export every installed package with its exact version and release tag
dnf list installed --all > /tmp/packages-full.txt
# Copy repository definitions so you can restore third-party sources like RPM Fusion
cp -r /etc/yum.repos.d/ /mnt/backup-drive/fedora-backup/repos-backup/
# Export custom SELinux booleans if you modified access controls
semanage boolean -l --modified > /mnt/backup-drive/fedora-backup/selinux-booleans.txt
The --modified flag in semanage only outputs booleans you actually changed. Default booleans are managed by the policy package and will be overwritten on the next dnf upgrade --refresh. Fedora's release cadence is six months. The N-2 release goes end-of-life when N+1 ships. Plan your package exports around that cycle so you do not try to restore a repository configuration against an archived mirror. Trust the package manager. Manual file edits drift, snapshots stay.
Full disk imaging for bare metal recovery
Incremental backups cover data and configuration. They do not cover partition tables, bootloader stages, or filesystem metadata. If your disk controller fails or your partition layout gets corrupted, you need a sector-by-sector image. dd is the standard tool for this. It reads raw blocks and writes them to a file or another block device. It does not care about filesystems. It copies everything, including empty space and deleted data. This makes it perfect for disaster recovery but terrible for daily use due to storage overhead.
Here is how to image your root partition to an external drive.
# Identify your root partition first to avoid overwriting the wrong disk
lsblk -f
# Stream the root partition to an image file with progress tracking
sudo dd if=/dev/sda2 of=/mnt/backup-drive/fedora-root.img bs=4M status=progress
# Verify the image integrity immediately after creation
sudo md5sum /dev/sda2 /mnt/backup-drive/fedora-root.img
The bs=4M flag sets the block size to four megabytes. Larger block sizes reduce CPU overhead and speed up the transfer on modern drives. Always verify the checksum right after the copy finishes. A silent disk error during the transfer will corrupt the image and waste hours during recovery. If your system uses LUKS encryption, dd will only copy the encrypted container. Keep your passphrase in a secure password manager. Without it, the image is just random noise. Snapshot the system before the upgrade. Future-you will thank you.
Automating with systemd timers
Manual backups fail when you forget to run them. systemd timers replace cron for modern Fedora systems. They integrate with the journal, support calendar-based scheduling, and survive reboots without extra configuration. You pair a service unit with a timer unit. The timer triggers the service at the specified interval. The journal captures every execution, making debugging straightforward.
Here is how to create a weekly backup timer that runs your script.
# /etc/systemd/system/fedora-backup.service
[Unit]
Description=Weekly Fedora System Backup
After=local-fs.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/fedora-backup.sh
# Run as root to access /etc and /home without permission errors
User=root
# /etc/systemd/system/fedora-backup.timer
[Unit]
Description=Trigger weekly backup service
[Timer]
OnCalendar=weekly
Persistent=true
# Catch up on missed runs if the system was powered off during the scheduled time
RandomizedDelaySec=300
[Install]
WantedBy=timers.target
Enable the timer with sudo systemctl enable --now fedora-backup.timer. The Persistent=true flag ensures the service runs immediately after boot if it missed its scheduled window. systemctl status fedora-backup.timer shows recent log lines AND state in one view. Always check status before restart.
Verifying your backups
A backup is not a backup until you have restored from it. Test your recovery procedure on a non-critical directory or a virtual machine. Copy a single file from the rsync snapshot back to a temporary folder. Compare the checksums. Mount the dd image in a loop device and verify the partition table. If the restore fails, your backup strategy fails. Fix the script before the real emergency arrives.
Here is how to test a loop mount of your disk image.
# Create a temporary mount point for verification
sudo mkdir -p /mnt/test-restore
# Mount the image read-only to prevent accidental writes
sudo mount -o loop,ro /mnt/backup-drive/fedora-root.img /mnt/test-restore
# List the root directory to confirm filesystem structure
ls -la /mnt/test-restore
# Unmount when finished
sudo umount /mnt/test-restore
Reboot before you debug. Half the time the symptom is gone. Test restores expose permission mismatches, missing dependencies, and broken symlinks that only appear when the filesystem is actually mounted.
Common pitfalls and error patterns
The rsync command will refuse to proceed and print rsync: link_dest "/path/to/backup" is not a directory when the previous backup directory is missing or the path contains a typo. The script relies on ls -t to find the latest snapshot. If the backup drive is empty, the command fails. Add a guard clause that checks for an existing snapshot before running the incremental copy.
If you see dd: error writing '/mnt/backup-drive/fedora-root.img': No space left on device, your external drive is full or the filesystem has reached its inode limit. Check available space with df -h and df -i before starting a raw image. Raw images consume the exact size of the partition, not the size of the used data. Use partclone or btrfs send/receive if you need space-efficient backups of sparse partitions.
SELinux denials show up in journalctl -t setroubleshoot with a one-line summary. Read those before disabling SELinux. A backup script running as root will trigger denials if it tries to write to a directory with the wrong context. Fix the context with restorecon -Rv /mnt/backup-drive instead of switching to permissive mode. firewall-cmd --reload after every rule change. Otherwise the runtime config and the persistent config diverge.
Choosing your backup strategy
Use rsync with --link-dest when you need fast incremental backups of user data and configuration files. Use dnf list installed and repository exports when you want to recreate your exact software stack on a fresh install. Use dd or partclone when you require bare-metal recovery and cannot tolerate partition table or bootloader corruption. Use systemd timers when you want automated, journal-integrated scheduling that survives reboots. Stay on manual execution if you only perform backups during major upgrades and want full control over each run.