Where backups go: destinations, encrypted
Where backups can go, provider by provider, what has been tried against each real service, and how a destination is encrypted and watched.
Part of Backups and disaster recovery.
Provider guides
A destination is an rclone remote; the --type decides which. Object stores take the bucket (or
container) as the first part of the folder: --field path=my-bucket/noust-backups. A destination
is tried when it is saved: noust backup destination add and update (and POST and PUT /api/backup-destinations) create the folder, which is the first real write so a key that can only
read fails here, and list it, exactly as noust backup destination test NAME does, and keep nothing
that does not answer. --skip-test ("verify": false in the API) saves one that is down on purpose.
For an object store the bucket must already exist: Noust looks at it first, read only, and says
so, instead of creating a bucket in your account out of a mistyped name. So the matrix that matters
is your own: a provider is supported on your account when destination add succeeds. Noust's offline
tests pin what is passed to rclone for each type below, not how a provider answers; the next
subsection says what has been run against a real server.
| Where | --type |
What to give |
|---|---|---|
| Amazon S3 | s3 |
provider=AWS, region, the access key; no endpoint |
| Cloudflare R2 | s3 |
provider=Cloudflare, endpoint=https://<account>.r2.cloudflarestorage.com |
| Backblaze B2 | b2 (native) or s3 |
account and application key; or provider=Backblaze, endpoint=https://s3.<region>.backblazeb2.com |
| Hetzner Object Storage | s3 |
provider=Hetzner, endpoint=https://<location>.your-objectstorage.com |
| Wasabi | s3 |
provider=Wasabi, endpoint=https://s3.<region>.wasabisys.com |
| DigitalOcean Spaces | s3 |
provider=DigitalOcean, endpoint=https://<region>.digitaloceanspaces.com |
| Scaleway | s3 |
provider=Scaleway, endpoint=https://s3.<region>.scw.cloud, region |
| IDrive e2 | s3 |
provider=IDrive, the endpoint of your bucket's region |
| MinIO | s3 |
provider=Minio, your own endpoint |
| Ceph (RadosGW) | s3 |
provider=Ceph, your own endpoint |
| Supabase Storage, Vultr and other S3 | s3 |
provider=Other, the endpoint they give you |
| Azure Blob Storage | azureblob |
account and the account key |
| Google Cloud Storage | gcs |
the JSON key of a service account (read from --stdin) |
| An SSH server | sftp |
host, user, and a password or key_file |
| An FTP server | ftp |
host, user, password, and explicit_tls=true (plain FTP sends the password in clear) |
| A NAS | smb, webdav or sftp |
host, user, password |
| Nextcloud, ownCloud | webdav |
url, vendor, user, an app password |
| Google Drive, OneDrive, Dropbox, Box, pCloud | drive, onedrive, dropbox, box, pcloud |
the token rclone authorize <type> prints on your own computer |
| A disk this server mounts | local |
an absolute path |
A provider name outside the list of the S3 form is passed to rclone as written (provider=Alibaba):
rclone knows more of them than the form offers. An address inside this machine's own networks (a NAS
on the LAN, a local MinIO) is refused until it is named in security.allow_private_hosts.
What has been tried against the real service
The table above says what Noust passes to rclone. This one says what has been run against a real server, when, and with which rclone. A row is added when its run is, with the date it was run:
| Where | Last tried | rclone | What ran |
|---|---|---|---|
MinIO (s3, provider=Minio) |
2026-10-17 | 1.60.1 | A bucket that does not exist is refused and not created; a wrong key is refused with the server's own words and nothing is kept; a name MinIO would refuse is stopped before the network; a file goes up, is listed, comes back identical and is deleted, in clear and encrypted |
An SSH server (sftp) |
2026-10-17 | 1.60.1 | Against rclone's own SFTP server: tried and kept, a wrong password refused and not kept, a file sent (verified by MD5), listed, fetched back identical and deleted |
A WebDAV server (webdav, vendor=other) |
2026-10-17 | 1.60.1 | Against rclone's own WebDAV server, the same steps, the upload verified by size |
The rclone is the 1.60.1 package of the harness image (v1.60.1-DEV); a newer one is expected to
behave the same and has not been tried. The SFTP and WebDAV rows prove Noust's side of the
protocol (what it passes, what it keeps, what it refuses) against rclone's server for it, which is a
different implementation from the client's side; they do not prove a particular vendor's quirks.
Not tried against the real service, and so supported as far as rclone documents it and no
further: Amazon S3, Cloudflare R2, Backblaze B2, Hetzner Object Storage, Wasabi, DigitalOcean
Spaces, Scaleway, IDrive e2, Ceph, Supabase Storage and Vultr, Azure Blob Storage, Google Cloud
Storage, an FTP server, SMB, Nextcloud and ownCloud, Google Drive, OneDrive, Dropbox, Box, pCloud.
Prove yours with noust backup destination add; if it connects, the same steps ran.
The runs are python tests/integration/backups_run.py --scenario s3_destination and --scenario protocol_destinations (Docker; they create noust-test-w6b-* containers with the label noust.test=1
and remove them).
Amazon S3 with the least access. Give the key only what a backup needs; this policy is the whole of it (replace the bucket):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:ListBucket", "s3:GetBucketLocation"],
"Resource": "arn:aws:s3:::my-noust-backups"
},
{
"Effect": "Allow",
"Action": ["s3:PutObject", "s3:GetObject", "s3:DeleteObject"],
"Resource": "arn:aws:s3:::my-noust-backups/*"
}
]
}noust backup destination add offsite --type s3 \
--field provider=AWS --field region=eu-west-1 --field access_key_id=AKIA... \
--field path=my-noust-backups/server-1 --stdin < secret-access-key.txt
noust backup destination test offsiteCloudflare R2. Create an API token with "Object Read & Write" on the bucket; R2 has no regions, so
leave region empty and use the account's endpoint.
Google Cloud Storage. Create a service account, give it Storage Object Admin on the bucket only,
download its JSON key and pass it whole: --stdin < key.json. bucket_policy_only=true is right for a
bucket with uniform bucket-level access, which is the default for new ones.
Azure Blob Storage. The container must exist; --field path=container/noust-backups. The account key
is under Access keys of the storage account.
Backblaze. The native b2 type uses an application key limited to one bucket; the S3 type works with
the same key against the S3 endpoint of the bucket's region. Either is fine; native is one request fewer
per file.
What a provider does with a bucket's own lifecycle rules (versioning, object lock, expiry) is its
business and Noust's retention does not know about it: a lifecycle rule that deletes objects younger
than the schedule keeps them makes a backup disappear from under the schedule, and noust backup verify is how you find out.
Destinations are encrypted, and watched
A destination made without a word about encryption wraps the remote in rclone's crypt backend with a
key generated here and printed once by noust backup destination show-key: noust backup destination add --encrypt/--no-encrypt (on by default), encrypted in the API (true, false or omitted), and
backup.encrypt_new_destinations: false turns the default off for a server that wants plain copies.
What the operator said wins; a key given to read backups already there means encryption; otherwise the
default. The ens-medium profile refuses an upload to an unencrypted destination whatever the default is.
The monitor announces a backup that was never taken, which fails nothing, and a destination that went
away, which fails only the next upload: backup_missing when no successful run of a schedule, a
database's policy, an application's data policy or Noust's own backup is newer than
monitor.backup_missing_days (2; a weekly or monthly schedule is given its period and a day; 0 turns it
off), once, then every day while it stays true; and destination_unreachable when a destination some
policy sends to does not answer (asked every monitor.backup_check_hours, as noust backup destination test asks), once per outage with rclone's own words, and again when it answers. Both are switches under
notifications.events.