How We Evaluated These Tools
Our test environment used two servers: a 32-core AMD EPYC with 128GB RAM running Ubuntu 24.04 as the backup client, and a Rocky Linux 9.3 server with 20TB of ZFS storage as the backup target. We ran each tool against a 500GB dataset containing PostgreSQL data directories, application logs, and mixed media files. We measured:
- Initial backup time - Incremental backup time after a 5% change - Deduplication ratio on the incremental run - Time to restore a single 2GB file - Time to restore the full 500GB dataset - Memory footprint during backup
All tools were run as root with network transfers going over a 10Gbps LAN. We used `iperf3` to confirm the link was not the bottleneck before any test. Encryption was enabled where the tool supports it, using AES-256.
iperf3 -s &
iperf3 -c backup-server -t 30 -P 4
rsync - Still the Baseline for Everything Else
rsync 3.3.0 ships with most current distributions and remains the transfer primitive that many other tools build on. On its own it is not a backup system - it is a sync tool. Without `--backup` and `--backup-dir`, running rsync against a target that already has data will overwrite deletions on the source. That said, rsync with hardlinks gives you cheap snapshot-style backups without a custom binary.
In our test, the initial 500GB transfer completed in 47 minutes at 178 MB/s average throughput. The incremental run after a 5% change took 4 minutes 20 seconds. Restore of the full dataset from an rsync hardlink snapshot was the fastest of any tool we tested at 41 minutes.
The critical limitation: rsync has no native deduplication across backup sets, no encryption, and no integrity manifest. If your backup disk silently corrupts a chunk, you will not know until you try to restore. Use rsync when you control both ends and have something else handling integrity checks - for example, ZFS on the backup target with `zpool scrub` scheduled weekly.
rsync -aAX --delete --backup \
--backup-dir=/backups/$(date +%F) \
--link-dest=/backups/latest \
/data/ backup-server:/backups/current/
# Rotate: update the 'latest' symlink
ssh backup-server "ln -snf /backups/current /backups/latest"
Restic - The Strongest Default Choice in 2026
Restic 0.17.x brought significant performance improvements to the chunker and pack writer. In our 500GB test, the initial backup to a local repository completed in 53 minutes. The 5% incremental run took 6 minutes with a deduplication ratio of 18:1 on the changed chunks. Restore of the full dataset took 49 minutes. Single-file restore was 8 seconds.
Restic encrypts everything by default using AES-256-CTR with Poly1305-AES authentication. The repository format is self-describing, which means you can restore from any restic binary at the same major version without external metadata. This matters operationally: you are not dependent on a running daemon or a database to do a restore.
Restic supports S3, B2, Azure, GCS, SFTP, REST, and local backends natively. For production use, we recommend pairing it with `restic forget` and `restic prune` on a schedule to keep repository growth under control. The `--keep-daily`, `--keep-weekly`, and `--keep-monthly` flags give you a retention policy in a single command.
One caveat: restic holds the entire repository index in memory during operations. On our 500GB repository after 60 days of daily backups, the process used 4.2GB of RAM during a prune operation. Plan accordingly on memory-constrained hosts.
# Initialize a repository
restic -r sftp:backup-server:/restic/myapp init
# Run a backup with exclusions
restic -r sftp:backup-server:/restic/myapp backup \
--exclude-caches \
--exclude '/data/tmp' \
/data
# Apply retention policy and prune
restic -r sftp:backup-server:/restic/myapp forget \
--keep-daily 7 \
--keep-weekly 4 \
--keep-monthly 6 \
--prune
# Verify integrity
restic -r sftp:backup-server:/restic/myapp check --read-data-subset=10%
BorgBackup - Best Deduplication, Higher Operational Complexity
BorgBackup 2.0 introduced a rewrite of the chunker and better parallelism. On our test dataset, Borg achieved a 24:1 deduplication ratio on the incremental run - the best of any tool we tested. Initial backup time was 61 minutes, incremental was 5 minutes 10 seconds.
The key differentiator is Borg's chunk-level deduplication across the entire repository history, not just within a single snapshot. If you back up multiple servers with similar OS files into the same Borg repository, the cross-server dedup savings are substantial. We tested two identical-OS servers into one repo and saw a 31% reduction in total storage compared to separate repositories.
The operational risk with Borg is repository locking. If a backup job crashes mid-run, it leaves a stale lock. You must run `borg break-lock` manually before the next job can proceed. In automated environments, this requires a wrapper script that checks for stale locks and handles the recovery path. Borg 2.0 improved this with better lock timeouts, but it remains a sharp edge in unattended operation.
Borg also does not support parallel writes from multiple clients to the same repository without Borgmatic's coordination layer. For multi-server setups, either use one repository per client or use Borgmatic.
# Initialize with encryption
borg init --encryption=repokey-blake2 \
backup-server:/borg/myapp
# Create a snapshot
borg create --stats --progress \
backup-server:/borg/myapp::'{hostname}-{now:%Y-%m-%dT%H:%M}' \
/data \
--exclude '/data/tmp' \
--exclude-caches
# List snapshots
borg list backup-server:/borg/myapp
# Mount and browse a snapshot
borg mount backup-server:/borg/myapp::myhost-2026-08-01T02:00 /mnt/restore
Borgmatic - The Right Way to Run Borg at Scale
Borgmatic wraps Borg with a YAML configuration layer and handles the pre/post hook logic, error alerting, and retention policy execution that you would otherwise write yourself. Version 1.9 added support for Borg 2.0 and PostgreSQL/MySQL database dump hooks that run before the filesystem backup.
The database hook is genuinely useful. Instead of writing a cron wrapper that dumps PostgreSQL, waits for it to finish, then starts the backup, borgmatic handles the sequencing inside a single backup run. Failed dumps abort the backup rather than silently backing up a partial file.
If you are running Borg in production on more than two servers, use borgmatic. The configuration file approach also means your backup policy lives in version control rather than scattered across cron entries.
# /etc/borgmatic/config.yaml
location:
source_directories:
- /data
- /etc
repositories:
- path: backup-server:/borg/myapp
label: primary
storage:
encryption_passphrase: "${BORG_PASSPHRASE}"
archive_name_format: '{hostname}-{now:%Y-%m-%dT%H:%M:%S}'
retention:
keep_daily: 7
keep_weekly: 4
keep_monthly: 6
hooks:
postgresql_databases:
- name: all
hostname: localhost
username: postgres
before_backup:
- echo "Starting backup on $(hostname)"
on_error:
- curl -fsS -m 10 "https://hc-ping.com/${HC_UUID}/fail"
Amanda - Enterprise Scheduling Without the Enterprise Cost
Amanda 3.5.4 is the oldest tool in this list and it shows in the configuration syntax. It uses a central server model where one Amanda server coordinates backups from multiple clients, scheduling them across a DLE (Disk List Entry) model. This architecture makes it suitable for environments with 50+ servers where you need centralized scheduling and tape or virtual tape library support.
Setup overhead is significant. You need an Amanda server, client packages on every host, and a correctly configured `amanda.conf` and `disklist` file before a single byte gets backed up. On our test setup, initial configuration took 3 hours including debugging the `amcheck` pre-flight. That said, once running, Amanda's scheduling engine is robust: it automatically balances backup loads across the configured holding disk and handles retries on failed jobs.
We do not recommend Amanda for small environments or teams without a dedicated storage engineer. For large enterprises backing up to tape or object storage at petabyte scale, it remains competitive.
# Check Amanda server can reach all clients
amcheck -s DailySet
# Run a manual backup immediately
amdump DailySet
# Verify a specific backup
amverify DailySet hostname /data 2026-08-01
Bacula - When You Need Workflow Control at Scale
Bacula 15.0 uses a client-server-director architecture with separate Director, Storage Daemon, and File Daemon components. The configuration language is verbose but expressive: you can define backup schedules, pool policies, and restore workflows with conditional logic that no other open source tool matches.
In our test, Bacula's initial backup was the slowest at 71 minutes for 500GB, partly because our config used the default buffer sizes. After tuning `Maximum Network Buffer Size = 65536` in both the Storage and File Daemon configs, throughput improved by 22%.
Bacula's strength is job dependency management. You can define a chain of jobs - dump DB, back up filesystem, verify checksum, report - where each step gates the next. For regulated environments where you need an audit trail of every backup operation and a documented verification step, Bacula's catalog database (PostgreSQL or MySQL) provides that history natively.
The community version lacks deduplication. Bacula Enterprise adds it, but that is a commercial license. If dedup is a requirement, Borg or Restic will serve you better.
# bacula-fd.conf tuning
FileDaemon {
Name = myapp-fd
Maximum Network Buffer Size = 65536
Maximum Concurrent Jobs = 4
}
# Run a manual job from bconsole
bconsole
*run job=BackupMyApp level=Full
*status dir
*list jobs
Duplicati and Timeshift - Specific Use Cases Only
Duplicati 2.0.8 is a good fit for desktop Linux or small VPS instances where you want a GUI and cloud backend support without writing scripts. It uses AES-256 encryption and supports S3, Backblaze B2, Google Drive, and others. On our 500GB server test it was the slowest tool we benchmarked at 94 minutes initial backup, and the memory usage during deduplication peaked at 6.8GB. We would not run Duplicati on a production database server.
Timeshift is not a backup tool for servers. It uses rsync or BTRFS snapshots to capture system state and is designed for desktop system recovery. There is no network target support, no encryption, and no mechanism to back up user data directories separately from system files. If you have found Timeshift in a production server backup runbook, replace it.
For DevOps teams building automated backup pipelines, tools like taskbotshub.ai can help wire together backup job orchestration, alerting, and restore testing workflows across your infrastructure without writing custom glue code for each environment.
# Timeshift - what it actually does (system snapshots only)
timeshift --create --comments "before kernel upgrade"
timeshift --list
# Not for server data backup
Restore Testing - The Part Everyone Skips
A backup you have not restored from is not a backup. We added restore testing to our benchmark because every tool passed the backup phase but two had silent failures on restore that only appeared under specific conditions.
The minimum viable restore test for any server: once per week, restore a randomly selected file from a randomly selected backup snapshot and verify its checksum against the original. Once per month, restore the full dataset to a staging server and run application smoke tests.
For restic, automate this with a script that picks a random snapshot ID and restores a file to `/tmp/restore-test/`, then compares SHA-256 with the live file. If the checksums differ, send an alert.
For environments where you are naming backup repositories, storage buckets, or internal services that support your backup infrastructure, consistent and clear naming pays dividends when you are doing emergency restores at 3am. Services like nicename.me can help when you need to register clean domain names for backup portals or monitoring dashboards tied to your backup systems.
#!/bin/bash
# weekly-restore-test.sh
REPO="sftp:backup-server:/restic/myapp"
SNAPSHOT=$(restic -r "$REPO" snapshots --json | \
jq -r '.[].id' | shuf -n 1)
TEST_FILE=$(restic -r "$REPO" ls "$SNAPSHOT" \
--json | jq -r 'select(.type=="file") | .path' | \
shuf -n 1)
restic -r "$REPO" restore "$SNAPSHOT" \
--include "$TEST_FILE" \
--target /tmp/restore-test/
ORIG_HASH=$(sha256sum "$TEST_FILE" | awk '{print $1}')
RESTORE_HASH=$(sha256sum "/tmp/restore-test/${TEST_FILE}" | awk '{print $1}')
if [ "$ORIG_HASH" != "$RESTORE_HASH" ]; then
echo "RESTORE MISMATCH: $TEST_FILE" | mail -s "Backup Alert" ops@example.com
exit 1
fi
rm -rf /tmp/restore-test/
echo "Restore test passed: $TEST_FILE from snapshot $SNAPSHOT"
Performance Summary Across All Tools
Numbers from our 500GB test dataset on a 10Gbps LAN:
| Tool | Initial Backup | Incremental (5% change) | Dedup Ratio | Full Restore | Peak RAM | |---|---|---|---|---|---| | rsync hardlinks | 47 min | 4m 20s | none | 41 min | 120MB | | Restic 0.17 | 53 min | 6m | 18:1 | 49 min | 4.2GB | | BorgBackup 2.0 | 61 min | 5m 10s | 24:1 | 55 min | 2.1GB | | Bacula 15.0 (tuned) | 57 min | 7m | none | 52 min | 380MB | | Amanda 3.5.4 | 63 min | 8m | none | 58 min | 290MB | | Duplicati 2.0.8 | 94 min | 12m | 11:1 | 88 min | 6.8GB |
rsync wins on raw speed because it skips chunking and encryption overhead. Borg wins on storage efficiency. Restic hits the best balance of speed, deduplication, and operational simplicity for most use cases.