How to Use VPS as Off-Site Backup Target
Provider snapshot no be off-site backup. Use a VPS with Proxmox Backup Server or restic, then price 90-day retention before you commit.
Wetin off-site backup target really be
Off-site backup target na second machine wey hold copy of your data and fit fail independently from the original. VPS for another provider na the cheapest option wey most readers fit get. Three options make sense: Proxmox Backup Server wey dey run for the VPS, a restic repository wey you reach through SSH or S3, or an rsync mirror wey the backup host dey pull. Which one fit you depend on wetin you need restore and how fast you need am back. Who get permission to delete the copy go decide the remaining details.
Off-site mean say e dey for different failure domain. That mean different provider, plus account wey no share login with the one wey dey run your server. Second server for another region of the same provider fit survive fire for one building. E no fit survive compromised control panel login, because one account control both copies.
Snapshot for your provider no be that second copy. E dey behind the same panel password, so anybody wey get that password fit delete the server and its snapshots in one session. Snapshot services too dey charge per gigabyte per month, with rates wey pass plain disk by far. That one make ninety days of snapshots expensive. The difference between VPS snapshots and backups worth reading before you rely on either one.
Which of the three shapes fit you
- Proxmox Backup Server (PBS): the source na Proxmox VE (virtual environment), and wetin you go restore na one complete virtual machine. E dey back up for disk-image level, and e verify jobs dey read the data wey dey target again.
- A restic repository: the source na one or more Linux hosts, and wetin you go restore na directory or database dump. E dey encrypt data for client side, and e dey support SSH and S3, plus e own REST protocol.
- rsync over SSH, pulled by the backup host: you want the files for target as ordinary files, wey you fit read with
lsandcat, without any client software to restore dem.
If you no fit decide, run restic. E dey encrypt data before anything comot from the machine, and e no need anything for target apart from SSH account and disk. How to set up restic backups for VPS explain the client side more, while restic and BorgBackup side by side explain the choice if you already dey run Borg.
Sizing the target: wetin one month of retention go cost
Deduplication na why the numbers small pass wetin people dey expect. restic and PBS both dey split files into variable-size chunks and hash each chunk. Dem store each unique chunk only once. The second backup of a 500 GB dataset no go add another 500 GB. E go add only the chunks wey change.
So repository size dey follow how old your oldest snapshot be, no be the number of snapshots. Take 500 GB of data and 5 GB of new unique data every day. The repository go then hold the 500 GB base, plus roughly 5 GB for every day back to the oldest snapshot wey the policy keep.
The data behind this chart
[
{
"label": "7 daily",
"repo_size_gb": 535,
"usd_at_10_per_tb": 5.35
},
{
"label": "7 daily, 4 weekly",
"repo_size_gb": 640,
"usd_at_10_per_tb": 6.4
},
{
"label": "7 daily, 4 weekly, 6 monthly",
"repo_size_gb": "1,400",
"usd_at_10_per_tb": 14.0
},
{
"label": "7 daily, 4 weekly, 12 monthly",
"repo_size_gb": "2,325",
"usd_at_10_per_tb": 23.25
}
]The dollar column dey price that repository at 10 US dollars per TB per month. Na placeholder for the arithmetic, no be quote from any provider, so replace am with the real per-TB price of the plan wey you dey consider. One week of dailies dey hold about 535 GB. One full year of history dey hold 2,325 GB, wey be $23.25 every month compared with $5.35 for the week. History cheap. Na the base copy be wetin you dey pay for.
Deduplication no dey help data wey don already get compression or encryption. A gzipped database dump dey change completely every time e run, so each dump go land as new chunks and the repository go grow by one full dump every night. Write the dump uncompressed and allow the backup tool compress am, because restic don support compressed repositories since 0.14 and version 0.19 add the fastest and better zstd modes. Photo and video libraries no dedupe well for the same reason, so size dem based on their real growth rate instead of the rows above.
You dey buy idle disk instead of CPU here, and na exactly the case where storage VPS dey beat regular VPS.
Wetin make bandwidth and restore time determine the plan
Disk na the cheap part. The first upload and the final restore na the expensive parts. 500 GB na 4 trillion bits, so if you divide am by link speed, you go get the minimum time wey full restore fit take.
The data behind this chart
[
{
"label": "40 Mbit/s home upload",
"elapsed_h": 27.8
},
{
"label": "100 Mbit/s",
"elapsed_h": 11.1
},
{
"label": "500 Mbit/s",
"elapsed_h": 2.2
},
{
"label": "1 Gbit/s VPS port",
"elapsed_h": 1.1
}
]Those figures assume full line rate with no protocol overhead, so treat dem as best case. For 100 Mbit/s, full restore need 11.1 hours before anybody fit touch the data. From home upload of 40 Mbit/s, e need 27.8 hours. For 1 Gbit/s port, the same restore go take 1.1 hours. Plenty small files fit make the process slower than the calculation, because per-file overhead become the main issue once files dey below few hundred kilobytes.
Two things follow from this. If your recovery time objective (RTO), meaning the outage wey you fit tolerate, na four hours, 500 GB restore over 100 Mbit/s link don already miss am, and cheaper disk no go help. Also, most VPS plans dey measure outbound transfer, so one full restore go use 0.5 TB from the backup host monthly allowance. Check that allowance, and check wetin the provider go do when you pass am, before you need the data.
The first backup na the complete dataset, and na the slowest run wey you go ever do. Start am on Friday, then limit the rate so e no saturate the source uplink: restic takes --limit-upload in KiB per second, while rsync takes --bwlimit.
Shape 1: Proxmox Backup Server as remote datastore
PBS fit work when source na Proxmox VE and wetin you wan restore na virtual machine. VPS no fit boot Proxmox ISO, so install PBS on top Debian. Version 4.2 na the current one as of August 2026, and e dey built on Debian 13 (trixie).
wget https://enterprise.proxmox.com/debian/proxmox-archive-keyring-trixie.gpg \
-O /usr/share/keyrings/proxmox-archive-keyring.gpg
sha256sum /usr/share/keyrings/proxmox-archive-keyring.gpgCompare that checksum with the value wey dey published for the Proxmox package repositories page. The trustworthiness of apt repository no pass the key wey you verify. Then write /etc/apt/sources.list.d/proxmox.sources:
Types: deb
URIs: http://download.proxmox.com/debian/pbs
Suites: trixie
Components: pbs-no-subscription
Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpgsudo apt update && sudo apt install -y proxmox-backup-server
sudo proxmox-backup-manager datastore create offsite /mnt/datastore/offsiteGive the datastore its own filesystem or its own volume. Full datastore go stop backups, and datastore wey dey share root filesystem fit bring the whole server down when e fill.
Next, create the account wey source go use, then give am token instead of password.
sudo proxmox-backup-manager user create backup@pbs
sudo proxmox-backup-manager user generate-token backup@pbs pve1
sudo proxmox-backup-manager acl update /datastore/offsite DatastoreBackup \
--auth-id 'backup@pbs!pve1'Token secret go print only once and you no fit read am again, so save am when e show. The role dey important just like the token. DatastoreBackup fit create and restore only its own backups, and e no get the Datastore.Prune privilege, so that token no fit delete snapshot wey e don write.
Retention for PBS get two parts, and na the second part people dey often skip. Prune dey remove snapshots. Garbage collection dey remove chunks wey no surviving snapshot dey reference again. Free space go show after garbage collection, no be after prune.
proxmox-backup-client prune host/web1 \
--keep-daily 7 --keep-weekly 4 --keep-monthly 6 --dry-run
sudo proxmox-backup-manager garbage-collection start offsite
sudo proxmox-backup-manager verify offsiteDrop --dry-run once the list of snapshots wey e plan to remove look correct. Garbage collection dey run for two phases: e first update the access time of every chunk wey dem still dey reference, then e delete chunks wey access time older than the cutoff. The cutoff na 24 hours and 5 minutes before the run start. That grace period dey make sure say chunk wey backup still dey write no get deleted underneath am. Schedule prune every day and garbage collection every week for the datastore, then add verify job so target go read its own chunks again and report corruption for disk before restore expose am.
If source na PBS instance itself, the off-site box fit pull instead of dem pushing backup go am.
sudo proxmox-backup-manager remote create home1 \
--host pbs.home.example --userid sync@pam --password 'SECRET' \
--fingerprint '64:d3:ff:3a:50:38:53:5a:9b:f7:50:ab:fe'
sudo proxmox-backup-manager sync-job create home1-offsite \
--remote home1 --remote-store main --store offsite --schedule 'Wed 02:30'Run that sync job for VPS, with the default pull direction. VPS go reach inside the home datastore, so home box no hold any credential wey fit touch the off-site copy.
Shape 2: restic repository over SSH or S3
Debian and Ubuntu both package restic, but dem both dey behind upstream. Version 0.19.1 na current as of August 2026. Install the official binary for the source host.
curl -LO https://github.com/restic/restic/releases/download/v0.19.1/restic_0.19.1_linux_amd64.bz2
bunzip2 restic_0.19.1_linux_amd64.bz2
sudo install -m 755 restic_0.19.1_linux_amd64 /usr/local/bin/restic
restic versionrestic version go print the version and the Go compiler wey build am. Later upgrades na sudo restic self-update, and e dey work for official binaries but e no dey work for copy wey apt install.
For the backup VPS, create account wey no own anything else, then copy public key of the source host enter /home/resticsrv/.ssh/authorized_keys.
sudo adduser --disabled-password --gecos '' resticsrv
sudo install -d -m 700 -o resticsrv -g resticsrv /srv/resticInitialise the repository from the source through SFTP.
sudo sh -c 'umask 077; head -c 32 /dev/urandom | base64 > /root/.restic-password'
export RESTIC_REPOSITORY='sftp:resticsrv@backup.example.net:/srv/restic/web1'
export RESTIC_PASSWORD_FILE=/root/.restic-password
restic init
restic backup /etc /srv /var/backups --exclude-cachesStore that password for somewhere wey no be this server and no be the backup target. If you lose am, nobody fit read the repository again, and no recovery path dey at all. Na so client-side encryption work.
Retention na one command, and na the second half dey free disk space.
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
restic check --read-data-subset=10%forget dey delete snapshots. prune dey delete pack files wey na only those snapshots reference, and --prune dey run am automatically when e actually remove something. Without am, the repository no go ever shrink. restic check dey verify repository structure, and --read-data-subset=10% dey read again and re-hash one tenth of the pack files. This one fit catch corruption for the target without the cost of reading everything. The other form, --read-data-subset=1/10, dey check one fixed tenth. So, if you increase that first number every week, you go cover the whole repository within ten weeks.
If person kill one run, the next one go stop with repository is already locked exclusively by PID. Confirm say no backup dey run, then clear am with restic unlock.
For object storage, the repository string go become s3:https://s3.example.net/web1, with credentials for AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY. Everything else remain the same. Na so restic dey talk to self-hosted MinIO object store wey dey run for the same VPS.
Shape 3: rsync over SSH wey get pull-only key
The security property of this shape na direction. The backup VPS dey connect to source and read from am. Source no hold any key and e no get route go backup host, so if person breach source, e no fit reach the backups at all.
Generate key pair for backup VPS, then install the public half for source with a forced command.
command="rrsync -ro /srv",restrict ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA offsite-pullrrsync dey inside rsync package for /usr/bin/rrsync on Debian 13 and Ubuntu 24.04. -ro allow reading only and e imply -no-del, so this key no fit write to source or delete anything for there. restrict switch off SSH features wey no dey needed here, including port forwarding and the pty, so nobody fit use the key for interactive login. Paths come dey relative to the directory wey you name, so remote path / mean /srv for source.
The pull dey keep history with hardlinks. Files wey no change for the new tree na hardlinks to the previous tree, so dem cost one directory entry instead of another copy.
DEST=/srv/mirror/web1
TODAY=$(date +%F)
LAST=$(ls -1d "$DEST"/2* 2>/dev/null | tail -1)
LINK=""
if [ -n "$LAST" ]; then LINK="--link-dest=$LAST"; fi
rsync -aH --numeric-ids $LINK -e 'ssh -i /root/.ssh/pull_ed25519' \
pull@web1.example.net:/ "$DEST/.$TODAY.partial/"
mv "$DEST/.$TODAY.partial" "$DEST/$TODAY"The rename for the end na wetin make dated directory trustworthy: the name go appear only after rsync exit 0, so interrupted transfer no go look like completed snapshot. Expire old trees with one line, and keep thirty.
ls -1d /srv/mirror/web1/2* | sort | head -n -30 | xargs -r rm -rfMake we talk true about wetin this shape cost. Hardlinks dey deduplicate complete files only, so if one byte change inside 4 GB disk image, e go copy all 4 GB, while restic and PBS go store only few changed chunks. The target still dey hold your files as plaintext, so anybody wey get root for backup VPS fit read dem.
Client-side encryption, so target no go ever see plaintext
Treat backup VPS like machine wey you no fully control. E get provider, and provider get staff plus failed disks wey dem fit carry commot from the building.
restic dey encrypt every chunk for source before e send am, so repository na ciphertext plus metadata about sizes and timing. PBS encryption na opt-in: create key, then pass am for every backup.
proxmox-backup-client key create /root/pbs-encryption.key
proxmox-backup-client backup root.pxar:/ --keyfile /root/pbs-encryption.key
proxmox-backup-client key paperkey --output-format text > qrkey.txtPrint the paper key and keep am for physical place. Proxmox documentation talk the matter plainly: without the key, backed up files no dey accessible. Keep the key away from backup target, because key wey dey beside ciphertext no dey protect anybody.
rsync mirrors no get equivalent. The files go land as files. If the data sensitive, either accept say target fit read am, or use one of the other two shapes.
Stop compromised source from wiping its own backups
If attacker take the source, e go search for the backups next. The credential wey dey upload the backups dey right there for the machine. If that credential fit delete too, dem go use am.
PBS answer this one with roles. Token wey get only DatastoreBackup fit write new snapshots and restore its own ones. E no fit prune, because deleting snapshot need the separate Datastore.Prune privilege. Run retention from the PBS side. This way, the source no ever hold credential wey fit remove anything.
restic over SFTP no get this kind separation, because the SSH key wey writes to the repository fit also delete from am. The fix na the REST backend. Run rest-server for the backup VPS with --append-only. This allows creation of new backups but blocks deletion and modification of existing ones. Then point the client to rest:https://backup.example.net:8000/web1 with RESTIC_REST_USERNAME and RESTIC_REST_PASSWORD. Any restic forget --prune from the source go fail. Na the expected result be that one. So retention go run from another machine wey get its own credential. The restic manual also recommends --keep-within instead of count-based policies for append-only repositories. If attacker flood the repository with junk snapshots, dem fit otherwise push your real ones outside a --keep-last window.
rsync solve the same problem by pulling. The source no hold any credential for the target.
One rule cover all three setups: the credential wey fit delete backups must dey on a machine different from the one wey dem dey back up.
Put restore drill for calendar
Backup wey you never restore na still assumption. Book one hour every quarter and test am.
restic snapshots
restic restore latest --target /var/tmp/restore-test --include /etc/nginx
diff -r /etc/nginx /var/tmp/restore-test/etc/nginxIf diff -r no print anything, e mean say the restored tree match the live one. For PBS, the same drill na proxmox-backup-client restore host/web1/2026-08-13T02:30:00Z root.pxar /var/tmp/restore-test/, plus one scheduled verify job wey go read chunks again for the target and report checksum failures.
The drill must prove more than say the bytes dey intact.
- Restore from a third machine, no be from the source, because na the source exactly you dey assume say e don disappear. So, repository password or PBS key must dey reachable without that source.
- Time the restore and write the number down. Then compare am with the RTO wey you claim. The chart above show the transfer floor. The real number also include decrypting and writing to disk, plus the time wey you spend finding the snapshot wey you want.
- Restore something wey get state, like a database dump wey you go load into a scratch instance. Tar file wey extracts successfully no be proof say the application go start.
The cheapest disk for the whole world no get value until you don restore from am once.
FAQ
Off-site backup dey mean snapshot for my VPS provider?
No. Provider snapshot dey inside the same account, behind the same panel login, and for the same invoice as the server wey e copy. Anybody wey get that login fit delete the server and every snapshot of am in one session. Snapshots dey useful for quick rollback before risky upgrade, but dem no be second location. Off-site copy dey under different account, ideally for different provider, with credentials wey the source machine no get.
How much disk space I need for one month of retained backups?
Calculate am from the age of your oldest snapshot, no be from the number of snapshots. Deduplicating tool dey store each unique chunk once, so repository size roughly equal source size plus new unique data per day multiplied by the number of days wey you keep. For 500 GB of data wey dey change by 5 GB per day, one week of daily backups na about 535 GB, while full year of history na 2,325 GB. Add extra headroom, because full disk go make the next backup fail, and restic's prune need free space to repack pack files before e fit return the space.
Compromised server fit delete its own off-site backups?
Yes, unless you design against am. With plain SSH or SFTP repository, the key wey dey write fit also delete. Give the source credential wey no fit remove data: a PBS API token wey get only the DatastoreBackup role, wey no get the Datastore.Prune privilege, or restic against rest-server started with --append-only, wey dey refuse deletion and modification of existing backups. Pull design go further, because the source no go get any credential for the backup host. Run retention from the side wey no be the source.
I suppose run Proxmox Backup Server or restic for the backup VPS?
Match the tool with the unit wey you want restore. If source na Proxmox VE and you want the whole virtual machine back, run PBS, because e dey back up at disk-image level and restore VM in one step. If source na Linux host and you want files and database dumps back, run restic. E only need SSH account for the target and e dey encrypt before sending. Running both dey normal: PBS for the hypervisor, restic for servers wey no dey on am.
How long restore from VPS backup go take?
Divide data size by link speed to get the minimum time, then add time for decryption and writing. 500 GB over 100 Mbit/s link na 11.1 hours at line rate, while the same restore over 1 Gbit/s port na 1.1 hours. Many small files dey run slower than this calculation because of per-file overhead. Time one real restore and use the measured number, because na only that number your recovery plan fit rely on.