Loading...

Storage · 12 min read

rclone: copy, sync and migrate files between clouds

rclone is a free command-line tool that copies, syncs and moves files between your disk and more than 70 cloud storage services, or directly from one cloud to another. You describe each storage account once as a named remote in rclone config, then use the same commands against all of them. This guide covers installation, remotes, the core commands, the flags that matter, S3 migrations, verification and scheduling.

Updated

rclone: copy, sync and migrate files between clouds

What rclone is, and what it is good at

rclone is a free, open-source command-line program for copying, syncing and moving files between your disk and cloud storage, or between two clouds. It is often called "rsync for cloud storage": one binary, written in Go, that speaks more than 70 storage backends, including Amazon S3 and every S3-compatible service, Google Drive, OneDrive, Dropbox, Azure Blob, Backblaze B2, SFTP and WebDAV.

The idea that makes it useful is the remote. You describe each storage account once, give it a short name such as s3old or gdrive, and from then on every command works the same way against any of them: rclone copy ./backups s3old:my-bucket/backups reads exactly like rclone copy gdrive:Photos ./photos. A path is remote:path, and for object storage the first part of the path is the bucket.

In practice rclone is used for four jobs: nightly backups to object storage, one-off migrations from one provider to another, pulling files out of Google Drive or other consumer clouds, and mounting a bucket as if it were a local folder. It compares files before transferring them, so a second run only sends what changed, retries failed operations, and can encrypt everything on the client before it leaves the machine.

What it is not: a two-way sync client like the Dropbox app (the newer bisync command exists, but it is a deliberate tool, not a background service), or a backup program with deduplicated snapshots. For versioned, deduplicated backups, tools such as restic use rclone as a transport underneath.

Installing rclone on Linux, macOS and Windows

rclone is a single executable with no dependencies, so installing it is mostly a question of where the binary comes from. Distribution packages (apt install rclone) are often several releases behind; for anything that talks to current cloud APIs, prefer the official build.

Linux and macOS: the project's install script downloads the latest release for your platform and puts it in /usr/bin (or /usr/local/bin on macOS). On macOS, Homebrew works too, but the Homebrew build cannot run rclone mount; if you need mounting, use the official binary together with macFUSE.

Windows: winget install Rclone.Rclone is the quickest way; Scoop and Chocolatey also carry it. Without a package manager, download the zip from rclone.org/downloads, unpack rclone.exe into a folder such as C:\rclone, and add that folder to your PATH. Run it from PowerShell or cmd; it has no installer and no GUI of its own. To use rclone mount on Windows you also need WinFsp.

Check the result with rclone version. A binary installed from the official build can update itself later with rclone selfupdate; a packaged one should be updated through its package manager.

Install and check rclone
# Linux / macOS: official install script
sudo -v ; curl https://rclone.org/install.sh | sudo bash

# macOS with Homebrew (no rclone mount support)
brew install rclone

# Windows (PowerShell)
winget install Rclone.Rclone

# everywhere
rclone version

rclone config and the remote concept

rclone config starts an interactive wizard: n for a new remote, a name, the storage type, then the questions that type needs (keys, endpoint, region, or a browser login for Google Drive and other OAuth services). The answers are written to a plain INI file, rclone.conf. rclone config file prints where it is: usually ~/.config/rclone/rclone.conf on Linux and macOS, and %APPDATA%\rclone\rclone.conf on Windows.

Because it is an ordinary text file, you can also write remotes by hand, copy the file to a server, or keep it in your secrets tooling. Treat it as a secret: it holds access keys and OAuth tokens. Secrets that rclone itself writes are only obscured, not encrypted; rclone config offers a configuration password if the file has to sit on a shared machine.

Each [section] is one remote. You then address it as name: followed by a path. With object storage, name: alone means the account, name:bucket a bucket and name:bucket/prefix a "folder" inside it. rclone lsd name: is the quickest test that the keys and endpoint work.

The file is not the only way. Every option can come from an environment variable named RCLONE_CONFIG_<REMOTE>_<OPTION>, which suits containers and CI where you would rather inject secrets than ship a config file.

Two remotes in rclone.conf: AWS S3 and Google Drive

[s3old]
type = s3
provider = AWS
access_key_id = AKIA...
secret_access_key = ...
region = eu-central-1

[gdrive]
type = drive
scope = drive.readonly
token = {"access_token":"...","expiry":"..."}

