Skip to content

rclone (everything else)

kopia shells out to rclone, so the rclone backend reaches any rclone-supported provider: Google Drive, OneDrive, Dropbox, pCloud, Box, Mega, and dozens more. This is the escape hatch for providers without a native kopia backend.

If a native backend exists for your provider, prefer it. It is simpler and has fewer moving parts. Those are S3, Azure, GCS, B2, and WebDAV. Use rclone for everything else.

  • A working rclone.conf that defines the remote you’ll reference. Build and test it on your own machine first:

    Terminal window
    $ rclone config # interactively create a remote, e.g. named "mydrive"
    $ rclone ls mydrive: # confirm it works before putting it in a Secret
  • The remote name in your remotePath, which is mydrive: below, must match a section header in that rclone.conf, which is [mydrive].

rclone is one of the three file-delivered backends. The mover reads the whole config from a well-known environment key, writes it to a private file with mode 0600, and runs rclone with --config.

Secret key Required What it is
KOPIA_RCLONE_CONFIG yes The entire rclone.conf, exactly as printed. Written to a file, then passed to rclone as --config.
KOPIA_PASSWORD yes The repository encryption password.
stringData:
KOPIA_RCLONE_CONFIG: |
[mydrive]
type = drive
scope = drive
token = {"access_token":"REPLACE_ME", ...}
KOPIA_PASSWORD: "choose-something-long-and-random"
---
apiVersion: v1
kind: Secret
metadata:
name: rclone-config
namespace: backups
type: Opaque
stringData:
# A standard rclone.conf defining the remote referenced by remotePath below
# (here the remote is named `mydrive`). Generate it with `rclone config`. The
# operator's mover writes this to a file and runs rclone with `--config`. The
# key is KOPIA_RCLONE_CONFIG (a valid env identifier), not `rclone.conf`
# (a dotted key is dropped by Kubernetes envFrom).
KOPIA_RCLONE_CONFIG: |
[mydrive]
type = drive
scope = drive
token = {"access_token":"REPLACE_ME","token_type":"Bearer","refresh_token":"REPLACE_ME"}
KOPIA_PASSWORD: "choose-something-long-and-random"
---
apiVersion: kopiur.home-operations.com/v1alpha1
kind: Repository
metadata:
name: rclone-primary
namespace: backups
spec:
backend:
rclone:
remotePath: mydrive:backups/kopia # rclone remote:path; `mydrive` is defined in rclone.conf
configSecretRef:
name: rclone-config # Secret holding the rclone.conf above (NOT `auth`)
encryption:
passwordSecretRef:
name: rclone-config # may be the same Secret; it also carries KOPIA_PASSWORD
key: KOPIA_PASSWORD
create:
enabled: true
Field Required Default Example What it controls
remotePath yes — mydrive:backups/kopia rclone path in remote:path form. The part before : must match a [section] in the config. The part after it is the folder.
configSecretRef no¹ — { name: rclone-config } Secret holding the rclone.conf, under the key KOPIA_RCLONE_CONFIG. This is not auth. A ClusterRepository adds namespace:.
startupTimeout no 15s 2m How long kopia waits for its embedded rclone serve to come up before failing the connect. It takes a Go duration. Raise it for slow remotes whose metadata and indexes load through the rclone-to-WebDAV bridge.

¹ Optional in the schema, but required in practice. rclone can’t reach a remote without its config.

Customization — the values you actually change

Section titled “Customization — the values you actually change”
  • remotePath is the remote:path. The remote name must exist in the config.
  • KOPIA_RCLONE_CONFIG holds the config contents. Re-paste it when tokens rotate.
  • create.enabled initializes the repository if it’s missing.

The same backend.rclone stanza works on a cluster-scoped ClusterRepository, with two requirements. The configSecretRef, and the encryption.passwordSecretRef, must carry an explicit namespace:. And the Secret must exist in the namespaces the movers run in. See Movers.

Prove this backend really takes a backup. The same example file carries a tiny smoke-test: a throwaway PVC, a SnapshotPolicy, and a Snapshot, all pointed at the rclone-primary repository above. It takes you from “applied” to “a snapshot on my remote” in one go.

1. Apply the bundle. That is the backups namespace, the Secret, the Repository, and the smoke-test objects:

Terminal window
$ kubectl apply -f deploy/examples/backends/rclone.yaml

2. Wait for the repository to be Ready. Everything else waits on this:

Terminal window
$ kubectl -n backups wait --for=condition=Ready repository/rclone-primary --timeout=2m
repository.kopiur.home-operations.com/rclone-primary condition met

3. Take the smoke backup. The Snapshot uses generateName, so create it rather than apply it. The namespace, Secret, Repository, PVC, and policy already exist and report unchanged. The Snapshot is the one new object:

Terminal window
$ kubectl create -f deploy/examples/backends/rclone.yaml
snapshot.kopiur.home-operations.com/smoke-now-abc12 created

4. Watch it succeed:

Terminal window
$ kubectl -n backups get snapshots -w
NAME PHASE ORIGIN SNAPSHOT AGE
smoke-now-abc12 Pending manual 2s
smoke-now-abc12 Running manual 7s
smoke-now-abc12 Succeeded manual k1f1ec0a8 38s

The output above is illustrative. The Snapshot has no fixed Succeeded condition, so to wait on it in a script, key on the phase:

Terminal window
$ kubectl -n backups wait --for=jsonpath='{.status.phase}'=Succeeded \
snapshot/smoke-now-abc12 --timeout=5m

5. Prove the data really moved. status.stats shows non-zero bytesNew and filesNew, and status.snapshot.kopiaSnapshotID is the kopia snapshot ID on your remote:

Terminal window
$ kubectl -n backups get snapshot smoke-now-abc12 -o jsonpath='{.status.stats}'
{"sizeBytes":4096,"bytesNew":1280,"filesNew":2,"filesUnchanged":0}
$ kubectl -n backups get snapshot smoke-now-abc12 -o jsonpath='{.status.snapshot.kopiaSnapshotID}'
k1f1ec0a8

Both outputs are illustrative; sizes and the ID vary. Non-zero bytesNew proves the backup uploaded real content through rclone.

6. Clean up the smoke-test when you’re done:

Terminal window
$ kubectl -n backups delete snapshot --all # finalizer also deletes the kopia snapshot
$ kubectl -n backups delete snapshotpolicy smoke
$ kubectl -n backups delete pvc smoke-data

From here the rest of the lifecycle is the same on every backend. Only the Repository differs. Put it on a cron with a SnapshotSchedule, described in Backups & schedules and Example 01. Restore by picking a Snapshot, described in Restores and Example 03.

  • Auth or token errors. Tokens in rclone.conf expire or get revoked. Re-run rclone config reconnect <remote>: on your own machine and re-paste the config.
  • configSecretRef ignored. Make sure you used configSecretRef, not auth. rclone has no auth block.
  • Always validate with rclone ls <remote>: on your own machine before applying.