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.
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:
sudo -v ; curl https://rclone.org/install.sh | sudo bashIt 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:
rclone versionConnect 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:
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=trues3is the backend. Every S3-compatible service uses it.providerapplies that service's quirks. UseOtherfor a service rclone does not list.regionandendpointsay where the bucket lives. See the table below.acl=privatekeeps uploaded objects private.no_check_bucket=truestops rclone checking for, or creating, the bucket. Keys that cannot create buckets need it.
| Storage | provider | region | endpoint |
|---|---|---|---|
| AWS S3 | AWS | The bucket's region, such as us-east-1 | Leave empty |
| Cloudflare R2 | Cloudflare | auto | https://ACCOUNT_ID.r2.cloudflarestorage.com |
| DigitalOcean Spaces | DigitalOcean | Leave empty | nyc3.digitaloceanspaces.com (your region) |
| Wasabi | Wasabi | Leave empty | s3.wasabisys.com |
| Backblaze B2, UpCloud and others | Other | As the provider documents | The 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.
rclone lsf offsite:my-bucketchmod 600 ~/.config/rclone/rclone.confcopy, sync and move
All three skip files whose size and modification time match. They differ in what they delete.
| Command | What it does | For backups? |
|---|---|---|
rclone copy | Uploads new and changed files. Never deletes anything at the destination. | Yes. The safe default. |
rclone sync | Makes the destination match the source, deleting files the source no longer has. | Yes, with --backup-dir. |
rclone move | Copies, 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:
rclone sync /var/www offsite:my-bucket/server1/current/www --backup-dir offsite:my-bucket/server1/old/$(date +%F)/www --max-delete 500--backup-dirmust be on the same remote as the destination and must not be inside it. Herecurrent/andold/sit side by side.$(date +%F)expands to today's date, such as2026-10-03.--max-delete 500stops 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.
rclone sync /var/www offsite:my-bucket/server1/current/www --dry-runChoose 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.
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.
# rclone filter rules: the first match wins
- *.log
- *.tmp
- .git/**
- node_modules/**
- cache/**rclone sync /var/www offsite:my-bucket/server1/current/www --filter-from /etc/rclone/backup.filterDo 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
| Flag | Default | What it does |
|---|---|---|
--transfers N | 4 | Parallel uploads. Raise for many small files. |
--checkers N | 8 | Parallel comparisons. Lower if storage times out. |
--bwlimit 10M | Off | Caps bandwidth at 10 MiB/s. Bytes, not bits. |
--fast-list | Off | Fewer listing requests, more memory. |
--checksum | Off | Compares 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:
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:
rclone config create secret crypt remote=offsite:my-bucket/server1-crypt password=YOUR-LONG-PASSPHRASE password2=YOUR-SECOND-PASSPHRASE --obscurepassword2 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:
rclone sync /var/www secret:www --backup-dir secret:old/$(date +%F)/wwwLose 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:
rclone check /var/www offsite:my-bucket/server1/current/www --filter-from /etc/rclone/backup.filter- After
copy, add--one-wayto check only that every source file arrived. --downloadcompares 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:
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:
rclone copyto offsite:my-bucket/server1/current/www/site/wp-config.php /tmp/wp-config.phpOlder versions sit in the dated --backup-dir folders:
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/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
donesudo chmod 700 /usr/local/bin/rclone-backup.sh30 3 * * * root flock -n /run/rclone-backup.lock /usr/local/bin/rclone-backup.sh >> /var/log/rclone-backup.log 2>&1--confignames the config file, so cron finds it even if you created the remote as another user.flock -nskips a run while the previous one is still going.--log-fileappends. Rotate it with logrotate'scopytruncate; 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 code | Meaning |
|---|---|
| 0 | Success |
| 1 | Error not otherwise categorized |
| 2 | Syntax or usage error |
| 3 | Directory not found |
| 4 | File not found |
| 5 | Temporary error that more retries might fix |
| 6 | Less serious errors |
| 7 | Fatal error, such as a suspended account |
| 8 | --max-transfer limit reached |
| 9 | Nothing 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 symptom | Fix |
|---|---|
Config file "rclone.conf" not found or didn't find section in config file | rclone is reading another config, usually because cron runs as a different user. Pass --config with the full path. |
AccessDenied although the key can write objects | The key cannot check or create buckets. Set no_check_bucket=true or pass --s3-no-check-bucket. |
x509: certificate signed by unknown authority | Install ca-certificates and check the clock. |
| Restored files have the wrong owner or mode | Back 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: