Rested
All guides
8 min read

How to automate VPS backups with cron and restic

Step-by-step: set up automated, encrypted VPS backups with restic and cron — repository setup, a backup script, scheduling, retention, and monitoring for failures.

Install restic and create the repository

restic is a single binary and ships in most distro repositories (apt install restic, dnf install restic). Back up to object storage in a different failure domain than the VPS — any S3-compatible bucket. Put the secrets in a root-only environment file so they never appear in cron logs or process listings. If you lose RESTIC_PASSWORD the backups are unrecoverable, so store it in a password manager, not just on the VPS you are protecting.

sudo install -m 600 /dev/null /etc/restic/env
sudo tee /etc/restic/env >/dev/null <<'EOF'
export RESTIC_REPOSITORY="s3:https://s3.example.com/my-vps-backups"
export RESTIC_PASSWORD="a-long-random-passphrase"
export AWS_ACCESS_KEY_ID="..."
export AWS_SECRET_ACCESS_KEY="..."
EOF

sudo bash -c 'source /etc/restic/env && restic init'

Write the backup script

The script sources the secrets, backs up the paths you care about, applies a retention policy, and prunes. Backing up /etc, your app directory, and a fresh database dump covers most single-server apps.

#!/usr/bin/env bash
set -euo pipefail
source /etc/restic/env

# Optional: dump a database first so the backup is consistent
# pg_dump -Fc -d myapp -f /var/backups/myapp.dump

restic backup /etc /srv/myapp /var/backups --tag automated --host "$(hostname)"
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune

Schedule it with cron

Run it nightly from root's crontab (sudo crontab -e) and redirect output to a log so a failure leaves a trace. Prefer systemd? A timer with OnCalendar=*-*-* 02:30:00 gives the same schedule plus journalctl logging and systemctl list-timers visibility.

# Nightly at 02:30
30 2 * * * /usr/local/sbin/vps-backup >> /var/log/vps-backup.log 2>&1

Monitor failures and test restores

Cron keeps running a failing job without reporting it, so automation needs two safeguards. Monitor failures by sending the exit status to a healthcheck or ping service, or by alerting on a non-zero exit. And test restores on a schedule by restoring into a scratch directory and checking the contents.

source /etc/restic/env
restic snapshots
restic restore latest --target /tmp/restore-check

Common pitfalls

Most broken cron backups come from a few recurring mistakes.

  • Secrets in the crontab — keep them in the root-only env file, not inline.
  • No retention — without forget --prune the repository grows until the bucket bill hurts.
  • Silent failures — a cron job with no monitoring is a backup you will discover is broken during a restore.
  • Backing up to the same VPS — that violates 3-2-1; the off-site copy is the whole point.

When you outgrow cron

One server and one cron line is fine. Across several servers, the cron-and-grep approach stops scaling: you cannot easily see which hosts ran, which failed, or how old your newest recovery point is. That is what Rested provides on top of the same restic engine — schedules, run history, failure alerts, and restores across every server from one place, with your encryption key kept by you.

Related from Rested

Common questions

Frequently asked questions

How do I automate restic backups with cron?

Store your restic environment in a root-only file, write a small script that runs restic backup followed by restic forget --prune, and schedule it from root's crontab (for example nightly at 02:30), redirecting output to a log.

How do I keep restic credentials out of cron logs?

Put RESTIC_REPOSITORY, RESTIC_PASSWORD, and storage keys in a file such as /etc/restic/env with 0600 permissions, and source it inside the backup script rather than putting secrets in the crontab line.

Should I use cron or a systemd timer?

Either works. A systemd timer adds journalctl logging and systemctl list-timers visibility, which makes failures easier to notice than plain cron output.