You backed up your home directory for months using a simple script. The script ran fine until the night your drive filled up. You check the backup folder and see five copies of your 400GB project directory, each slightly different. Your external drive is full, and you realize your backup strategy is eating your storage faster than your data is growing. You need a tool that stores only the changes, not the whole world every time.
What's actually happening
BorgBackup treats your data like a git repository for files. It breaks every file into variable-sized chunks based on content, not position. It calculates a hash for each chunk. If the chunk already exists in the repository, Borg skips it. If you change one byte in a 10GB video file, Borg stores only that changed chunk and links to the rest. The result is a repository that grows slowly, even as you back up the same data repeatedly.
Variable chunking prevents desynchronization. If you insert a paragraph at the top of a document, fixed-size chunking would shift every chunk boundary and force the tool to store the entire file again. Borg uses a content-defined chunking algorithm. The chunk boundaries depend on the data inside the file. Changes only affect the chunks that contain the modification. The rest of the file remains identical and gets deduplicated.
Borg also encrypts everything by default. The repository is useless without your passphrase. This protects your data if the backup drive is stolen. You choose the encryption mode during initialization. The mode determines where the encryption key lives. Borg supports repository-key mode, key-file mode, and passphrase-only mode. Each mode has trade-offs for convenience and security.
Borg does not delete old archives automatically. You must run a prune command to enforce a retention policy. Without pruning, your repository will grow forever as you create new archives. A typical policy keeps daily backups for a week, weekly backups for a month, and monthly backups for a year. Borg matches archives by name prefix and applies the policy to remove old snapshots.
Install and initialize the repository
Install Borg via DNF. Fedora keeps the package updated. Run sudo dnf install -y borgbackup. Create a directory for the repository. If you are using an external drive, mount it first. Initialize the repository. Choose repokey if the backup stays on your machine. Choose keyfile if you plan to move the repository to another computer often. The keyfile mode stores the encryption key separately, so you must carry the key file with the repository.
Here's how to initialize a repository with repository-key encryption, which stores the key inside the repo for local backups.
sudo dnf install -y borgbackup # Install the latest stable Borg from Fedora repos
mkdir -p /mnt/backup/repo # Create a mount point for your external drive or backup directory
borg init --encryption=repokey /mnt/backup/repo # Initialize repo; repokey stores key in repo, good for local drives
Choose the encryption mode before you initialize. You cannot change it later without re-encrypting everything.
Create your first backup
Create archives with timestamps. Exclude cache and temporary directories to save space. Borg includes everything you point it at unless you tell it otherwise. Backing up virtual filesystems like /proc or /sys causes errors and wastes time. Exclude cache directories to avoid storing transient data.
Here's how to create a backup of your home directory while excluding cache and virtual filesystems.
borg create --stats --progress \
/mnt/backup/repo::backup-$(date +%F) \
/home \
--exclude /home/*/.cache \
--exclude /home/*/.local/share/Trash \
--exclude /proc \
--exclude /sys \
--exclude /dev # Create archive, show stats, exclude cache and virtual filesystems
Exclude cache directories. Backing up .cache wastes space and time.
Verify the backup
Verify the backup. Check the list of archives. Inspect the stats to confirm deduplication is working. The stored size should be significantly smaller than the original size if you have backed up before. Borg reports the original size, the deduplicated size, and the compressed size. The deduplicated size shows how much data is actually new. The compressed size shows the final footprint on disk.
Here's how to list archives and check the stats for the latest backup.
borg list /mnt/backup/repo # List archives to confirm creation
borg info /mnt/backup/repo::backup-$(date +%F) # Show stats for the latest archive
Check the stats. If the stored size equals the original size, deduplication isn't working or you backed up new data.
Restore files when disaster strikes
Restore files when disaster strikes. You can extract single files or entire directories. Always test restoration on a separate location first. Borg extracts files to the current directory by default. Use --stdout to pipe a single file to a new location. This avoids overwriting files in place.
Here's how to extract a single file and a directory from an archive.
borg extract /mnt/backup/repo::backup-2024-05-20 --stdout /home/user/documents/important.pdf > /tmp/recovered.pdf # Extract single file to stdout
borg extract /mnt/backup/repo::backup-2024-05-20 /home/user/documents/ # Extract directory to current location
Test your restores. A backup you cannot restore is just a data hoard.
Enforce retention with pruning
Borg does not delete old archives automatically. You must run borg prune to enforce retention policy. Add --keep-daily=7 --keep-weekly=4 --keep-monthly=6 to keep a rolling window of backups. Borg matches archives by name prefix. Use --prefix to target specific backup sets. Pruning removes old archives and runs garbage collection to reclaim space from deleted chunks.
Here's how to prune old archives and keep a rolling retention window.
borg prune --keep-daily=7 --keep-weekly=4 --keep-monthly=6 --prefix backup- /mnt/backup/repo # Prune old archives, keep daily/weekly/monthly, match prefix
Run prune after create. Or combine them in a script. A repository without a retention policy is just a data hoard.
Common pitfalls and errors
Borg locks the repository during operations. If you run two backups at once, the second one fails with LockTimeoutError: Timeout waiting for lock. Wait for the first backup to finish. Borg also checks the repository version. If you upgrade Borg to a new major version, older repositories might need an upgrade. Run borg upgrade if you see a version mismatch error. Never edit files inside the repository manually. Borg tracks metadata. Manual edits corrupt the repository.
You may see Permission denied errors when backing up system directories. Borg tries to read every file. Some files are restricted by permissions or SELinux. Exclude restricted directories or run the backup as root. Running as root is safer for system backups but requires careful permission handling. Borg preserves ownership and permissions. Restoring as root restores files with the original owner.
If you see Repository does not exist after moving the repository, check the path. Borg stores the repository ID in the cache. If you move the repository to a new location, update the cache or run borg update-repository to refresh the ID mapping.
Borg caches repository metadata locally in ~/.cache/borg/. This speeds up operations. If the cache becomes corrupted, Borg will warn you. Run borg check --repair to fix repository errors. Run borg cache sync to refresh the cache.
Convention asides
Fedora's release cadence is 6 months. Borg updates frequently. Run sudo dnf upgrade --refresh weekly to keep Borg patched. dnf upgrade --refresh is the normal weekly maintenance command. dnf system-upgrade is for crossing major Fedora releases. They are different commands. Don't conflate them.
Borg stores configuration in ~/.config/borg/. This is the user-modified directory. Files in /usr/lib/ ship with the package. Edit ~/.config/borg/. Never edit /usr/lib/.
If you automate backups with systemd timers, check journalctl -xeu borgbackup.timer if the timer fails. The x flag adds explanatory text and the e flag jumps to the end. Most sysadmins type journalctl -xeu <unit> muscle-memory style.
Decision matrix
Use Borg when you need deduplication to save space and encryption for security. Use Rsync when you need a simple mirror of files and don't care about versioning or encryption. Use Timeshift when you want system snapshots for Fedora rollback and don't need to back up user files. Use Restic when you need cloud storage support and a language-agnostic client. Stay with Borg if you are comfortable with the command line and want a battle-tested local backup solution.