Using Rclone to Sync Local Files with SFTP To Go

There are numerous utilities and services to sync files between servers and file storage services, and we’ve already discussed many of them: Chronosync, FreeFileSync, Mountain Duck, WinSCP for Windows, and more.

Rclone stands among them for three reasons: it works virtually everywhere, supports dozens of data storage types, and you can automate it with scripts and schedulers. The GUI tools can’t do all that.

This guide explains the basics of using rclone and focuses on syncing files between local file storage and your SFTP To Go server.


Install rclone

To follow along, start by installing rclone. Go to https://rclone.org/downloads/, download rclone for your operating system, and follow the installation instructions on that page.


Rclone in a nutshell

Rclone is an application with a command-line interface, so it expects you to use a specific sequence of commands and options: an action command followed by a path, followed by options. Here is the usual syntax for syncing:

rclone sync source:path destination:path [options]

The source and destination: parts are remotes, which are named configurations that specify how to connect to a specific storage location. While they are called remotes, the location can be the hard disk on your desktop computer or server where rclone is running.

You create remotes once, typically at the very beginning of using rclone, and then use them every time you need to sync data between two locations.

A simple real-life example of that would be:

rclone sync dropbox:invoices/ onedrive:invoices/

Here, rclone finds all new or changed files in the invoices folder on a Dropbox account and copies them to the invoices folder on a OneDrive account.

There’s a lot you can do with rclone apart from one-way syncing as in the example above. You can do bi-directional syncs, copy, move, and delete files, serve local and remote files over HTTP and DLNA, and much more.

Rclone works the same whether you use a managed SFTP service or a self-hosted server. It supports over a hundred data storage providers, so you can sync files directly between Google Drive and Dropbox or between Cloudflare R2 and an SFTP server like SFTP To Go.

Before we set up rclone, let’s get one important part out of the way.


Why configure remotes?

Rclone can absolutely work without setting up remotes, but it’s not as neat.

For online services that require authentication, you’d have to submit credentials every time you perform a sync, request a list of files, or delete a folder. A remote configuration can store all required credentials, so you only need to specify the remote name and the path. 

For local files specifically, a configured remote gives you several benefits:

  • baking useful backend flags into the remote configuration and using them consistently without retyping every time;
  • creating and using tools that expect the remote:path syntax uniformly;
  • consistent tracking of two-way syncs across runs thanks to more readable commands.

Setting up remotes

We are going to need two remotes: one for a local filesystem and one to access the data on your SFTP To Go account. We have already covered the topic of creating an rclone remote for SFTP To Go in a dedicated article, please refer to it.

Creating a remote for a local filesystem requires little information. Mainly, it’s the flags you may want to include in the remote configuration so that you don’t specify them every time you run a sync.

Here is a very generic way to create a remote for a local filesystem. You only specify the name of the remote (mylocal) and its type (local):

rclone config create mylocal local

If you want to add some flags to the remote configuration when you create it, here is how you do it:

rclone config create mylocal local links=true one_file_system=true

The two specific flags in the above example are for UNIX-like operating systems:

  • links=true tells rclone to preserve symbolic links instead of converting them to actual files.
  • one_file_system=true tells rclone not to cross over to other file systems mounted to the same location. So, for example, rclone will read data from /mnt/data, but not from /mnt/data/nfs-share if that subdirectory is a separate filesystem.

Note that when a new remote is created, rclone outputs a quick summary:

[mylocal]
type = local
links = true
one_file_system = true

It’s not very revealing when you create a simple remote for a local filesystem. However, whenever you create a remote with credentials and extra flags, do yourself a favor and see if all the details you specified are correct. If you made a mistake, you can amend it with either rclone config (see the documentation for details) or by editing the local rclone configuration file (e.g. ~/.config/rclone/rclone.conf) in a text editor.


Test connectivity

Let’s confirm that rclone can connect to both remotes. For example, you can list all directories in the user’s home directory for each remote.

Start with the source remote:

rclone lsd mylocal:
        4096 2026-08-07 10:08:27        -1 inbound

Repeat the same for the destination remote:

rclone lsd sftptogo:
          -1 1970-01-01 01:00:00        -1 projects

You’ll notice that folders on SFTP To Go have timestamps from 1 January 1970. Read on, and we’ll discuss why that happens and how to work around that.

The connection evidently works, so let’s learn how to do basic file operations on remotes.


Create folder structure

Let’s assume that you will copy files to a folder on SFTP To Go for processing, and then processed files will be saved to a separate folder on your SFTP To Go account. Start by creating a folder named inbound:

rclone mkdir sftptogo:inbound

Verify that the folder has been created:

rclone lsd sftptogo:
         -1 1970-01-01 01:00:00        -1 inbound

After that, repeat to create another folder named archive. This is where processed files will be stored.


