A backup nobody has tested by restoring it is just a file taking up disk space. restic and BorgBackup solve backups differently from tar or rsync: they split data into variable-length chunks, store only unique chunks in the repository, and encrypt the archive on the client side. On a VPS with limited disk space, this cuts the storage footprint of daily copies by 3-5 times compared to a plain tar.gz.
Why deduplication matters for backups
A plain tar.gz creates a whole new archive on every daily run, even if only 200 MB out of 50 GB changed in a day. Over a month that adds up to a terabyte of copies of the same files. restic and BorgBackup compare data chunks against what is already stored in the repository on every run and append only what actually changed.
In practice this means the first backup of a 50 GB directory will take up nearly the same amount of space in the repository. The second run and every one after that usually add 100-500 MB, covering changed logs, configs, and part of the site files. Keeping 30 daily copies becomes realistic even on a VPS with an 80 GB disk.
How restic differs from BorgBackup
Repository architecture and the client
restic is written in Go, ships as a single binary with no dependencies, and works the same way on Linux, FreeBSD, and Windows. BorgBackup is written in Python with C extensions for speed, requires installation through a package manager or pip, and in practice is used more as a client than as a server.
Encryption and remote backends
restic always encrypts the repository with AES-256, with no way to turn it off. BorgBackup gives you a choice: you can create a repository with no encryption at all, which speeds up writes to a trusted local disk. restic has a noticeably wider list of native backends — it can write directly to S3, Backblaze B2, and Azure Blob Storage, and through rclone serve, to dozens of other clouds.
| Parameter | restic | BorgBackup |
|---|---|---|
| Implementation language | Go, single binary | Python and C |
| Encryption | AES-256, always on | AES-256, optional |
| Native backends | SFTP, S3, B2, Azure, rclone | SFTP, local disk |
| Cross-host deduplication | Yes, in a shared repository | Yes, in a shared repository |
| FUSE mounting | Available, restic mount | Available, borg mount |
Installing restic and BorgBackup on a VPS
Both tools are in the Debian and Ubuntu repositories, starting with versions where the packages are not too outdated. For a fresh restic build, it is easier to download the binary from GitHub Releases and replace the packaged one.
apt update && apt install -y restic borgbackup
restic version
borg --version
# if the restic version in the repository is old — self-update:
restic self-update
Neither client needs a server component: the repository is just a directory on disk, over SFTP, or in object storage, accessed directly by the client.
First backup and restoring a file
The repository is initialized once, and the password for it should be stored separately from the server — without it, data cannot be restored even with root access to the VPS.
export RESTIC_REPOSITORY=/mnt/backup/restic-repo
export RESTIC_PASSWORD='password-at-least-20-characters-save-it'
restic init
restic backup /etc /var/www /home
restic restore latest --target /tmp/restore --include /etc/nginx
The restic snapshots command lists every restore point with its date and the size of new data. You can restore either the whole snapshot or a single file with --include, without unpacking the entire archive.
Where to store the repository: disk, SFTP, S3
Storing the repository on the same disk as the data makes no sense: if the disk fails or the VPS is deleted, both the data and the backups disappear. Practical options:
- A second disk or block storage mounted separately from the system partition — the fastest option for restores, but it does not protect against losing the whole server.
- SFTP to a second VPS in another data center — restic and borg connect to it directly, with no middleware.
- S3-compatible storage, including your own MinIO server — you can create the repository directly over the s3 protocol by setting access keys in environment variables.
When you need to sync an existing repository to the cloud without built-in protocol support, you put rclone between the client and the storage — it can act as a serve layer for restic and as a standalone copy tool for borg.
Automation with cron and integrity checks
A backup without rotation quickly eats up all the storage disk space. The retention policy is set with the forget flags: how many daily, weekly, and monthly copies to keep, with the rest resolved through the deduplication chain and physically removed by the prune command.
0 2 * * * restic backup /etc /var/www --tag daily && restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
Once a month, run a full integrity check of the repository, not just a review of the snapshot list — otherwise, corrupted chunks in object storage only surface at the moment of a real restore.
- restic check --read-data — reads every chunk of the repository and verifies checksums, not just metadata.
- borg check --verify-data — the equivalent for BorgBackup, run it less often because of the disk load.
- Once a quarter — a test restore of a snapshot to a separate server, not just a single-file restore command.
- Keep the repository password in a password manager separate from the VPS, not in an environment variable inside .bashrc.