Skip to content
Fernando Valler

Rclone on a VPS: How to Automate Backups and File Synchronization with systemd

Learn what rclone is, why it is useful on VPS servers, how to configure a remote storage backend, automate backups with systemd and timers, and monitor execution logs with journalctl.

Rclone on a VPS: How to Automate Backups and File Synchronization with systemd

Managing a VPS is not only about keeping applications running. You also need to think about backups, redundancy, and how to safely transfer files to another server or cloud storage provider.

This is where rclone becomes especially useful.

Rclone is a command-line tool for managing files across local storage and dozens of cloud storage services. It supports many different backends, including S3-compatible storage, Google Drive, Dropbox, OneDrive, WebDAV, SFTP, and many others.

In this article, we will build a practical setup for a Linux VPS:

  • install rclone;
  • configure a remote storage backend;
  • test the transfer;
  • create a systemd service;
  • schedule it with a systemd timer;
  • inspect the logs;
  • verify that the backup actually reached its destination.

What Is Rclone?

Rclone is a command-line utility for copying, synchronizing, moving, listing, and managing files across different storage systems.

Its syntax is intentionally similar to traditional Linux tools such as cp, mv, and ls, but with a strong focus on remote and cloud storage.

A simple example:

bash
rclone copy /var/backups remote:backups

In this example:

  • /var/backups is the local source;
  • remote: is the configured remote storage;
  • backups is the destination directory.

The concept of a remote is important.

Instead of using a completely different command for every provider, we configure the storage backend once and then use the same rclone interface.

For example:

text
gdrive:server-backups
s3:my-bucket
b2:backups
onedrive:servers

The remote name is completely configurable.


Is Rclone a Backup Tool?

This distinction is important.

Rclone is excellent at copying and synchronizing files, but that does not automatically make every rclone setup a complete backup solution.

For example:

bash
rclone copy /srv/app/backups remote:backups

copies files to another storage location.

However:

bash
rclone sync /srv/app/backups remote:backups

tries to make the destination match the source and may delete files from the destination when they no longer exist in the source.

For a simple backup workflow, I usually prefer starting with:

bash
rclone copy

instead of:

bash
rclone sync

because it reduces the risk of an accidental deletion in the source being immediately mirrored to the backup destination.

When the requirement is a real versioned backup system with retention, snapshots, deduplication, and encryption, a tool such as restic may be more appropriate.

Rclone and restic can also complement each other: restic can handle the backup repository while rclone provides access to remote storage.


Main Advantages of Rclone

1. One Interface for Many Providers

One of rclone’s biggest advantages is that you can interact with different storage providers using a consistent command-line interface.

For example:

text
Google Drive
Amazon S3
Cloudflare R2
Backblaze B2
Dropbox
OneDrive
SFTP
WebDAV

The exact backend configuration changes, but many everyday operations remain the same.

This is especially convenient when your infrastructure changes over time.


2. Excellent for Automation

Because rclone is command-line based, it fits naturally into:

text
bash
systemd
cron
CI/CD
scripts
backup jobs
maintenance tasks

This is particularly useful on Linux servers, where you usually want administrative tasks to run without a graphical interface.


3. Transfers Between Storage Systems

Rclone does not have to be limited to:

text
VPS → Cloud

Depending on the backend, it can also transfer data between remote storage systems.

That can be useful for:

  • migrations;
  • provider changes;
  • data replication;
  • moving large datasets between storage services.

It also avoids unnecessary intermediate copies when the selected backends support server-side or remote-to-remote transfers.


4. Verification and Resumable Transfers

Rclone can compare files using size, metadata, and hashes when supported by the backend.

It also provides commands specifically designed to verify whether source and destination contain matching data.

This is useful because a successful transfer is not always enough evidence that the resulting backup is correct.


5. More Than Just Copying Files

Rclone has many features beyond simple file transfers.

Examples include:

bash
rclone mount
rclone check
rclone cryptcheck
rclone bisync
rclone serve

It also provides virtual storage backends for features such as encryption and storage composition.

This makes rclone more than a simple “copy to cloud” utility.


Rclone vs Rsync vs Restic

These tools can look similar, but they solve different problems.

ToolMain PurposeCloud StorageSnapshotsDeduplication
RcloneCopy and synchronize filesExcellentNo, not by itselfNo
RsyncFile synchronizationIndirectNoNo
ResticVersioned backupsExcellentYesYes

