VPS Snaps

How to back up a server with rclone to S3-compatible storage

rclone copies a server's files to S3-compatible storage and uploads only what changed. Use rclone copy if the backup should never lose a file, or rclone sync with --backup-dir to mirror the server while keeping everything sync would overwrite or delete. Install it from rclone.org rather than your distribution, test every command with --dry-run, and confirm the result with rclone check.

10 min readUpdated Checked against official documentation

Install a current rclone

The rclone docs warn that distribution packages "are often quite out of date". Ubuntu 24.04's apt offers 1.60.1, from November 2022; in October 2026 the current release is 1.75.1. The old build lacks the Linode and Hetzner S3 providers (added in 1.65 and 1.72) and every flag added since. Use the official script:

Terminal
sudo -v ; curl https://rclone.org/install.sh | sudo bash

It needs unzip, 7z or busybox, installs /usr/bin/rclone, and does nothing if the latest version is already there. sudo rclone selfupdate updates it later. Remove any distribution package first (sudo apt remove rclone) so the two never replace each other. Then check the version:

Terminal
rclone version

Connect an S3-compatible bucket

A remote is a named connection in rclone's config file. rclone config asks for settings interactively; rclone config create takes them as key=value pairs. This creates a remote called offsite for Cloudflare R2:

Terminal
rclone config create offsite s3 provider=Cloudflare access_key_id=YOUR_KEY_ID secret_access_key=YOUR_SECRET region=auto endpoint=https://ACCOUNT_ID.r2.cloudflarestorage.com acl=private no_check_bucket=true
  • s3 is the backend. Every S3-compatible service uses it.
  • provider applies that service's quirks. Use Other for a service rclone does not list.
  • region and endpoint say where the bucket lives. See the table below.
  • acl=private keeps uploaded objects private.
  • no_check_bucket=true stops rclone checking for, or creating, the bucket. Keys that cannot create buckets need it.
Storageproviderregionendpoint
AWS S3AWSThe bucket's region, such as us-east-1Leave empty
Cloudflare R2Cloudflareautohttps://ACCOUNT_ID.r2.cloudflarestorage.com
DigitalOcean SpacesDigitalOceanLeave emptynyc3.digitaloceanspaces.com (your region)
WasabiWasabiLeave emptys3.wasabisys.com
Backblaze B2, UpCloud and othersOtherAs the provider documentsThe S3 endpoint from the provider's dashboard

With env_auth=true instead of the two keys, rclone reads AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY from the environment, or uses the instance's IAM role on EC2, so no key sits in the config file.

Test the remote, then lock down the config file, which stores keys in plain text. rclone config file prints its path.

Terminal
rclone lsf offsite:my-bucket
Terminal
chmod 600 ~/.config/rclone/rclone.conf

copy, sync and move

All three skip files whose size and modification time match. They differ in what they delete.

CommandWhat it doesFor backups?
rclone copyUploads new and changed files. Never deletes anything at the destination.Yes. The safe default.
rclone syncMakes the destination match the source, deleting files the source no longer has.Yes, with --backup-dir.
rclone moveCopies, then deletes the source files.No.

rclone copies a directory's contents, like rsync with a trailing slash. rclone copy /var/www offsite:my-bucket/www puts /var/www/site/index.php at my-bucket/www/site/index.php; without /www on the destination it lands at my-bucket/site/index.php.

sync deletes. A file deleted by mistake, or a data volume that failed to mount, vanishes from the backup on the next run. rclone skips deletions if any error occurred, but an empty source is not an error. Give every sync a --backup-dir and a --max-delete limit.

To copy or mirror a whole bucket to another provider, including egress costs and checking the copy afterwards, see how to copy a bucket to another provider.

Keep changed and deleted files with --backup-dir

With --backup-dir, files that sync would overwrite or delete are moved into another directory instead, keeping their paths. Name it after the date and each run's old versions get their own folder:

Terminal
rclone sync /var/www offsite:my-bucket/server1/current/www --backup-dir offsite:my-bucket/server1/old/$(date +%F)/www --max-delete 500
  • --backup-dir must be on the same remote as the destination and must not be inside it. Here current/ and old/ sit side by side.
  • $(date +%F) expands to today's date, such as 2026-10-03.
  • --max-delete 500 stops the run with a fatal error if it would delete more than 500 files.

