Backups & DataGrid Pulsar team··11 min read

DIY VPS Backups Without Paying Your Host for Them

Back up an Ubuntu VPS with Restic to S3 or Google Drive. Set up encryption, scheduled snapshots, retention, and a restore drill before you need recovery.

DIY VPS Backups Without Paying Your Host for Them featured image
On this page
Short answer

Your VPS disappears, and the backup archive was on the same disk. Fix that by sending encrypted Restic snapshots to storage outside your hosting account. Use S3-compatible storage by default, or Google Drive through rclone. Back up application data and database-consistent exports, schedule the job, monitor missed runs, and restore onto a separate machine. You avoid the host's backup add-on, but storage and recovery still need a budget.

Choose what must survive losing the VPS

Your server stops booting, and the archive you need sits inside its inaccessible filesystem. Put the recovery copy outside the VPS and outside the hosting account that controls it. A local archive can help undo a mistake, but it cannot recover a server whose disk is gone.

This procedure targets Ubuntu 24.04 LTS on a single VPS. We recommend Restic for encrypted snapshots, with S3-compatible object storage as the default destination. Google Drive through rclone is a reasonable alternative when you already manage a suitable Drive account and accept the extra authentication dependency.

DestinationChoose it whenOperational responsibility
S3-compatible object storageYou want bucket-scoped credentials and direct Restic accessManage storage permissions and understand recovery transfer charges
Google Drive through rcloneYou already maintain a suitable Drive accountMonitor storage quota and keep OAuth authorization working
Another directory on the VPSYou need temporary stagingIt does not survive losing the VPS

Write down how much recent work you can lose and how long the application can remain unavailable. Those decisions determine the backup schedule and the recovery procedure. A nightly file backup cannot satisfy an application that needs recovery close to the moment of failure.

  • Include user uploads and other application files that cannot be recreated from source control.
  • Include database-consistent exports or a database-native backup set, with the credentials and roles needed for recovery.
  • Include system configuration and an off-server recovery note explaining how to rebuild the application.
  • Exclude disposable build output and caches unless they are expensive enough to justify retaining.

The examples use /srv/app-data for persistent application files and /var/backups/app for prepared database exports. Replace these paths with your actual sources before taking the first snapshot; creating an empty directory does not protect an application stored elsewhere. If you are still choosing a backup engine, use the Restic, Borg and Kopia comparison before committing to a repository.

Install the tools and protect the recovery password

Install the distribution packages and create a private configuration directory. Restic encrypts the repository, so losing its password can make an otherwise intact backup unusable. Keep that password in an independent password manager, together with the repository address and instructions for recovering the storage account.

bashTested on Ubuntu 24.04
sudo apt-get update
sudo env DEBIAN_FRONTEND=noninteractive apt-get install -y restic rclone openssl ca-certificates
sudo install -d -m 0700 /etc/vps-backup /var/cache/vps-backup /var/backups/app
sudo install -d -m 0750 /srv/app-data
sudo bash -c 'set -e; umask 077; if [ ! -s /etc/vps-backup/password ]; then openssl rand -base64 32 > /etc/vps-backup/password; fi'
command -v restic
command -v rclone
sudo stat -c '%a %U %n' /etc/vps-backup /etc/vps-backup/password
Check: Both executables have paths. The private directory belongs to root with mode 700, and the password file belongs to root with mode 600.

Transfer the password into your password manager through a trusted private session before initializing the repository. Do not paste it into an issue, agent conversation, or shared terminal transcript. A password stored only on the protected VPS disappears with the machine.

The backup job will run as root because system configuration and application exports can have restricted permissions. Keep its scripts root-owned and unavailable for modification by the application account. Apply the Ubuntu server hardening checklist alongside this setup, because encryption does not stop a compromised server from using credentials it can already read.

Connect either S3 storage or Google Drive

Choose one destination for this repository. Restic supports S3 storage directly and Google Drive through its rclone backend; the address formats differ. The official repository setup documentation describes both backends and their authentication settings.

For S3-compatible storage, create a private bucket in an account separate from your VPS provider account. Give the backup credential access only to that bucket or repository prefix, including listing, reading, writing, and deletion required by normal repository maintenance. Do not grant account administration or permission to remove the bucket.

Save the following S3 template as /etc/vps-backup/repository.env, replacing the example endpoint, bucket and credentials with values from your storage account. Use the bucket's actual HTTPS endpoint and add AWS_DEFAULT_REGION if your provider requires it. This is a configuration template, so the example values will not connect to storage.

conf
RESTIC_REPOSITORY='s3:https://s3.example.com/vps-archive/restic'
RESTIC_PASSWORD_FILE='/etc/vps-backup/password'
RESTIC_CACHE_DIR='/var/cache/vps-backup'
AWS_ACCESS_KEY_ID='REPLACE_WITH_BUCKET_ACCESS_KEY'
AWS_SECRET_ACCESS_KEY='REPLACE_WITH_BUCKET_SECRET_KEY'

For Google Drive instead, configure a remote named gdrive using the command below. Select Google Drive and complete the browser authorization flow; on a headless VPS, follow the prompt to authorize from a machine with a browser. Keep the resulting token private, and consult the rclone Google Drive documentation for scope and authorization details.

bash
sudo rclone config --config /etc/vps-backup/rclone.conf
sudo chmod 0600 /etc/vps-backup/rclone.conf
sudo rclone --config /etc/vps-backup/rclone.conf lsd gdrive:
Check: The Drive listing completes without an authentication error. An empty account can return no directory entries and still succeed.

Prefer a dedicated backup account if granting full Drive access. A folder name alone does not restrict what an OAuth token can access. Save this alternative as /etc/vps-backup/repository.env when using Drive, replacing the S3 template entirely.

conf
RESTIC_REPOSITORY='rclone:gdrive:vps-backups/primary'
RESTIC_PASSWORD_FILE='/etc/vps-backup/password'
RESTIC_CACHE_DIR='/var/cache/vps-backup'
RCLONE_CONFIG='/etc/vps-backup/rclone.conf'

Both choices leave the running VPS with credentials that can damage its backup repository. For protection against that failure, maintain an independently controlled copy or a provider-supported recovery mechanism whose deletion authority is unavailable to the VPS. Do not enable bucket expiration rules that remove live repository objects.

Prepare consistent data and install the backup scripts

Create /usr/local/sbin/vps-restic with the following contents. This wrapper gives interactive commands and the scheduled job the same configuration. Its environment file is sourced as shell code, so only root should be able to edit it.

bash
#!/bin/bash
set -euo pipefail
export PATH=/usr/sbin:/usr/bin:/sbin:/bin
set -a
. /etc/vps-backup/repository.env
set +a
exec /usr/bin/restic "$@"

Do not treat a copy of a running database directory as a recoverable database backup. Prepare a native export before Restic reads the files, and make export failure stop the job. The Postgres backup and restore procedure covers database-specific recovery requirements.

If this VPS runs a database, create an executable /etc/vps-backup/prepare-data script that produces fresh exports in /var/backups/app. Write each export to a temporary file and rename it into place only after the database tool succeeds; return a failing exit status on any error. Back up required roles separately, and do not enable the schedule until you have restored these exports successfully.

Create /usr/local/sbin/vps-backup with the following contents, adjusting the source paths. Set database_required=true if recovery depends on a database, which makes a missing preparation script fail visibly. For applications whose database records refer to uploaded files, coordinate exports and file capture with the application's supported consistency procedure, potentially including a maintenance window.

bash
#!/bin/bash
set -euo pipefail
export PATH=/usr/sbin:/usr/bin:/sbin:/bin
database_required=false
prepare=/etc/vps-backup/prepare-data
if [[ "$database_required" == true && ! -x "$prepare" ]]; then
  printf '%s\n' 'Database preparation script is required.' >&2
  exit 1
fi
if [[ -x "$prepare" ]]; then
  "$prepare"
fi
exec /usr/local/sbin/vps-restic backup \
  --host vps-primary \
  --tag production \
  --exclude /etc/vps-backup \
  /etc /srv/app-data /var/backups/app
bash
sudo chown root:root /etc/vps-backup/repository.env /usr/local/sbin/vps-restic /usr/local/sbin/vps-backup
sudo chmod 0600 /etc/vps-backup/repository.env
sudo chmod 0700 /usr/local/sbin/vps-restic /usr/local/sbin/vps-backup
sudo bash -n /usr/local/sbin/vps-restic
sudo bash -n /usr/local/sbin/vps-backup
Check: Both syntax checks exit successfully without output. If the application uses a database, its preparation script must also complete and produce exports that you can restore.