Rsync is extremely useful for synchronizing files between Linux systems, commonly over SSH.

Restic was designed specifically as a backup tool and provides snapshots, encryption, and deduplication.

Rclone sits somewhere else: it is particularly useful when the main problem is moving and managing files across different storage systems.

A simple way to think about it is:

Rclone focuses on moving and managing data. Restic focuses on maintaining a backup repository.


Installing Rclone on a VPS

The official rclone documentation provides installation methods for Linux, including an official installation script and pre-built binaries.

One simple approach is:

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

Then verify the installation:

bash
rclone version

You should see the installed rclone version and platform information.

For environments where you want more control over the installation process, you can also download and install the official binary manually.


Configuring a Remote

The next step is configuring the connection to your storage provider.

Run:

bash
rclone config

Rclone will open an interactive configuration wizard.

After creating the remote, check the available remotes:

bash
rclone listremotes

Then test access:

bash
rclone lsd remote:

or:

bash
rclone ls remote:

You can also check where the configuration file is stored:

bash
rclone config file

On Linux, the default location is commonly:

text
~/.config/rclone/rclone.conf

but the exact location depends on the environment and configuration.


Configuring Rclone on a Headless VPS

This is a common situation.

Some cloud providers require browser-based authentication, while a production VPS may not have a graphical environment.

One option is to configure the remote on another machine and then transfer the configuration file to the VPS.

For example, on the machine where you configure the remote:

bash
rclone config file

Then copy the configuration file to the server:

bash
scp ~/.config/rclone/rclone.conf user@server:/tmp/rclone.conf

On the VPS:

bash
sudo install -d -m 700 /home/rclone/.config/rclone
sudo install -m 600 /tmp/rclone.conf /home/rclone/.config/rclone/rclone.conf
sudo chown -R rclone:rclone /home/rclone/.config

The important part is ensuring that the user running the backup job can read the configuration file.


Creating a Dedicated Backup User

I prefer not to execute automated backup jobs as root when root privileges are not required.

We can create a dedicated system user:

bash
sudo useradd \
    --system \
    --create-home \
    --home-dir /home/rclone \
    --shell /usr/sbin/nologin \
    rclone

Then:

bash
sudo install -d -m 700 /home/rclone/.config/rclone
sudo chown -R rclone:rclone /home/rclone

The idea is simple:

text
root
  └── administers the server

rclone
  └── runs the backup job

This reduces the potential impact of a compromised or incorrectly configured backup process.


Running the First Manual Backup

Before introducing systemd, we should prove that the command works manually.

Suppose our application backups are stored in:

text
/var/backups/myapp

and the configured remote is:

text
remote:

We can run:

bash
sudo -u rclone rclone copy \
    /var/backups/myapp \
    remote:myapp

For more detailed output:

bash
sudo -u rclone rclone copy \
    /var/backups/myapp \
    remote:myapp \
    --progress \
    --log-level INFO

Before using sync, test it with:

bash
rclone sync \
    /var/backups/myapp \
    remote:myapp \
    --dry-run

--dry-run allows you to inspect the changes that would be made without actually modifying the destination.

This is especially useful before deploying a synchronization command in production.


copy vs sync

This is probably the most important distinction in this article.

copy

bash
rclone copy source destination

Copies new or changed files without turning the destination into an exact mirror of the source.

For a simple backup workflow, this is often the more conservative choice.

sync

bash
rclone sync source destination

Makes the destination match the source, including deletions when applicable.

Imagine this scenario:

text
SOURCE
backup-01.sql
backup-02.sql

DESTINATION
backup-01.sql
backup-02.sql
backup-03.sql

With sync, the file:

text
backup-03.sql

may be removed from the destination.

This is why sync should be used deliberately.

Before using it in production, test with:

bash
--dry-run

and carefully review the proposed changes.


Using --backup-dir

When sync is actually the desired behavior, another useful feature is:

bash
--backup-dir

This option allows files that would otherwise be overwritten or deleted to be moved to another backup directory.

For example:

bash
rclone sync \
    /var/backups/myapp \
    remote:myapp \
    --backup-dir remote:myapp-old

This adds another layer of protection for changed or deleted files.

However, I would still not treat this as a replacement for a real retention strategy.


Automating Rclone with systemd

Once the manual command has been validated, we can automate it.

Create:

bash
sudo nano /etc/systemd/system/rclone-backup.service

Use:

ini
[Unit]
Description=VPS backup using rclone
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
User=rclone
Group=rclone
UMask=0077

ExecStart=/usr/bin/rclone copy \
    /var/backups/myapp \
    remote:myapp \
    --log-level INFO \
    --stats 1m

StandardOutput=journal
StandardError=journal

There are a few important details here.

Type=oneshot means that the service runs a task and exits.

We do not need a long-running process.

The output is also sent to the systemd journal, so we can inspect it later using journalctl.


Creating the systemd Timer

Now create the timer:

bash
sudo nano /etc/systemd/system/rclone-backup.timer

Use:

ini
[Unit]
Description=Schedule the rclone backup

[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true
RandomizedDelaySec=5m

[Install]
WantedBy=timers.target

In this example, the job will run every day around:

text
02:30

OnCalendar allows us to define a schedule using systemd’s calendar syntax.

The following option is also useful:

ini
Persistent=true

If the machine was offline when the timer was supposed to run, systemd can trigger the associated service after the system comes back online.

We can also use:

ini
RandomizedDelaySec=5m

to introduce a small random delay.

This can be useful when several servers run similar backup schedules at the same time.


Enabling the Timer

After creating both files:

bash
sudo systemctl daemon-reload

Enable and start the timer:

bash
sudo systemctl enable --now rclone-backup.timer

Check its status:

bash
systemctl status rclone-backup.timer

And list the systemd timers:

bash
systemctl list-timers

You should see something similar to:

text
rclone-backup.timer

along with its next scheduled execution.


Testing the Service Immediately

You do not need to wait until 02:30 to see whether the backup works.

Run:

bash
sudo systemctl start rclone-backup.service

Then:

bash
systemctl status rclone-backup.service

Because the service uses:

ini
Type=oneshot

it is normal for the service to show:

text
inactive (dead)

after a successful execution.

What matters is whether the last execution completed successfully.


Checking Logs with journalctl

This is one of the strongest reasons to use systemd for scheduled jobs.

To see the complete log:

bash
journalctl -u rclone-backup.service

To show only the last 100 entries:

bash
journalctl -u rclone-backup.service -n 100

To follow the logs in real time:

bash
journalctl -u rclone-backup.service -f

To see today’s executions:

bash
journalctl -u rclone-backup.service --since today

This gives us a simple workflow:

text
rclone
   |
   v
systemd service
   |
   v
systemd journal
   |
   v
journalctl

No additional logging infrastructure is required for a basic setup.


Increasing the Log Level

During troubleshooting, it can be useful to increase the log level.

For example:

bash
rclone copy \
    /var/backups/myapp \
    remote:myapp \
    --log-level DEBUG

Rclone supports different log levels, including:

text
ERROR
NOTICE
INFO
DEBUG

For a normal production job, INFO is usually a reasonable starting point.

DEBUG is more useful when investigating failures.

You can also write logs directly to a file:

bash
--log-file=/var/log/rclone-backup.log

However, when the job is already managed by systemd, I generally prefer the journal:

bash
journalctl -u rclone-backup.service

It keeps the logging model simple and integrates naturally with the rest of the server.


Verifying That the Backup Actually Exists

A job finishing without errors does not mean we should stop there.

Check the destination:

bash
rclone ls remote:myapp

or:

bash
rclone lsf remote:myapp

You can also check the total size:

bash
rclone size remote:myapp

This gives us a basic validation that the files are actually present in the remote storage.


Comparing Source and Destination

Rclone provides a dedicated command for comparing files:

bash
rclone check \
    /var/backups/myapp \
    remote:myapp

This compares source and destination using file size and hashes when supported by the backend.

It does not modify the data.

For backup validation, we can also use:

bash
rclone check \
    /var/backups/myapp \
    remote:myapp \
    --one-way

This is useful when the goal is to ensure that every source file exists correctly in the destination without treating additional destination files as an error.


Protecting the Credentials

The rclone configuration file contains sensitive information related to the configured remotes.

It should therefore not be readable by every user.

For example:

bash
chmod 700 /home/rclone/.config/rclone
chmod 600 /home/rclone/.config/rclone/rclone.conf

And:

bash
chown -R rclone:rclone /home/rclone/.config/rclone

Rclone also provides additional protection mechanisms for its configuration file.

One important distinction is the difference between obfuscation and encryption.

The command:

bash
rclone obscure

should not be considered strong cryptographic protection. It is primarily intended to prevent credentials from being immediately readable in the configuration file.

Treat the configuration file itself as sensitive.


Encrypting the Backup Data with Crypt

Another powerful rclone feature is the crypt backend.

It allows you to create an encrypted remote on top of another storage backend.

The architecture becomes:

text
VPS
 |
 v
rclone crypt
 |
 v
Google Drive / S3 / B2 / etc.

The content stored in the remote is encrypted, while rclone handles encryption and decryption transparently when accessing the data.

Conceptually:

text
backup:
    ↓
crypt:
    ↓
remote:

This is useful when you want data stored in the remote provider to remain encrypted independently of the provider’s own security model.


Important Considerations for a VPS

An automated backup job may look simple, but there are several common mistakes.

Do Not Test Only the Upload

Do not stop at:

text
"the command completed successfully"

A stronger validation process checks:

text
file exists on destination
file can be read
file matches the source
restore works

Do Not Use sync Without Understanding Deletions

A command such as:

bash
rclone sync /var/backups remote:backups

may be completely appropriate for a particular architecture.

But it can also propagate local deletions to the remote destination.

Before using sync, I recommend running:

bash
--dry-run

and reviewing the output carefully.


Do Not Run Everything as Root

When root privileges are not necessary, use a dedicated account.

This reduces the potential impact of a compromised or incorrectly configured backup process.


Do Not Forget the Restore Test

The worst time to discover that your backup strategy does not work is during an actual incident.

A real backup strategy must include restoration testing.

For example:

bash
rclone copy remote:myapp/test-backup /tmp/restore-test

Then inspect the restored files and, where appropriate, perform a complete application or database restoration test.


A Practical VPS Backup Architecture

For a simple VPS, we could use a structure like this:

text
/var/backups/
└── myapp/
    ├── database/
    │   ├── backup-2026-09-25.sql.gz
    │   └── backup-2026-09-26.sql.gz
    └── application/
        ├── backup-2026-09-25.tar.gz
        └── backup-2026-09-26.tar.gz

Then:

text
                +-------------------+
                |       VPS         |
                |                   |
                | /var/backups      |
                +---------+---------+
                          |
                          | rclone
                          v
                +-------------------+
                |   Cloud Storage   |
                |                   |
                |     myapp/        |
                +-------------------+

And the systemd components:

text
rclone-backup.timer
        |
        v
rclone-backup.service
        |
        v
      rclone
        |
        v
 Cloud Storage

Logs:

text
rclone
   |
   v
systemd-journald
   |
   v
journalctl

This is a simple architecture, but it is already enough for many small and medium VPS environments.


A Quick Checklist

Before considering the automation complete, I would verify:

text
[ ] rclone installed
[ ] remote configured
[ ] remote access tested
[ ] dedicated user created
[ ] configuration permissions reviewed
[ ] manual transfer tested
[ ] --dry-run tested when applicable
[ ] copy/sync chosen intentionally
[ ] systemd service created
[ ] systemd timer created
[ ] timer enabled
[ ] first scheduled execution validated
[ ] logs reviewed
[ ] destination files verified
[ ] rclone check executed
[ ] restore tested

Conclusion

Rclone is a very useful tool for VPS administrators because it provides a consistent command-line interface for working with different storage providers.

Its value is not simply “uploading files to the cloud”.

It can be used to:

  • transfer data between different storage backends;
  • automate backup jobs;
  • validate files;
  • migrate data;
  • encrypt remote content;
  • integrate cloud storage into Linux scripts and services.

For a simple VPS environment, a setup such as:

text
VPS
+
/var/backups
+
rclone
+
systemd timer
+
journalctl

can already provide a reliable and maintainable foundation for automated file transfers.

But it is important to keep the concepts separate:

Rclone is an excellent tool for data transfer and remote storage management. A complete backup strategy also needs retention, isolation, encryption, monitoring, integrity checks, and restoration procedures.

In other words:

Making a backup means copying the data. Having a backup strategy means knowing that the data can actually be recovered when you need it.

References

Rclone documentation: https://rclone.org/docs/

Rclone installation: https://rclone.org/install/

Rclone sync: https://rclone.org/commands/rclone_sync/

Rclone check: https://rclone.org/commands/rclone_check/

Rclone crypt: https://rclone.org/crypt/

systemd timers: https://www.freedesktop.org/software/systemd/man/latest/systemd.timer.html

journalctl: https://www.freedesktop.org/software/systemd/man/latest/journalctl.html