← Back to Wiki
Backups / Cloud

Build a Real Offsite Backup Replica on a Cheap VPS

A backup server sitting in the same building as everything it protects isn't a real disaster recovery plan. A second, independent backup instance on a cheap cloud VPS closes that gap for a few dollars a month — done right, it doesn't need to trust the network it's protecting against.

Picking the VPS

You don't need much. If you're only replicating VM/container backups (not bulk media or file shares), a small droplet/instance — a single vCPU, a couple GB of RAM, and a modest boot disk — is plenty, since the actual backup data lives on a separate attached block-storage volume sized to your real dataset. Check du -sh on your actual backup datastore path first, not df on the mount, to size that volume realistically — the two numbers can differ by an order of magnitude on a shared NAS export.

Check your backup software's actual OS support before provisioning. Proxmox Backup Server, for example, only ships packages for Debian — there is no Ubuntu build at all, despite Ubuntu being the default option on most cloud providers' droplet-creation screens. Confirm against the vendor's own package repository listing before you install anything, not after.

The instinct to "tunnel everything" — and why that's the wrong tool here

If you've already set up a reverse tunnel to expose a NAT'd home service to the internet, it's tempting to reach for the same tool here to "hide" the new backup server. Worth pausing on that: a generic TCP tunnel changes which address traffic arrives at — it doesn't add any access control of its own. It solves a NAT problem, not a security problem. A cloud VPS doesn't have a NAT problem; it already has its own public IP. Layering a tunnel on top adds complexity without adding the restriction you actually want.

What actually restricts access is a firewall rule scoped to a specific source IP — most cloud providers offer this as a free, built-in "cloud firewall" or security-group feature, enforced at the network edge before traffic ever reaches the instance:

Verify it immediately after creating it — confirm you can still reach both ports from the allowed address, and ideally confirm from a second network that you can't.

Your home's public IP can change. A rule this specific breaks silently if your ISP reassigns it — worth a periodic check if backups mysteriously stop syncing one day.

Does this backup replica need TLS?

Yes, and it's worth getting a real, trusted certificate instead of clicking through a browser warning every time — see running your own internal certificate authority if you haven't already got one going. The interesting wrinkle: a cloud VPS normally needs a certificate from a public CA (Let's Encrypt or similar) to get a browser-trusted cert, since public CAs validate a domain by actually reaching it over the internet. But if you've firewalled this server down to your own home IP anyway, it's functionally an internal-only service despite having a real public IP and DNS record — so it can just use your existing internal CA the same way every other admin tool on your LAN does, no public-CA validation dance required.

Does the backup software have a real Windows client / DNS quirk to know about?

Not specific to this setup, but worth double-checking while you're touching DNS: if the domain hosting this replica is on a zone proxied through a CDN for your other public sites, make sure this particular record is set to DNS-only, not proxied. Backup server protocols and ports typically aren't things a CDN's free-tier proxy passes through cleanly.

Locking down the sync credential

The token or credential your home backup server uses to push data offsite should be scoped to the absolute minimum it needs: write new backups, nothing else. No delete, no prune, no modify rights. That way, even if this credential leaks, or your home server is ever compromised, whatever gets its hands on it still can't reach back and destroy backups that already landed offsite.

Verify the credential's real effective permissions, not just what you granted it. Some platforms compute a token's actual access as the intersection of the token's own grant and its parent account's grant — a token can look correctly scoped in an access-control listing while its parent account still has broader (or narrower) rights that change what actually happens in practice. Use whatever command your platform provides for "what can this credential actually do," not just "what was it granted."

Configure a one-way, push-only sync — and disable "remove vanished"

Point your home backup server at the new offsite instance and set up a push sync job (home → offsite), not a pull. Critically, look for an option often called something like "remove vanished" or "delete extraneous" — and make sure it's off. This setting mirrors deletions: if a backup disappears from the source, it also gets deleted from the destination on the next sync. That's exactly the behavior you don't want for a disaster-recovery copy — a ransomware event, a fat-fingered delete, or a bug on the home side should never be able to cascade into wiping the offsite copies too.

The honest answer about "immutable" backups

Free/community-tier self-hosted backup software generally does not offer true WORM/immutable storage — the kind where nothing, not even an admin with full access, can delete or modify a backup before its retention period expires. That's a feature more commonly associated with paid object-storage tiers (S3-style "object lock") or dedicated enterprise backup appliances, not something a self-hosted community tool typically implements internally. Don't assume paying for a commercial license of the same self-hosted tool adds this either — check the specific product's actual feature list rather than assuming a paid tier always means "more security features"; sometimes the paid tier is purely about support/repository access.

What you get instead, from the two mitigations above, covers a real and specific threat model: a compromised home network or a leaked sync credential can't reach back and destroy the offsite copies. What it does not cover: someone with direct root access on the offsite instance itself deliberately deleting files. If that level of protection matters to you, the realistic path is swapping the backend storage for something with real object-lock support, which is a bigger architectural decision than what's covered here.

Test it before you trust it

Manually trigger the sync job once and actually watch it transfer real data, rather than trusting that a green checkmark on the job configuration means anything. Check the destination instance directly too — its disk usage growing and a snapshot list actually populating is the only real confirmation data arrived, not just that it left the source.

Gotcha: a job-listing command can lie by omission. On at least one platform, asking "list all sync jobs" returned an empty result immediately after a job was confirmed created and configured correctly — asking to "show" that specific job by name/ID returned it just fine. If a list view looks suspiciously empty right after creating something, check the specific item directly before assuming it didn't save.
Gotcha: intermittent connection timeouts to a brand-new cloud instance don't necessarily mean anything is actually wrong. Small, freshly-provisioned cloud instances can show transient network-path flakiness for a while after creation, especially under any install/configuration load — a connection attempt timing out once is not proof of a real outage or a firewall misconfiguration. Check the provider's own dashboard (is the instance reported healthy? what does its own CPU/network graph show?) before concluding something is actually broken, and simply retry with a short backoff first.
Reminder: a fresh cloud instance normally has no password set on its administrative account — most providers only configure key-based login by default. If you need to log into a web UI that requires username/password rather than accepting your SSH key, you'll need to set one directly on the instance first.