The backup excludes /etc/vps-backup deliberately because it contains repository credentials. Keep a protected off-server copy of its recovery information and script configuration. Otherwise, a replacement machine will lack the instructions needed to open the repository.

Initialize the repository and inspect the first snapshot

Initialize only a new repository, then run the same backup script that the scheduler will use. If you are reconnecting to an existing repository, skip initialization and list its snapshots first. Allow enough local space for database staging as well as Restic's cache.

bash
sudo /usr/local/sbin/vps-restic init
sudo /usr/local/sbin/vps-backup
sudo /usr/local/sbin/vps-restic snapshots --host vps-primary --tag production
sudo /usr/local/sbin/vps-restic ls latest --host vps-primary --tag production
Check: The backup exits successfully, the snapshot listing contains a fresh production snapshot, and its file listing includes actual application data. An empty application directory or missing database export is a failed coverage check even when the upload succeeded.

Inspect representative paths from every source you intended to protect. Pay particular attention to container volumes and application secrets stored outside /etc, because these examples will not discover them automatically. Add their real locations to the script, excluding live database files when using native exports.

Treat an incomplete backup or unreadable source as a failure requiring investigation. A repository can contain a new snapshot even when the command reports a problem, so a recent timestamp alone is insufficient. Record the expected source paths in the recovery note and review them whenever you change deployment layout.

Schedule the job and make missed backups visible

Use a systemd timer so you can inspect the schedule and job result with the server's normal service tools. Save the following service as /etc/systemd/system/vps-backup.service. Keep database preparation inside the backup script so its failure prevents a successful service result.

ini
[Unit]
Description=Encrypted off-server backup
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
User=root
UMask=0077
ExecStart=/usr/local/sbin/vps-backup
Nice=10
TimeoutStartSec=infinity

Save this timer as /etc/systemd/system/vps-backup.timer. The schedule uses the server's local timezone, and persistence allows a missed calendar activation to run after the machine returns. Change the frequency if your acceptable data-loss window is shorter than the interval shown.

ini
[Unit]
Description=Schedule encrypted off-server backups

[Timer]
OnCalendar=*-*-* 03:00:00
RandomizedDelaySec=20m
Persistent=true
Unit=vps-backup.service

[Install]
WantedBy=timers.target
bash
sudo systemctl daemon-reload
sudo systemctl start vps-backup.service
sudo systemctl enable --now vps-backup.timer
sudo systemctl show vps-backup.service -p Result -p ExecMainStatus
sudo systemctl list-timers vps-backup.timer --no-pager
sudo journalctl -u vps-backup.service -n 50 --no-pager
Check: The service reports Result=success and ExecMainStatus=0, the timer has a next activation, and the journal records a completed backup. The service being inactive after completion is normal for a oneshot job.

Configure an external monitor to expect a success signal after the backup command completes successfully. Have it alert when that signal is late, allowing for normal backup duration and the randomized delay. An alert generated only on the VPS cannot tell you that the entire VPS has disappeared.

Deliberately withhold a monitoring signal and confirm that the alert reaches you before relying on it. Also inspect destination quota and repository growth during routine maintenance. We would give Claude Code redacted service logs to investigate a failed run, while keeping storage credentials and deletion authority outside its session; the AI operations guardrail guide explains that division of responsibility.

Preview retention before deleting recovery points

Keep enough history to recover from damage discovered after the next backup has already run. A useful starting policy retains daily snapshots for recent mistakes and longer-spaced snapshots for older problems. Adjust it to your data churn and how long corruption could remain unnoticed.

bash
sudo /usr/local/sbin/vps-restic forget \
  --host vps-primary --tag production \
  --group-by host,paths,tags \
  --keep-daily 14 --keep-weekly 8 --keep-monthly 12 \
  --dry-run
Check: The preview identifies snapshots to retain and remove without deleting them. Check that every group refers to the intended host, source paths and production tag.

Restic applies retention within snapshot groups, and retained categories can overlap. forget removes snapshot references, while prune reclaims data no retained snapshot needs. Review the official retention documentation before applying a policy or changing grouping.

After a successful restore drill, run the following deletion command during a maintenance window with no backup active. Keep this manual initially so an incorrect policy cannot repeatedly remove history unattended. Do not disable repository locking to force overlapping jobs through.