One-way sync: local to SFTP To Go

When rclone performs a one-way sync, it compares the source directory against the target directory and transfers files in one direction. This makes the target directory a mirror of the source one: an identical copy that contains the exact same files as the original.

It is best illustrated with an example where the destination directory diverges a little from the source directory and needs a sync to become the perfect mirror again. To try that, let’s copy a directory you will be syncing to the remote, delete a file, and run an actual sync command. Start with copying:

rclone copy mylocal:inbound/ sftptogo:inbound/ --dry-run
2026/07/29 17:34:39 NOTICE: 2024/3_2024.pdf: Skipped copy as --dry-run is set (size 31.326Ki)
2026/07/29 17:34:39 NOTICE: 2024/4_2024.pdf: Skipped copy as --dry-run is set (size 30.244Ki)
2026/07/29 17:34:39 NOTICE: 2024/5_2024.pdf: Skipped copy as --dry-run is set (size 31.545Ki)
2026/07/29 17:34:39 NOTICE: 2024/6_2024.pdf: Skipped copy as --dry-run is set (size 31.443Ki)
2026/07/29 17:34:39 NOTICE: 2024/1_2024.pdf: Skipped copy as --dry-run is set (size 31.042Ki)
2026/07/29 17:34:39 NOTICE: 2024/2_2024.pdf: Skipped copy as --dry-run is set (size 29.877Ki)
2026/07/29 17:34:39 NOTICE: 2024/7_2024.pdf: Skipped copy as --dry-run is set (size 30.019Ki)

We are using the --dry-run flag here that tells rclone to simulate the actual operation and output what it would output if it actually moved files around. Recovering deleted files from the command line is difficult, so it pays to double-check before you delete or overwrite data.

If you don’t see any issues during the dry run, proceed with copying the files, this time for real:

rclone copy mylocal:inbound/ sftptogo:inbound/ -v

To verify that files have indeed been copied, you can use rclone ls:

rclone ls sftptogo:inbound/
   31787 2024/1_2024.pdf
    30594 2024/2_2024.pdf
    32078 2024/3_2024.pdf
    30970 2024/4_2024.pdf
    32302 2024/5_2024.pdf
    32198 2024/6_2024.pdf
    30739 2024/7_2024.pdf

Next, let’s make the destination directory diverge from the original a little by removing one copied file from it:

rclone delete sftptogo:inbound/2024/7_2024.pdf --dry-run
2026/08/09 17:52:28 NOTICE: 7_2024.pdf: Skipped delete as --dry-run is set (size 30.019Ki)

Once again, a dry run can save the day for you. If the command works as expected, repeat it without --dry-run and try syncing the two remotes:

rclone sync mylocal:inbound/ sftptogo:inbound/ -v
2026/08/09 17:58:31 INFO  : 2024/1_2024.pdf: Copied (replaced existing)
2026/08/09 17:58:31 INFO  : 2024/7_2024.pdf: Copied (new)
2026/08/09 17:58:31 INFO  : 2024/2_2024.pdf: Copied (replaced existing)
2026/08/09 17:58:32 INFO  : 2024/3_2024.pdf: Copied (replaced existing)
2026/08/09 17:58:32 INFO  : 2024/4_2024.pdf: Copied (replaced existing)
2026/08/09 17:58:33 INFO  : 2024/5_2024.pdf: Copied (replaced existing)
2026/08/09 17:58:33 INFO  : 2024/6_2024.pdf: Copied (replaced existing)

You can see that rclone replaced existing matching files and copied the file you had previously deleted on the SFTP To Go remote. After that, the contents of both directories match as they should.


Two-way syncing

Bidirectional, or two-way, syncs are for keeping two remotes in sync. The bisync command in rclone attempts to detect changes on both sides and reconcile them.

Before you use it normally, you need to establish the baseline, or the original state of files and folders on both remotes. Every time you run bisync after that, rclone will incrementally update the original baseline using a three-way comparison (baseline, source state, destination state). 

To create the original baseline, run rclone with the following flags:

rclone bisync mylocal:inbound/ sftptogo:inbound/ \
  --checksum \
  --resync \
  --dry-run \
  --verbose

If the command completes without errors, repeat it without --dry-run. On every recurring run afterwards, run it without --resync: this flag instructs rclone to establish a fresh baseline instead of doing a normal two-way comparison between the source and the destination.


Mirroring with inclusions and exclusions

So far, we’ve looked at fairly simple sync examples where you need all files in two remotes to match. But real-life scenarios often require explicitly including or excluding specific files or folders when you sync remotes. Here is a common example of inclusion in a sync:

rclone sync mylocal:reports sftptogo:backups/reports --include "*.pdf"

In the example above, rclone only syncs files matching the *.pdf pattern from the reports folder on your local filesystem to the backups/reports folder on SFTP To Go. All the other files are ignored entirely.