# the same S3 remote from environment variables instead
# RCLONE_CONFIG_S3OLD_TYPE=s3
# RCLONE_CONFIG_S3OLD_PROVIDER=AWS
# RCLONE_CONFIG_S3OLD_ACCESS_KEY_ID=AKIA...

The core commands, and copy vs sync

rclone copy copies files from source to destination and skips files that are already identical there. It never deletes anything at the destination, which makes it the safe default.

rclone sync makes the destination identical to the source, and that includes deleting destination files that are not in the source. Point it at the wrong folder, or swap source and destination, and it will remove data, and object storage has no recycle bin unless versioning is on. Always run a new sync command with --dry-run first, read what it would delete, and only then run it for real. --max-delete 100 is a useful seatbelt for scheduled jobs: the run stops instead of deleting more than that.

rclone move copies and then deletes each file from the source once it has arrived; add --delete-empty-src-dirs to clean up the folders as well. rclone check compares source and destination and reports differences without changing anything (more on it below).

For looking around: rclone lsd remote: lists buckets or directories, rclone ls remote:bucket lists every object with its size, rclone lsf gives a script-friendly list, and rclone size remote:bucket prints the object count and total bytes, which is the first number to compare after a migration. rclone tree and rclone ncdu help when you need to see where the space goes.

One behaviour trips up almost everyone: like rsync with a trailing slash, rclone copies the contents of the source directory, not the directory itself. rclone copy ./photos remote:bucket puts the files at the bucket root; write remote:bucket/photos if you want the folder. To copy or rename a single file, use copyto or moveto.

Everyday commands
rclone lsd s3old:                       # buckets this key can see
rclone ls s3old:media/2026/             # objects and sizes
rclone size s3old:media                 # count + total bytes

rclone copy ./site s3old:media/site -P  # upload, never deletes
rclone sync ./site s3old:media/site --dry-run   # preview first
rclone sync ./site s3old:media/site -P  # then for real

rclone move ./outbox s3old:media/inbox --delete-empty-src-dirs
rclone copyto ./logo.png s3old:media/img/logo-v2.png

Flags that matter: dry runs, speed and bandwidth

--dry-run (-n) shows what would be copied or deleted without touching anything. --interactive (-i) asks before each destructive action, which is handy for a one-off cleanup.

--progress (-P) shows live throughput, counts and ETA. For jobs that run unattended, use --log-file rclone.log --log-level INFO instead, so you can read afterwards what happened.

--transfers (default 4) is how many files move in parallel, and --checkers (default 8) how many comparisons run in parallel. Object storage is slow per request and fast in aggregate, so many small files benefit from --transfers 16 to 32 and --checkers 32 or more. Raise them gradually: providers rate-limit, and too many parallel requests turn into retries.

--bwlimit caps bandwidth, for example --bwlimit 20M (bytes per second, so 20 MiB/s), or a timetable such as --bwlimit "08:00,10M 19:00,off" that throttles during office hours and runs free at night.

--s3-chunk-size (default 5 MiB) sets the part size of multipart uploads, and --s3-upload-concurrency (default 4) how many parts of one file upload at the same time. For large files on a fast link, --s3-chunk-size 64M cuts the number of requests considerably. Memory use grows with transfers × upload-concurrency × chunk-size, so a 64 MiB chunk with 16 transfers can take several gigabytes of RAM. S3 allows at most 10,000 parts per object; rclone raises the chunk size by itself when it knows a file's size, but not for streamed uploads (rcat).

For buckets with millions of objects, --fast-list lists the whole bucket in fewer requests at the cost of memory, and --checksum or --size-only stop rclone from reading each object's modification time, which on S3 costs an extra request per object.

A tuned upload of a large backup directory
rclone copy /srv/backups s3old:backups/db \
  --transfers 16 --checkers 32 \
  --s3-chunk-size 64M --s3-upload-concurrency 4 \
  --bwlimit "08:00,20M 20:00,off" \
  --log-file /var/log/rclone-backup.log --log-level INFO

Configuring an S3-compatible remote, with CDN.com.tr as the example

Any service that implements the S3 API uses rclone's s3 type. The fields that change from provider to provider are provider, endpoint and sometimes region. Use the named provider when rclone has one (AWS, Cloudflare, Minio, Wasabi and others); it switches on that service's quirks. For a service rclone does not list, use provider = Other.

