A Proxmox Backup Server job backs up entire VMs and containers, which covers you if a whole box dies. It does not, by itself, give you a clean, restorable copy of the actual data living inside your self-hosted apps, the Vaultwarden vault, the Paperless-ngx document store, the dozen docker-compose.yaml files and their bind-mounted config directories that took real time to get right. If your backup strategy stops at the hypervisor layer, you’re covered against hardware death but not against the more common failure: a bad update, a fat-fingered docker compose down -v, or a config file you meant to edit and instead overwrote. This is where an app-level backup tool earns its place alongside whatever you’re already doing at the VM/container level.

Why hypervisor-level backup isn’t enough on its own

A PBS backup (or a VM snapshot) captures the entire disk image, which technically includes your Docker volumes, buried inside it. That’s real protection, but it’s coarse: restoring means bringing back the whole VM/container state as of that snapshot, not “just give me yesterday’s Vaultwarden database” or “just show me what this config file looked like before I broke it.” It’s also usually daily at best, meaning up to 24 hours of data loss in the worst case, and it doesn’t give you an easy way to browse what changed between backups.

App-level backup tools solve a different, complementary problem: fine-grained, deduplicated, easily browsable backups of specific directories and volumes, run as often as you want, with the ability to restore a single file or database from a specific point in time without touching anything else.

Restic vs Borg: what actually differs

Both are content-addressable, deduplicating, encrypted backup tools built for exactly this job, and both are solid choices. The practical differences:

Restic is a single static binary, no server component required, and it natively supports a wide range of storage backends out of the box, local disk, SFTP, S3-compatible object storage (Backblaze B2, Wasabi, MinIO), and more, without needing extra infrastructure. This makes it the simpler choice if you want to back straight up to cloud storage (B2 pairs especially well with Restic and is commonly the cheapest S3-compatible option per TB), or if you just don’t want to run a dedicated backup server at all.

Borg (BorgBackup) generally edges out Restic on deduplication efficiency and compression ratio in most real-world comparisons, which matters more the larger your backed-up data set gets. Its tradeoff is that it wants a repository it controls directly, either local/mounted storage or a remote host reachable over SSH running Borg itself (or a compatible remote-repo tool like borgmatic’s companion setups), it doesn’t speak S3-style object storage natively the way Restic does. If you’re backing up to a Linux box you control (a second local machine, a cheap VPS, another homelab box at a different location), Borg’s efficiency advantage is worth having. If your target is cloud object storage, Restic is the more direct fit.

Neither is a wrong choice for a homelab. If you’re already planning to push backups to S3-compatible cloud storage, pick Restic. If you’re backing up to a Linux box you control, pick Borg for the better dedup, or Restic if you’d rather not think about the difference and just want something that works everywhere.

What to actually back up in a Docker-based self-hosted stack

Two categories, and they need different treatment:

Bind-mounted config and data directories. Anything mapped as ./data:/app/data or similar in a docker-compose.yaml, the app’s actual working files, is a plain directory on the host filesystem and both Restic and Borg can back it up directly with no special handling, same as any other files.

Named Docker volumes. These live inside Docker’s own storage area (/var/lib/docker/volumes/ by default), not somewhere you’d casually browse. You can back them up directly from that path, but the cleaner, safer pattern is to spin up a throwaway container that mounts the named volume and pipe the backup tool through it, or stop the dependent container briefly and back up the volume’s underlying directory directly. For anything with a live database inside (Postgres, MySQL, SQLite-backed apps), back up a proper database dump (pg_dump, etc.) alongside or instead of the raw files, a backup taken mid-write on a live database file can be internally inconsistent even if the backup tool itself ran without error.

Also back up the docker-compose.yaml files themselves and any .env files. These aren’t data, but without them a restored volume is just orphaned files with no stack definition to bring them back online. Keeping compose files in a private git repo (never commit .env secrets to it) alongside the data backups from Restic/Borg means a full rebuild is “clone the repo, restore the volumes, docker compose up -d”, not a reconstruction project from memory.

A workable schedule

There’s no need to overthink cadence. A reasonable default: nightly backups via cron (both Restic and Borg are trivially cron-friendly, or wrap them with borgmatic or Restic’s own scheduling helpers for cleaner config management), with a retention policy keeping recent daily snapshots plus a thinning schedule further back, both tools support this natively (restic forget --prune with retention flags, Borg’s prune command). Something like 7 daily, 4 weekly, 6 monthly is a common, sane starting point, adjust based on how much churn your data actually has and how much backup storage you’re willing to spend.

Test the restore, not just the backup

This is the step almost everyone skips and the one that actually matters. A backup job completing without error tells you the tool ran, it doesn’t tell you the backup is actually restorable. Periodically (quarterly is a reasonable minimum) actually restore a real backup, ideally into a throwaway test environment, and confirm the app comes back up correctly with real data intact. Both Restic and Borg support mounting a backup repository as a browsable filesystem (restic mount, borg mount) specifically to make spot-checking easy without doing a full restore every time, use that for lighter-weight periodic sanity checks between the less frequent full restore tests.

Bottom line

Hypervisor-level backups (PBS, VM snapshots) protect you against hardware and whole-box failure. App-level backups with Restic or Borg protect you against the much more common failure mode, a bad update, a mistaken command, a config you overwrote, by giving you fine-grained, frequent, easily restorable copies of the actual data and configs that make your self-hosted stack yours. Run both. Pick Restic if you’re backing up to cloud object storage or want zero server infrastructure, pick Borg if you’re backing up to a box you control and want the better deduplication. Either way, actually test a restore periodically, a backup job that’s never been restored from is a hope, not a plan.