How to back up a VPS to S3: encrypted, automatic and restorable
Back up a VPS to S3 (AWS, Cloudflare R2, Backblaze B2, Wasabi) with restic: encrypted, incremental, scheduled and restore-tested, or with ZoPanel.

Key takeaways
- Backups stored on the VPS itself do not survive losing the server; you need a copy that leaves it, for example on S3.
- Encrypt before uploading and use an access key limited to a single bucket.
- Databases must be dumped consistently before the backup, not copied from MariaDB's data directory.
- A backup that has never been restored is not proven to work.
The simplest safe way to back up a VPS to S3 is an encrypted, incremental backup tool such as restic: dump your databases to files, back up website files, dumps and configuration to an S3 bucket (AWS S3, Cloudflare R2, Backblaze B2, Wasabi or MinIO), run it every night, let a retention policy remove old snapshots, and test a restore regularly. The setup takes about 30 minutes, and storing a few tens of gigabytes usually costs a few dollars a month.
This guide covers the manual setup on Ubuntu 24.04 or Debian 12, command by command, and the same job in ZoPanel. It also covers choosing a provider, keeping backups safe even if the server is compromised, and the mistakes that make backups useless exactly when you need them.
Why back up a VPS to S3?
Many people think "my provider has snapshots" or "I keep backups in /backup on the server". Neither is enough:
- Backups on the server itself are lost with the server: a failed disk, a suspended provider account, an accidental deletion or ransomware.
- Provider snapshots are handy, but they live with the same provider, often cannot restore a single file, and a snapshot of a database mid-write can be inconsistent.
- S3 is object storage somewhere else, billed by the gigabyte, with a standard API that almost every backup tool supports.
This is the "1" at the end of the 3-2-1 rule: at least three copies, on two kinds of storage, one of them off-site.
What should you back up on a VPS?
You do not need an image of the whole disk. The operating system and software can be reinstalled in minutes; what cannot be recreated is data:
| Item | Usual location | Notes |
|---|---|---|
| Website files | /var/www, /home |
Including user uploads |
| Databases | Dumps from mariadb-dump, pg_dump |
Never copy /var/lib/mysql while it runs |
| Configuration | /etc (nginx, PHP, cron, certificates) |
Small, and saves hours when rebuilding |
/var/vmail or Maildir folders |
If the server runs mail | |
| Keys and secrets | .env files, DKIM keys |
This is why backups must be encrypted |
Which S3 storage should you use?
Any S3-compatible service works with restic. Compare on:
- Egress fees. Restoring means downloading. Cloudflare R2 charges no egress; at the time of writing (October 2026) it charges USD 0.015 per GB-month for standard storage, with the first 10 GB-month free. AWS S3 and some others charge for data going out.
- Location. Pick a different region from the VPS, but close enough for fast uploads.
- Minimum storage duration. Some providers bill each object for a minimum number of days, which affects how aggressively you prune.
- Object Lock and versioning. These protect backups from an attacker deleting them (see below).
Prices change often; check each provider's current pricing before you choose.
How to back up a VPS to S3 with restic
restic encrypts data on the server before it leaves, uploads only what changed (incremental and deduplicated) and restores individual files.
Step 1: Create a bucket and a dedicated key
In your S3 provider's console, create a dedicated private bucket (for example vps-backup-web1) and an access key limited to that bucket. Never use your account's root key: if the server is compromised, the attacker gets one bucket, not your whole storage account.
Step 2: Install restic and store the credentials
sudo apt update && sudo apt install -y restic
restic version
sudo install -d -m 700 /etc/restic
openssl rand -base64 32 | sudo tee /etc/restic/password >/dev/null
sudo chmod 600 /etc/restic/password
Create /etc/restic/env (mode 600) with your details:
export AWS_ACCESS_KEY_ID="bucket-access-key"
export AWS_SECRET_ACCESS_KEY="bucket-secret-key"
export RESTIC_REPOSITORY="s3:https://<provider-endpoint>/vps-backup-web1"
export RESTIC_PASSWORD_FILE="/etc/restic/password"
On AWS the endpoint looks like s3.<region>.amazonaws.com; on R2 it is <ACCOUNT_ID>.r2.cloudflarestorage.com. If your provider needs a region other than us-east-1, add export AWS_DEFAULT_REGION=.... The restic documentation has the syntax for each service.
Copy /etc/restic/password off the server now (a password manager, or paper in a safe). Lose it and every backup is unreadable, by anyone.
Initialise the repository:
sudo bash -c 'source /etc/restic/env && restic init'
Step 3: Write the backup script
Create /usr/local/sbin/backup-s3.sh:
#!/bin/bash
set -euo pipefail
source /etc/restic/env
# 1. Consistent database dump (InnoDB) to a file
install -d -m 700 /var/backups/db
mariadb-dump --all-databases --single-transaction --routines --triggers --events \
| gzip > /var/backups/db/all-databases.sql.gz
# 2. Back up to S3 (only changes are uploaded)
restic backup /etc /home /var/www /var/backups/db --exclude-caches --tag nightly
# 3. Keep 7 daily, 4 weekly, 6 monthly snapshots; remove the rest
restic forget --tag nightly --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
sudo chmod 700 /usr/local/sbin/backup-s3.sh
sudo /usr/local/sbin/backup-s3.sh
For PostgreSQL, add sudo -u postgres pg_dumpall | gzip > /var/backups/db/postgres.sql.gz. Skip what you do not need (caches, node_modules) with --exclude.
Step 4: Run it nightly with a systemd timer
/etc/systemd/system/backup-s3.service:
[Unit]
Description=Backup VPS to S3 with restic
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/backup-s3.sh
Nice=10
IOSchedulingClass=idle
/etc/systemd/system/backup-s3.timer:
[Unit]
Description=Nightly backup to S3
[Timer]
OnCalendar=*-*-* 02:30:00
RandomizedDelaySec=15m
Persistent=true
[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable --now backup-s3.timer
systemctl list-timers backup-s3.timer
journalctl -u backup-s3 -n 50 # last run's log
Persistent=true runs a missed backup when the server comes back up. Add failure alerts (email, Telegram or a heartbeat service) so you do not discover three weeks later that backups stopped.
Step 5: Verify and test a restore
sudo bash -c 'source /etc/restic/env && restic snapshots'
sudo bash -c 'source /etc/restic/env && restic check --read-data-subset=5%'
# Restore one folder somewhere else, without touching live data
sudo bash -c 'source /etc/restic/env && restic restore latest --target /tmp/restore-test --include /var/www/example.com'
Every month or quarter, spin up a temporary VPS, install restic, restore everything and load the database dump. It is the only way to know you can come back after losing the server.
Protecting backups if the server is compromised
An attacker with root on the VPS also has its S3 key and can delete your backups. Layers that help:
- A key for one bucket only, as in step 1.
- Versioning or Object Lock on the bucket, where the provider supports it, with a lifecycle rule that removes old versions after N days. An overwritten or deleted object still has its previous version.
- Prune from somewhere else. The server only needs to write;
restic forget --prunecan run from another machine with a key that may delete. - A second copy with another provider for data that really matters.
Backing up a VPS to S3 with ZoPanel
ZoPanel has these steps built in. Remote backups to S3 need a Pro license.
- Open Settings → Remote backups, turn the switch on, pick one of the Provider presets (AWS, Cloudflare R2, Backblaze B2, Wasabi, MinIO and others) and fill in the endpoint, region, bucket, access key and secret key. Tick Path-style URLs (R2, MinIO) when your provider needs it.
- Set Remote copies to keep per account (1 to 365, default 14), click Test connection, then Save. From then on every account and database backup is uploaded when it finishes.
- Copies are encrypted on the server before upload with XChaCha20-Poly1305 and a key derived from the panel's recovery key. See it under Backups → Disaster recovery → Show key and keep it off the server.
- In the Incremental backups card, turn on nightly snapshots (01:00) of every account, choose S3 as the destination and set retention (7 daily, 4 weekly, 6 monthly by default). Every Saturday ZoPanel checks the repository and reads back 2% of the data; administrators get an alert if the check fails.
- Databases can also be backed up every hour, every 6 hours or daily, and those copies go to S3 too.
Restores are in the panel as well: bring back a whole account from S3 with Browse S3 (even from a server that no longer exists), or pick a snapshot and restore a single file, folder or mailbox. ZoPanel checks free disk space before a backup so it can never fill the disk, and every archive has a SHA-256 checksum that is verified before restoring. Customers can also set their own schedules and copy backups to their own S3 storage. Details are in Backups and Disaster recovery.
Mistakes that make backups useless
- Copying a running MariaDB data directory instead of dumping it: the files can be inconsistent and refuse to start.
- No encryption before upload: backups hold database passwords, keys and customer data.
- Losing the encryption password because it lived only on the server you lost.
- No failure alerts: the script breaks on an expired key or a full disk, and nobody notices.
- Keeping one copy: a problem found a week later is already in the only backup.
- Never testing a restore.
Conclusion
Backing up a VPS to S3 is one of the cheapest ways to protect your sites: one bucket, an encrypting tool such as restic, a timer, and the habit of testing restores. If you manage many sites or sell hosting, the hard part is doing that consistently for every account, with alerts and a fast way back. ZoPanel does that part for you; see pricing, start on the Free plan to try the on-server backup workflow, and turn on remote backups when you move to Pro.
Frequently asked questions
How much does it cost to back up a VPS to S3?
It depends on the volume and the provider. For example, at the time of writing Cloudflare R2 charges USD 0.015 per GB-month for standard storage, with the first 10 GB-month free and no egress fees. Because restic uploads only changes and compresses data, actual usage is usually far below your data size times the number of snapshots kept.
restic or rclone for S3 backups?
restic is a backup tool: encrypted, incremental, deduplicated, with snapshots and per-file restores. rclone is a sync and copy tool; it has a crypt layer but does not manage snapshots or retention. For server backups restic fits better; rclone is good for copying existing backup files to S3.
Do I need to stop websites during the backup?
No. mariadb-dump --single-transaction produces a consistent dump of InnoDB tables without locking the site, and restic reads files while websites keep running. Schedule backups for quiet hours and run them at low CPU and I/O priority.
How do I restore from S3 after losing the server?
Create a new VPS, install restic, restore the credentials and repository password, run restic restore latest --target /, reinstall the software and load the database dumps. With ZoPanel, install the panel on the new server, connect the same bucket, restore the configuration with the recovery key, then restore each account from Browse S3.
Can provider snapshots replace S3 backups?
Not entirely. Snapshots are great for a quick rollback before a big change, but they live with the same provider, often cannot restore single files, and may capture a database mid-write. Use them as an extra layer, not as your off-site copy.
Install ZoPanel free
One command on a fresh Ubuntu or Debian server. Up and running in minutes.
Install in 5 minutesKeep reading

Best VPS specs for WordPress: how much CPU, RAM and disk you need
The best VPS specs for WordPress for 1, 10 or 100 sites: how to size CPU, RAM and disk from your traffic, with real measurements and the mistakes to avoid.

How to install a LEMP stack on Ubuntu 24.04, step by step
Install a LEMP stack on Ubuntu 24.04 (and Debian 12): firewall, nginx, MariaDB, PHP-FPM, server blocks, Let's Encrypt SSL and per-site isolation done right.

How to protect a VPS from SSH brute force attacks
Protect a VPS from SSH brute force on Ubuntu or Debian: key-only login, Fail2ban, UFW rate limits, changing the port safely, and how not to lock yourself out.