CDN.com.tr object storage is S3-compatible, and rclone is one of the clients that work with it as they are. The endpoint is https://s3.cdn.com.tr; tools that ask for a region can be left at the default, and the service expects path-style addressing, which is rclone's default for provider = Other. Buckets and access keys are created in the panel (the Access Keys tab) or with cdnctl. The secret key is shown only once, at creation, so copy it straight into the rclone config or your secret manager.

Keys are best scoped to the bucket they serve. A key like that is not allowed to create buckets, so tell rclone not to try: no_check_bucket = true skips the bucket-creation check that rclone otherwise makes before uploading. For the same reason, test a bucket-scoped key with rclone lsd cdntr:my-bucket rather than listing the whole account.

cdnctl handles the control plane here: buckets, keys and bindings to container apps. Reading and writing the objects themselves is the job of an S3 client such as rclone. (The separate cdnctl cp command uploads to CDN file storage, which is a different product; see CDN file storage.)

rclone.conf: a CDN.com.tr object storage remote

[cdntr]
type = s3
provider = Other
access_key_id = <access key from the panel>
secret_access_key = <secret, shown once at creation>
endpoint = https://s3.cdn.com.tr
no_check_bucket = true

# test it
# rclone lsd cdntr:my-bucket
# rclone copy ./smoke.txt cdntr:my-bucket/ -v

Migrating between providers: R2, B2 or AWS S3 to another S3

A migration between two S3 services is two remotes and one command. rclone lists both sides, compares them and copies what is missing, so you can run the same command repeatedly: the first run moves the bulk, later runs only the changes, and the final run during your cutover is short.

The data flows through the machine that runs rclone: it downloads from the source and uploads to the destination. Run it on a server with good bandwidth to both ends rather than on a laptop, and check the source provider's egress pricing first. AWS bills outbound transfer, Backblaze B2 includes free egress up to a multiple of what you store, and Cloudflare R2 does not charge for egress. Server-side copy only happens inside one provider.

Settings that make big migrations faster and cheaper: --fast-list to cut listing requests, --checksum so rclone compares sizes and hashes instead of fetching modification times object by object, and higher --transfers and --checkers if the source allows it. Start with copy, not sync, so a mistake cannot delete anything; switch to sync (with --dry-run first) only for the last pass if objects were deleted at the source in the meantime.

For Backblaze B2 you can use either rclone's native b2 type or B2's S3 endpoint; both work. R2 keys are created in the Cloudflare dashboard, and its endpoint contains your account ID. Our comparison pages work through the moves in detail: Cloudflare R2 alternative, Backblaze B2 alternative and IDrive e2 alternative. On the application side, the only things that change are the endpoint and the keys.

R2 to CDN.com.tr object storage, with a dry run first
# rclone.conf (source)
[r2]
type = s3
provider = Cloudflare
access_key_id = ...
secret_access_key = ...
endpoint = https://<ACCOUNT_ID>.r2.cloudflarestorage.com
region = auto

# 1. preview, 2. bulk copy, 3. repeat until the delta is small
rclone copy r2:media cdntr:media --dry-run
rclone copy r2:media cdntr:media \
  --fast-list --checksum --transfers 32 --checkers 64 -P

# cutover: stop writes, final pass, then compare
rclone sync r2:media cdntr:media --fast-list --checksum -P
rclone check r2:media cdntr:media --one-way

Verifying a migration with rclone check

rclone check source: dest: compares both sides object by object and prints a summary: how many files match, how many differ, and which exist on only one side. It changes nothing. --one-way only looks for source files missing or different at the destination, which is what you want when the destination already has extra data.

The comparison uses sizes and, where both sides share a hash type, hashes. On S3 that hash is MD5, and here is the catch: an object uploaded in multiple parts has an ETag that is not its MD5. rclone stores the real MD5 in object metadata when it uploads multipart files itself, but objects written by other tools often have none, so for those check can only compare sizes and says so in its output ("hashes could not be checked"). When you need byte-for-byte certainty, --download reads both copies and compares the content, at the cost of transferring everything again.

For reports you can keep, write the lists to files with --combined, --missing-on-dst and --differ. Compare rclone size on both sides as a final sanity check, and for an encrypted remote use rclone cryptcheck, which checks the encrypted copy against the plain source.

A check that leaves a report behind
rclone size r2:media && rclone size cdntr:media

rclone check r2:media cdntr:media --one-way \
  --combined check-report.txt \
  --missing-on-dst missing.txt --differ differ.txt

# slow but exact: download and compare the bytes
rclone check r2:media cdntr:media --download

Google Drive, encryption and mounting, briefly