bash
sudo /usr/local/sbin/vps-restic forget \
  --host vps-primary --tag production \
  --group-by host,paths,tags \
  --keep-daily 14 --keep-weekly 8 --keep-monthly 12 \
  --prune

Storage-side version history and deleted-file retention can keep consuming space after Restic prunes. Check the provider's accounting instead of assuming repository cleanup immediately releases all storage. Keep storage lifecycle policies from expiring objects that still belong to the active repository.

Restore on a replacement machine and book the next drill

Provision a separate recovery machine and install the same tools there. Recreate the root-only wrapper and repository configuration using your off-server recovery information, then obtain the password from your password manager. Do not copy credentials from the original VPS during this drill, because the exercise must work when that machine is unavailable.

Run the following commands on the recovery machine with enough free disk space for the restored files. The repository check reads stored data, which can incur transfer charges and take time. The restore target is a new private directory, keeping recovered configuration separate from the replacement machine's active configuration.

bash
sudo /usr/local/sbin/vps-restic snapshots --host vps-primary --tag production
sudo /usr/local/sbin/vps-restic check --read-data
restore_dir=$(sudo mktemp -d /var/tmp/vps-restore.XXXXXX)
sudo /usr/local/sbin/vps-restic restore latest \
  --host vps-primary --tag production \
  --target "$restore_dir"
sudo ls -la "$restore_dir/srv/app-data"
sudo ls -la "$restore_dir/var/backups/app"
Check: The repository check and restore both exit successfully, and the destination contains the expected application files and database exports. Open representative recovered files rather than checking names alone.

The Restic restore documentation explains snapshot selection and target paths. For this initial drill, latest is convenient; during an incident, select a known-good snapshot from before the damage. Never restore the saved /etc tree directly over a running replacement server without reviewing its contents.

Import the database into an isolated instance and start the application with restored data. Disable outbound mail, payment actions and background jobs that could affect real users. Check an application operation that reads both database records and uploaded files, since successful decryption alone does not establish application consistency.

Record the elapsed recovery time and every missing dependency in the off-server recovery note. Fix those gaps, then create a recurring calendar task for another restore drill and repeat it after substantial storage or deployment changes. Your next action is to book that drill with a named owner and a specific date.

FAQ

What is a good VPS backup tool for a small server?

We recommend Restic when you want encrypted file snapshots and a choice of off-server destinations. Its command-line workflow fits scheduled Linux jobs without needing a separate management server. The deciding factor is whether you can operate its recovery process: identify persistent data, capture databases consistently, preserve credentials independently, and restore the application when the original VPS is unavailable.

Can I back up a VPS to Google Drive?

Yes. Configure Google Drive as an rclone remote, then let Restic use that remote as its repository backend. Keep Restic responsible for snapshot history instead of relying on a plain synchronized folder. Drive account access, OAuth authorization and available storage become backup dependencies, so include them in monitoring and prove that your recovery machine can authenticate independently.

How do I back up a VPS to S3?

Create a private bucket, obtain credentials scoped to its backup contents, and configure Restic with the provider's endpoint and your repository password. Initialize the repository before uploading snapshots. Keep account administration separate from the server credential, and understand which permissions allow deletion. Recovery also depends on retaining account access when the hosting account or original machine is unavailable.

Are host snapshots enough for VPS backups?

Host snapshots can be useful for rollback, particularly before a risky system change. Their recovery value depends on where they are stored, how they are protected, and whether you can access them after losing the hosting account. Keep an independent copy of irreplaceable data and use a database-supported consistency method rather than assuming a disk snapshot captures every application correctly.

Can I back up a running database with Restic?

Restic can store database exports or database-native backup files, but copying an actively changing database directory is not a substitute for the database's backup procedure. Make the native backup complete successfully before file capture begins. Restore it into an isolated database during drills, including required roles and extensions, and coordinate uploaded files if their contents must match database records.

Can I make VPS backups without paying for storage?

You may be able to use storage already included in an account you maintain, but that does not remove capacity limits or operational work. Budget for growing history and the possibility of downloading the entire repository during recovery. Compare the full arrangement with the host's add-on, including your time maintaining credentials, checking failed jobs and practicing restores.

Free ebook

Put this guide in the bigger picture

See how this topic connects to the rest of your product. Our free field guide explains apps, infrastructure and AI, with checklists to help you make business decisions.

We use cookies to ensure that we give you the best experience on our website. If you continue to use this site we will assume that you are happy with it.