On this page
Storage providers
Which stores can hold a fleet's objects, and how each one is declared. The
backend is a replaceable adapter behind the same stado:// object plane: the
canonical layout, the queue and the object API answer the same on every one.
stado capabilities object-storage prints this list from the binary's own
catalog, and storage.backend takes the id or any alias in the first column.
Self-hosted
| Backend | What it is |
|---|---|
stado (alias self-hosted) |
Your own machine and disk: a Stado object API that every host reaches, which also serves the S3 API. See self-host your storage. |
minio |
A MinIO server you run. |
garage |
A Garage cluster you run. |
seaweedfs |
A SeaweedFS S3 gateway you run. |
ceph (alias rgw) |
A Ceph Object Gateway you run. |
local |
A directory on this machine only; a coordinate written here means nothing on another host. |
Hosted
| Backend | Provider | Declares |
|---|---|---|
gcs |
Google Cloud Storage | bucket |
azure |
Azure Blob | account, container |
s3 |
Amazon S3 | bucket, region (the host's AWS identity or the cloud-aws credential) |
cloudflare (r2) |
Cloudflare R2 | account id, bucket |
backblaze (b2) |
Backblaze B2 | region (us-west-004…), bucket |
wasabi |
Wasabi | region (us-east-1…), bucket |
digitalocean (spaces) |
DigitalOcean Spaces | region (nyc3…), bucket |
hetzner |
Hetzner Object Storage | location (fsn1…), bucket |
scaleway |
Scaleway Object Storage | region (fr-par…), bucket |
ovhcloud (ovh) |
OVHcloud Object Storage | region (gra…), bucket |
akamai (linode) |
Akamai (Linode) Object Storage | region, bucket |
vultr |
Vultr Object Storage | location (ewr1…), bucket |
oracle (oci) |
OCI Object Storage, S3 compatibility API | tenancy namespace as account, region, bucket |
ibm (ibm-cos) |
IBM Cloud Object Storage | region (us-south…), bucket |
alibaba (aliyun, oss) |
Alibaba Cloud OSS | region as OSS names it (oss-cn-hangzhou…), bucket |
tencent (cos) |
Tencent Cloud COS | region (ap-guangzhou…), bucket |
huawei (obs) |
Huawei Cloud OBS | region (cn-north-4…), bucket |
exoscale (sos) |
Exoscale Simple Object Storage | zone (ch-gva-2…), bucket |
ionos |
IONOS Object Storage | region, bucket |
contabo |
Contabo Object Storage | region (eu2…), bucket |
upcloud |
UpCloud Managed Object Storage | instance as account, region, bucket |
storj |
Storj S3-compatible gateway | region, bucket |
filebase |
Filebase | bucket |
tigris |
Tigris | bucket |
yandex |
Yandex Object Storage | bucket |
idrive-e2 (idrive, e2) |
IDrive e2 | the endpoint the account was issued, region, bucket |
s3-compatible |
any other S3 API endpoint | endpoint URL, region, addressing, bucket |
Each named provider's endpoint is the one the provider publishes for its S3 API, built from what the table names; its addressing and, where the provider documents a single one, its signing region come with it. Every provider rated here is a preview until a release carries its live acceptance.
Stores that do not speak the S3 API
Not every object store has an S3 API, and Stado does not need one: gcs
is reached through the Cloud Storage JSON API, whose writes are made
conditional on an object's generation (ifGenerationMatch), and azure
through the Blob service REST API, whose writes carry If-None-Match: * and
If-Match: <etag>; local and stado are Stado's own. What every backend
must offer is what the queue relies on: an if-absent create and a
compare-and-swap replacement, so that a claim, a lease or a publication
succeeds for one holder only.
Any other store needs a way to be one of these. If it publishes an S3 API
(most do), it is s3-compatible with its endpoint, and the conditional-write
proof below decides whether it may hold the queue. If it publishes none
(an OpenStack Swift cluster without its S3 middleware, a file share), run an
S3 gateway in front of it that keeps conditional writes, or keep the fleet's
objects in a self-hosted stado store on a disk you own
(self-hosting). A storage.backend the catalog does not
name is refused when the store is opened, before anything is read or
written, with WC_STORAGE_BACKEND=<name> is not supported (use "<every id>"); stado storage copy refuses one for --from/--to with unknown storage backend "<name>"; use one of: <every id>.
Declaring one
Every S3 API store reads the same storage.s3_compatible.* keys, each only
where its provider asks for it, and none has a default:
| Key | Variable | Read by |
|---|---|---|
storage.s3_compatible.bucket |
WC_S3_COMPATIBLE_BUCKET |
every provider |
storage.s3_compatible.credential_role |
WC_S3_COMPATIBLE_CREDENTIAL_ROLE |
every provider: the credential-store role whose item holds the key pair in access_key_id and secret_access_key |
storage.s3_compatible.region |
WC_S3_COMPATIBLE_REGION |
every provider the table above lists with a region, location or zone, self-hosted servers and s3-compatible; the others sign for the one region their provider documents |
storage.s3_compatible.account |
WC_S3_COMPATIBLE_ACCOUNT |
cloudflare, oracle, upcloud |
storage.s3_compatible.endpoint |
WC_S3_COMPATIBLE_ENDPOINT |
self-hosted servers, idrive-e2 and s3-compatible |
storage.s3_compatible.addressing |
WC_S3_COMPATIBLE_ADDRESSING |
s3-compatible only: path or virtual-hosted |
stado config set storage.backend cloudflare
stado config set storage.s3_compatible.account example-account-id
stado config set storage.s3_compatible.bucket example-fleet
stado config set storage.s3_compatible.credential_role example-object-store
A disaster-recovery copy declares the same keys under
storage.backup.s3_compatible.*, with its bucket in storage.backup.bucket.
The key pair never enters the configuration: Stado reads the two fields from
the selected credential store when it opens the store.
Refusals
Each refusal names what is missing and where it is declared:
the <provider> storage backend needs WC_S3_COMPATIBLE_<KEY> (storage.s3_compatible.<key>); nothing declares itthe <provider> storage backend (<product>) needs storage.s3_compatible.<key>; nothing declares itthe <provider> storage backend (<product>) runs where the deployment says: storage.s3_compatible.endpoint must name its URLstorage.s3_compatible.<key> "<value>" is not a single <product> nameWC_S3_COMPATIBLE_ENDPOINT (storage.s3_compatible.endpoint) "<value>" must be an absolute http:// or https:// URLWC_S3_COMPATIBLE_ADDRESSING (storage.s3_compatible.addressing) is "<value>"; use "path" (the bucket in the path) or "virtual-hosted" (the bucket in the host name)the credential playing role <role> holds no access_key_id; the s3-compatible backend reads its key pair from the access_key_id and secret_access_key fields
Conditional writes
The queue's claims, leases and release publications are if-absent creates
(If-None-Match: *) and compare-and-swap replacements (If-Match). Amazon
S3 documents both. Every other S3 API store proves them once, before the
first write that relies on them: Stado creates one object under
system/conditional-writes/<random>, creates it again, replaces it against a
version it never held and removes it; both the second create and the
replacement must be refused with 412. Reads, listings and plain writes never
wait for the proof.
A store that stores either write is refused for every write that relies on
them, for the life of the process, with the <provider> bucket <bucket> at <endpoint> ignores If-None-Match: * (…) and If-Match (…); the queue's claims, leases and publications would succeed for two holders at once. A
check that could not finish (could not be checked for conditional writes: …, or honours conditional writes, but the proof object … could not be removed) decides nothing, and the next such write asks again.
Moving objects to or from one
stado storage copy and stado storage verify address any provider on
either side: --from/--to name the backend, and --from-bucket,
--from-account, --from-region, --from-endpoint, --from-addressing
and --from-credential-role (and their --to- twins) carry what it
declares:
stado storage copy --from local --from-path ~/.stado/local-storage \
--to backblaze --to-region us-west-004 --to-bucket example-fleet \
--to-credential-role example-object-store
Stado Desktop's Space panel offers the same fields under Copy objects between stores and Compare store names, metadata and bytes.
Machines a scheduler rents
An agent on a machine the scheduler rents opens the deployment's store with
what its startup template carries: gcs, azure, s3, local,
s3-compatible and every named provider, primary and backup. Before a
machine is created the scheduler checks, per backend, that every binding the
store needs is declared, and for an S3 API store that the agent's scoped
vault grant (agent.skarbiec.roles) names its credential role, because the
agent reads the key pair with that grant and nothing else. A missing binding
is refused as agent startup setting <variable> is empty; configure <variable> (config key <key>), an ungranted role as … does not name this credential role, so an agent on a rented machine could not read the store's key pair.
A stado store (another Stado's object API) is refused for rented machines:
its bearer is a file on the dispatching host that is never delivered to the
machine. The same self-hosted store is reachable from one through its S3 API:
declare s3-compatible with endpoint <object API>/s3, region stado,
path addressing, and a credential role whose item holds the namespace as
access_key_id and its bearer as secret_access_key. A backend name the
catalog does not know is refused by name. Hosts that run their own Stado
open every backend.
Source: this website