Google Drive. Choose drive in rclone config, pick a scope (drive.readonly is enough for downloading), and approve access in the browser. On a server without a browser, answer n to auto config and run rclone authorize "drive" on a machine that has one, then paste the token back. rclone's built-in client ID is shared by all users and gets rate-limited; for heavy use, create your own OAuth client in Google Cloud and enter it during setup. Google Docs files are not real files, so rclone exports them (to docx, xlsx and so on) when downloading. Google also limits uploads to about 750 GB per user per day, so a large migration *into* Drive takes several days.

Encryption. A crypt remote wraps another remote and encrypts file contents, and optionally names, before upload. You create it on top of, say, cdntr:backups, then write through the crypt remote; the provider only ever sees ciphertext. The password and salt live in your rclone.conf: lose them and the data is unrecoverable, so back them up separately from the data.

Mounting. rclone mount remote:bucket /mnt/bucket makes a bucket look like a folder (on Windows, mount to a drive letter such as X: with WinFsp installed). Add --vfs-cache-mode writes or full so applications that rewrite files work properly. A mount is fine for browsing, media libraries and occasional reads; it is not a disk, so do not put databases or anything that needs file locking on it.

Download from Drive; add an encrypted remote on top of a bucket

rclone copy gdrive:Projects ./projects -P

# rclone.conf: encrypted backups inside an existing bucket remote
[secure]
type = crypt
remote = cdntr:backups/encrypted
filename_encryption = standard
password = <obscured by rclone config>
password2 = <obscured by rclone config>

rclone copy /srv/backups secure: -P

Scheduling rclone: cron, systemd and Task Scheduler

rclone has no scheduler of its own; it is meant to be run by one. On Linux, a cron entry is enough for most jobs. Wrap the command in flock so a slow run is not overlapped by the next one, log to a file, and point --config at an explicit path, because cron runs with a different HOME and would otherwise not find your remotes.

For a sync that deletes, add the seatbelts: --max-delete to stop a run that would remove far more than usual, and --backup-dir to move overwritten and deleted files into a dated folder instead of losing them. rclone's exit code is 0 on success and non-zero on failure, so the wrapper script or systemd unit can raise an alert; a job that has been failing silently for a month is the usual way backups fail.

On systemd machines, a service plus a timer gives you logging in the journal and Persistent=true, which runs a missed job after a reboot. On Windows, create a Task Scheduler task that runs rclone.exe with the full config path and a log file, under an account that has access to both the files and the config.

Nightly backup with cron, a lock and a safety net
# crontab -e  (02:30 every night)
30 2 * * * flock -n /tmp/rclone-backup.lock \
  rclone sync /srv/backups cdntr:backups/nightly \
  --config /home/backup/.config/rclone/rclone.conf \
  --max-delete 200 \
  --backup-dir cdntr:backups/deleted/$(date +\%F) \
  --log-file /var/log/rclone-backup.log --log-level INFO

rclone FAQ

What is the difference between rclone copy and rclone sync?

copy adds and updates files at the destination and never deletes anything. sync makes the destination identical to the source, so it also deletes destination files that are not in the source. Use copy unless you need deletions mirrored, and always try a new sync with --dry-run first.

Is rclone free, and is it safe to use?

Yes. rclone is open-source under the MIT licence, with no paid edition. It talks directly to your storage provider; nothing passes through a third-party service. The real risks are a leaked rclone.conf, which holds your keys, and a sync pointed the wrong way.

Does rclone have a GUI on Windows?

rclone itself is a command-line program; on Windows you run rclone.exe from PowerShell or cmd. It ships an experimental web interface (rclone rcd --rc-web-gui), and several third-party front ends exist, but the commands in this guide are the same everywhere.

How do I download a folder from Google Drive with rclone?

Create a drive remote with rclone config, then run rclone copy gdrive:FolderName ./local-folder -P. Shared files live under --drive-shared-with-me, shared drives are configured as their own remote, and Google Docs are exported to Office formats on the way down.

Why is rclone slow with many small files?

Each object costs at least one request, so latency, not bandwidth, sets the pace. Raise --transfers and --checkers, use --fast-list for big buckets, and add --checksum or --size-only on S3 so rclone does not fetch every object's modification time separately.

Which settings does rclone need for CDN.com.tr object storage?

An s3 remote with provider = Other, endpoint = https://s3.cdn.com.tr, and the access key and secret created in the panel. The region can stay at the default. With a key scoped to one bucket, add no_check_bucket = true.