How We Evaluated These Tools
The comparisons below consider tools evaluated against a dataset containing PostgreSQL data directories, application logs, and mixed media files. Key dimensions include:
- 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 dataset - Memory footprint during backup
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.
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. 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, pairing it with `restic forget` and `restic prune` on a schedule keeps 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 large repositories after months of daily backups, the process can consume several gigabytes 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. 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, and backing two identical-OS servers into one repo can meaningfully reduce 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. Initial configuration typically involves non-trivial debugging of 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.
Amanda is not recommended 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.
Default buffer sizes can limit throughput; tuning `Maximum Network Buffer Size = 65536` in both the Storage and File Daemon configs is a well-known improvement for network performance.
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 larger datasets it tends to be slower than alternatives and memory usage during deduplication can be substantial. It is not well suited to production database servers.
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. Restore testing matters because a tool can pass the backup phase while having silent failures on restore that only appear 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
rsync tends to be fastest on raw throughput because it skips chunking and encryption overhead. Borg leads on storage efficiency due to its chunk-level deduplication across the entire repository history. Restic hits a strong balance of speed, deduplication, and operational simplicity for most use cases. Amanda and Bacula carry more operational overhead but suit larger, more complex environments. Duplicati is the most accessible option for desktop or light VPS use but does not scale well to large production datasets.