Similarly, the following command will exclude all *.tmp files from the sync:

rclone sync mylocal:reports sftptogo:backups/reports --exclude "*.tmp"

However, if you need to combine inclusion and exclusion, setting that up with these command-line flags can get tricky. Rclone applies rules in the strict “first match wins” order, so you have to watch out for the first rule canceling out the second one. Here is an example:

rclone sync mylocal:logs/ sftptogo:logs --include "*.log" --exclude "*"

Here, rclone will include all *.log files in the sync and exclude everything else. But if you reverse it like this…

rclone sync mylocal:logs/ sftptogo:logs --exclude "*" --include "*.log"

rclone will exclude everything, and that will prevent the second rule from being applied, because * covers all files including *.log.

Things get a lot more hairy when you have more than two conditions. Let’s say you’re syncing a directory of exported data files to cold storage. The rules are:

  • Exclude all *_raw.csv files (unprocessed dumps, too big or messy to ship)
  • Exclude everything in any /tmp_exports/ folder
  • Except keep *_raw.csv files specifically inside /archive/2024/ (you need those raw dumps preserved for that one compliance year)
  • Include everything else (cleaned CSVs, JSON summaries, reports)

With a combination of --include and --exclude, the command will look like this:

rclone sync /data /dst \
  --include "/archive/2024/**_raw.csv" \
  --exclude "tmp_exports/**" \
  --exclude "*_raw.csv" \
  --include "**"

This is noticeably harder to read and doesn’t scale well later, when you need multiple other archive-year exceptions. The solution? Use the --filter flag. 

First, create this text file:

# data-sync-filters.txt
+ /archive/2024/**_raw.csv
- *_raw.csv
- tmp_exports/**
+ **

Then use it in a command:

rclone sync mylocal:/data sftptogo:data/ --filter-from data-sync-filters.txt

This approach has important benefits:

  • The exception sits directly above the rule it carves out from. You read line 1 and line 2 together as "raw CSVs are excluded, except this one archive".
  • New exceptions are just new lines rather than flag reshuffling. If finance says "also keep raw files in /archive/2023/ for the audit", you add one line without touching anything else.
  • The text file where you keep the filter rules is an artifact you can version in a Git repository and reuse. You can also put a comment that explains why 2024 is special-cased (e.g. # retained for SOX audit). This is far more maintainable than parsing flag order buried in a shell script.

Working around missing S3 timestamps

SFTP To Go is built on top of the AWS infrastructure (including S3 storage), which comes with a caveat: modification timestamps cannot be altered or set. Every object receives a timestamp matching its creation time.

This can mess up bi-directional syncs, because after an initial sync, files on SFTP To Go will appear newer than those at the destination. Because rclone cannot update the modification timestamp on SFTP To Go to match the source, subsequent runs may incorrectly trigger back-and-forth sync loops or overwrite updated destination files with older source versions.

Fortunately, rclone has alternative ways to compare files:

  • When you use the --checksum flag, rclone will calculate and compare hashes for files with matching names and locations. Checksums are precise: even if you change one digit in a CSV file, the file size will be the same, but the checksum will change because the content has changed. However, the checksum calculation takes time, which may be critical for larger syncs.
  • When you use the --size-only flag, rclone will compare file sizes to determine whether a file on one of the remotes has changed. Using file size is fast, but it’s less precise and will fail in similar situations where the content has changed, but the file size hasn’t.

Rule of thumb: If your sync only appends or uploads new files, use --size-only for maximum speed. If existing files are being edited or overwritten, use --checksum to ensure total data accuracy.


Wrapping up

Rclone is a lifesaver when you need a reliable, scriptable CLI sync tool that works on every desktop or server operating system out there and supports virtually all types of storage.

You’ve now seen how to set up remotes, run one-way and two-way syncs, fine-tune what gets transferred with inclusion/exclusion filters, and work around the S3 quirk. That’s enough to get you started building a dependable pipeline with SFTP To Go.

If you are looking into switching to a managed SFTP service, we offer a detailed migration guide, so check it out.


Frequently asked questions

Can rclone sync between two cloud providers without files going through my local machine?

Yes, remotes just point to different storage locations. What happens between them stays between them. No files are ever copied to the local filesystem.

What’s the difference between rclone’s copy, sync, and bisync?

copy only adds and updates files, sync makes the destination an exact mirror of the source, and bisync reconciles changes made on both sides.

Should I use --checksum or --size-only to compare files when performing a two-way sync with SFTP To Go?

Use --checksum when accuracy matters the most. Use --size-only when speed is more important and exact content changes are less likely.

How do I automate rclone syncs to run on a schedule?

Pair rclone with a task scheduler: cron on Linux/macOS or Task Scheduler on Windows. Or you can use a service like CronToGo.