Bucket versioning also keeps old versions; --s3-versions shows them.

Do a dry run first

--dry-run (-n) lists every upload and deletion without changing anything. Run it before the first sync and after any change to paths or filters. -i asks before each destructive step instead.

Terminal
rclone sync /var/www offsite:my-bucket/server1/current/www --dry-run

Choose what to back up

--exclude skips matching paths and can be repeated. * matches within one path segment, ** matches across slashes, and a pattern starting with / only matches at the top of the source.

Terminal
rclone sync /var/www offsite:my-bucket/server1/current/www --exclude "*.log" --exclude "node_modules/**"

For more rules, use a filter file. - excludes, + includes, and the first matching rule wins, so a + line for one file placed above a - line for its directory keeps that file.

/etc/rclone/backup.filter
# rclone filter rules: the first match wins
- *.log
- *.tmp
- .git/**
- node_modules/**
- cache/**
Terminal
rclone sync /var/www offsite:my-bucket/server1/current/www --filter-from /etc/rclone/backup.filter

Do not combine --exclude, --include and --filter flags in one command; the docs warn the result may not be what you expect. Add -vv --dump filters to see how rclone reads your rules.

Three more flags matter on a server. -x stays on one filesystem. -M (--metadata) stores owner, group and permissions with each object so a restore can put them back. Symlinks are skipped unless you add -l, which stores each as a small .rclonelink file, or -L, which copies what they point to.

Speed and bandwidth

FlagDefaultWhat it does
--transfers N4Parallel uploads. Raise for many small files.
--checkers N8Parallel comparisons. Lower if storage times out.
--bwlimit 10MOffCaps bandwidth at 10 MiB/s. Bytes, not bits.
--fast-listOffFewer listing requests, more memory.
--checksumOffCompares MD5 instead of modification time. Saves an S3 request per file, but reads every local file.

--bwlimit also takes a timetable. This allows 512 KiB/s from 08:00 and full speed from 23:00:

Terminal
rclone sync /var/www offsite:my-bucket/server1/current/www --bwlimit "08:00,512k 23:00,off"

Encrypt backups with crypt

A crypt remote wraps another remote and encrypts file contents and names before upload, so the provider only sees scrambled data. Give it its own folder in the bucket:

Terminal
rclone config create secret crypt remote=offsite:my-bucket/server1-crypt password=YOUR-LONG-PASSPHRASE password2=YOUR-SECOND-PASSPHRASE --obscure

password2 is the salt, a second secret. --obscure makes sure both get obscured; without it, rclone can mistake a long base64 password for an already obscured one. To keep passphrases out of shell history, run rclone config and answer the prompts instead. Then use secret: like any remote:

Terminal
rclone sync /var/www secret:www --backup-dir secret:old/$(date +%F)/www

Lose the passphrase or the salt and nobody can decrypt the backup. Keep both off the server, in a password manager. The copy in rclone.conf is only lightly obscured: anyone who reads that file can decrypt your backups unless you encrypt the config itself (rclone config, then s).

Crypt does not hide file sizes or modification times, encrypted names over 143 characters can hit provider limits, and changing the passphrase means uploading everything again.

Verify the backup

rclone check compares sizes and MD5 hashes on both sides and reports files that differ or are missing. Use the backup's filters:

Terminal
rclone check /var/www offsite:my-bucket/server1/current/www --filter-from /etc/rclone/backup.filter
  • After copy, add --one-way to check only that every source file arrived.
  • --download compares the data itself instead of stored hashes.
  • For a crypt remote, use rclone cryptcheck /var/www secret:www.
  • Files that change during the check show as differences.

Only a restore proves the backup is usable; see how to test a backup restore.

Restore files

Copy in the other direction, into an empty directory first:

Terminal
rclone copy offsite:my-bucket/server1/current/www /srv/restore/www -M -P

-P shows progress. -M restores owner and permissions if the backup was made with -M; the docs warn against doing that as root from a source you do not trust. For one file, copyto writes to an exact path:

Terminal
rclone copyto offsite:my-bucket/server1/current/www/site/wp-config.php /tmp/wp-config.php

Older versions sit in the dated --backup-dir folders:

Terminal
rclone lsf offsite:my-bucket/server1/old/

S3 buckets cannot store empty directories, so check that upload and cache directories exist after a restore.

Run it from cron

This script backs up /etc and /var/www, keeps 30 days of changed and deleted files, and exits non-zero if a run fails.

/usr/local/bin/rclone-backup.sh
#!/usr/bin/env bash
set -euo pipefail

CONF=/root/.config/rclone/rclone.conf
DEST=offsite:my-bucket/server1
TODAY=$(date +%F)
CUTOFF=$(date -d "30 days ago" +%F)

for dir in etc var/www; do
  rclone sync "/$dir" "$DEST/current/$dir" \
    --config "$CONF" \
    --backup-dir "$DEST/old/$TODAY/$dir" \
    --filter-from /etc/rclone/backup.filter \
    --max-delete 500 \
    --fast-list \
    --log-file /var/log/rclone-backup.log --log-level INFO
done

# Remove backup-dir folders older than 30 days.
# old/ does not exist until a file has changed, so a failed listing is ignored.
for d in $(rclone lsf --dirs-only --config "$CONF" "$DEST/old" 2>/dev/null || true); do
  if [[ "${d%/}" < "$CUTOFF" ]]; then
    rclone purge --config "$CONF" "$DEST/old/${d%/}"
  fi
done
Terminal
sudo chmod 700 /usr/local/bin/rclone-backup.sh
/etc/cron.d/rclone-backup
30 3 * * * root flock -n /run/rclone-backup.lock /usr/local/bin/rclone-backup.sh >> /var/log/rclone-backup.log 2>&1
  • --config names the config file, so cron finds it even if you created the remote as another user.
  • flock -n skips a run while the previous one is still going.
  • --log-file appends. Rotate it with logrotate's copytruncate; rclone cannot reopen its log.
  • $(date +%F) is fine in a script. Written directly in a crontab line, every % must be escaped as \%.

rclone retries a failed run three times (--retries), then exits with a code that says what went wrong. More on scheduling in how to schedule backups with cron.

Exit codeMeaning
0Success
1Error not otherwise categorized
2Syntax or usage error
3Directory not found
4File not found
5Temporary error that more retries might fix
6Less serious errors
7Fatal error, such as a suspended account
8--max-transfer limit reached
9Nothing transferred (only with --error-on-no-transfer)
10--max-duration limit reached

You do not need mount or serve

rclone mount shows a bucket as a local filesystem, and rclone serve shares a remote over HTTP, SFTP, WebDAV and more. Neither helps here. The rclone docs explain that sync and copy survive unreliable storage by retrying, which a mount cannot do the same way.

Common errors

Error or symptomFix
Config file "rclone.conf" not found or didn't find section in config filerclone is reading another config, usually because cron runs as a different user. Pass --config with the full path.
AccessDenied although the key can write objectsThe key cannot check or create buckets. Set no_check_bucket=true or pass --s3-no-check-bucket.
x509: certificate signed by unknown authorityInstall ca-certificates and check the clock.
Restored files have the wrong owner or modeBack up and restore with -M.
Sync stops at the delete limit--max-delete did its job. Check the source is mounted and complete.
rclone refuses to run because paths overlap--backup-dir sits inside the destination, or the destination inside the source. Make them siblings.

rclone copies files as they are. For deduplicated, versioned backups of a whole server, see restic or BorgBackup.

Frequently asked questions

Is rclone sync safe for backups?
Only with a safety net. sync deletes destination files that are gone from the source, so a mistaken delete reaches the backup. Add --backup-dir and --max-delete.
What is the difference between rclone copy and rclone sync?
copy adds and updates files at the destination and never deletes. sync also deletes destination files that no longer exist in the source.
Does rclone keep file permissions and ownership?
Not by default. Add -M (--metadata) when backing up and restoring; on S3 they are stored as object metadata.
Can rclone encrypt backups?
Yes. A crypt remote encrypts contents and names before upload with a passphrase only you hold. Lose it and the data is unrecoverable.
Should I install rclone with apt?
Better not. Ubuntu 24.04 ships 1.60.1 from 2022. The official script installs the current release, and rclone selfupdate keeps it current.

How this was checked

Commands, limits and prices were checked against these official pages, on October 3, 2026: