🇬🇧 English | 🇺🇦 Українська
8. Providers¶
Every service listed here implements the same S3 API, but the details differ. Picking a provider in the settings closes most of these gaps automatically; this chapter covers what's worth knowing beyond that.
Every provider in this chapter except DigitalOcean Spaces has been verified end to end: write, read,
metadata, a range request, listing and batch deletion — including keys containing spaces,
ampersands and Cyrillic characters. A separate end-to-end test
(S3.Live.ResumeInterruptedDownload) verifies resuming an interrupted download too — that
If-Match on a ranged GET genuinely makes the provider reject a stale version of an object,
rather than just ignoring the condition. This doesn't follow from the other tests: each
provider implements conditional requests on its own. One more separate test
(S3.Live.CreateAndDeleteBucket) verifies bucket creation and deletion, in particular that
deleting a non-empty bucket is rejected with a clear reason rather than silently emptying it.
What works where¶
| Provider | Write and read | Multipart + cancellation | Copy | Presigned URLs | Tags | Lifecycle rules | Download resume | Create / delete bucket |
|---|---|---|---|---|---|---|---|---|
| Amazon S3 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Cloudflare R2 | ✅ | ✅ | ✅ | ✅ | ❌ 501, not implemented | ✅ | ✅ | ✅ |
| Backblaze B2 | ✅ | ✅ | ✅ | ✅ | ⚠️ a B2 bug | ✅ | ✅ | ✅ |
| Google Cloud Storage | ✅ | ✅ | ✅ | ✅ | ❌ 400, not implemented | ❌ its own schema | ✅ | ✅ |
| MinIO | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Wasabi | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ⚠️ deletion may be blocked by the account |
✅ verified end to end against the real service · ⚠️ mostly works, with a known quirk · ❌ the provider doesn't implement this part of the S3 API. Details are in each provider's own section below; click a name in the table.
Amazon S3¶
| Endpoint URL | leave empty |
| Region | your bucket's region |
| Path Style Addressing | off |
Regional endpoints. s3.amazonaws.com only serves us-east-1. Any other region has to go
to s3.<region>.amazonaws.com, or the provider answers with 301. The plugin substitutes the
correct host on its own — so the endpoint field can stay empty as long as you set the region.
Bucket creation outside us-east-1 requires naming the region in the request body. The
plugin adds it where needed, and doesn't add it where doing so would itself be an error.
Bucket names are globally unique across every Amazon customer. A plausible name is usually already taken — that's normal, not a sign of a problem.
Cloudflare R2¶
| Endpoint URL | https://<account-id>.r2.cloudflarestorage.com |
| Region | auto — that exact literal |
| Path Style Addressing | on |
Listing buckets doesn't work. R2 doesn't implement this operation and always answers with 403. Create and browse buckets in the Cloudflare dashboard instead.
Object tags don't work. R2 answers Set Object Tags with 501 NotImplemented — not a
permissions error, but a direct statement from the provider that this part of the S3 API is
absent. If you need tags specifically on R2, use custom metadata (Set Metadata) instead — not
the same mechanism (metadata is immutable without rewriting the object), but it's what R2
supports.
Everything else — upload, download, server-side copy, multipart upload and its cancellation, presigned URLs — has been verified and works normally.
Lifecycle rules require a separate token permission. Get/Set/Delete Bucket
Lifecycle is a bucket-level action, not an object-level one, and an ordinary "Object Read &
Write" R2 token isn't enough for it: without the right permission, Set Bucket Lifecycle
answers with 403 Access Denied, the same way any other action without the right permission
would. The API itself supports this fine — verified end to end, and it started working
immediately once the token's permissions were changed.
The token for this isn't created on the general Account → API Tokens page (there's no R2 template there at all), but specifically on the R2 → Manage R2 API Tokens page — a separate one, with R2's own templates. Pick Admin Read & Write there (not just "Object Read & Write") and, if you want, narrow the Bucket scope to one specific bucket.
Compression of text content types. R2 compresses responses for text Content-Types on the
fly. The visible consequence: for an object like that, the response carries a weak ETag
(W/"...") and no length at all.
The plugin accounts for this: metadata requests ask for an uncompressed representation, and ETags get normalized, so an identifier from R2 compares correctly against the same object's identifier on any other service. Nothing extra to do here — but if you talk to R2 outside the plugin, it's worth keeping in mind.
Backblaze B2¶
| Endpoint URL | https://s3.<region>.backblazeb2.com |
| Region | from the Endpoint field in the B2 console |
| Path Style Addressing | on |
The endpoint and region depend on where the bucket was created. Both are visible in the B2 console, under the bucket's properties, in the Endpoint field.
B2 calls the secret key an "application key."
A lifecycle rule with only Expire After Days is rejected by B2. A request that Amazon,
MinIO, R2 or Wasabi accept without question comes back here as 400 MalformedXML, with
an explanation that there's an Expiration rule but no matching ExpiredObjectDeleteMarker rule
with the same prefix — B2 is natively versioned, so Expire After Days there always leaves
behind a delete marker instead of erasing the object outright. The full mechanism is explained
in
4. Blueprint Operations.
A working pair of rules for B2 — the same Prefix, different Ids:
Make Array
[0] Id = "expire-temp" Prefix = "logs/" Expire After Days = 30
[1] Id = "expire-temp-markers" Prefix = "logs/" Expire Orphaned Delete Markers = true
Expire Orphaned Delete Markers was added to FS3LifecycleRule for exactly this case —
verified end to end against a real B2 bucket.
Reading tags after deleting them on B2 can return 405, rather than an empty list.
Set Object Tags and the first Get Object Tags after it work normally; after
Delete Object Tags, that same Get Object Tags on the same object sometimes answers with
405 MethodNotAllowed instead of the expected empty tag set. This is B2's own behavior,
reproduced by the end-to-end test; if something suddenly fails with 405 on B2 right after
deleting tags where it used to work, this is why — not a regression in your own code.
S3 Create Bucket / S3 Delete Bucket require a key with account-level permissions.
B2's own officially documented scenario — aws s3api create-bucket against a B2 endpoint —
works exactly the way it does against any other S3-compatible provider. But an application key
scoped to one specific bucket (the usual practice for B2) has no permission to create a new
bucket in the account — the provider answers 403 AccessDenied, and the plugin surfaces that
directly rather than failing silently. Create a key without a bucket restriction if you need
bucket management from code.
Google Cloud Storage¶
| Endpoint URL | leave empty |
| Region | auto |
| Path Style Addressing | on |
The plugin talks to Google's S3-compatible XML API, not its native API. That means it needs HMAC keys, not a service account's JSON key — in the console that's Cloud Storage → Settings → Interoperability → Create a key.
Google rewrites the Accept-Encoding header, so the plugin deliberately leaves it out of the
signature. This is an implementation detail, but it's exactly why some other clients get 403
from GCS in cases where every other service works fine.
Lifecycle rules don't work through the S3 API at all. Even through the "S3-compatible" XML
API, GCS's ?lifecycle endpoint expects a separate, non-S3 request body format: instead of
the standard <Filter>/<Status>/<Expiration>, it has its own vocabulary of
<Rule><Action>...</Action><Condition>...</Condition></Rule>. Set Bucket Lifecycle sends a
correct document per the S3 spec — the same one Amazon, MinIO and (partly)
other providers accept — and GCS answers 400 MalformedLifecycleConfiguration, because it's not
the document it's expecting. This isn't a plugin bug, and it isn't something a different request
encoding would fix: to manage a bucket's lifecycle on GCS, set the rules in the
Google Cloud Storage console instead.
S3 Create Bucket / S3 Delete Bucket require the Storage Admin role on the project.
The role the GCS console offers by default when creating an HMAC key for interoperable
access — Storage Object Admin — acts at the bucket level and doesn't include the
storage.buckets.create permission, which is
officially documented as
required for creating a bucket through the XML API; with it, the request answers
400 InvalidArgument (reproduced both by the plugin and independently, with the same key
through mc mb, with no plugin code in the path at all). Grant the key the Storage Admin role
at the project level instead of Storage Object Admin if you need bucket management from code.
Creating a bucket through the XML API additionally requires either an x-goog-project-id
header (the plugin doesn't send it — it's a non-standard, non-S3 field) or a default project for
interoperable access set in the Interoperability console — a one-time setup, after which an
ordinary request works with no extra header.
MinIO¶
| Endpoint URL | http://host:9000 |
| Region | any value, but it takes part in the signature |
| Path Style Addressing | on |
MinIO runs anywhere — on a workstation, in your own data center, in a managed cluster. The quirks are the same in every case.
Buckets need to be created ahead of time. MinIO doesn't create a bucket
on the first write attempt: you'll get NoSuchBucket. Create it with the S3 Create Bucket
node, through the MinIO console, or with mc mb — the plugin doesn't
restrict the method in any way.
Region isn't checked by MinIO, but the signature still has to be consistent, so the field can't be left empty. The default value works fine.
The scheme is http://, unless you've set up TLS. This is the most common reason a local
MinIO instance "doesn't respond."
Wasabi¶
| Endpoint URL | https://s3.<region>.wasabisys.com, e.g. https://s3.eu-central-1.wasabisys.com |
| Region | the same one as in the endpoint — Wasabi doesn't redirect from a wrong regional host the way Amazon does |
| Path Style Addressing | on |
The closest thing to plain S3, with no exceptions: write, read, copy, tags, lifecycle rules and resuming an interrupted download all passed the end-to-end test without a single caveat, where other providers trip up one way or another.
But the account can block bucket deletion, even for an empty bucket. In the end-to-end
test, S3 Create Bucket worked normally, and the following S3 Delete Bucket on that same,
freshly-created and empty bucket answered 424 Failed Dependency, explaining "Bucket Delete
Activity ... was blocked by Security Contacts in place." This is an account-level security
feature on Wasabi (protection against accidental or malicious bucket
deletion, confirmed by security contacts), not a request error — the exact same request worked
without issue on MinIO, R2 and Amazon S3. If
you need programmatic bucket deletion on Wasabi, this feature has to be
turned off or confirmed in the Wasabi console beforehand; otherwise the
plugin correctly reports the refusal rather than trying to work around it.
DigitalOcean Spaces¶
| Endpoint URL | https://<region>.digitaloceanspaces.com, e.g. https://nyc3.digitaloceanspaces.com |
| Region | the same one as in the endpoint |
| Path Style Addressing | on |
⚠️ Not verified live. Unlike every other provider in this chapter, DigitalOcean Spaces hasn't yet passed an end-to-end test against a real account — everything below is taken from the provider's own official documentation, not confirmed by a request from the plugin. And the gap between what's documented and what actually happens is more the rule than the exception here: of the six providers verified live, three (Cloudflare R2, Backblaze B2, Google Cloud Storage) turned out to diverge from their own documentation exactly on tags and lifecycle rules — precisely what's claimed below. Treat this as claimed, not proven.
Per the official Spaces API reference:
- Object tags (
Get/Put/Delete Object Tags) are documented as supported. - Lifecycle rules (
Get/Set/Delete Bucket Lifecycle) are also documented as supported — but with a separate documented condition: a rule can't be filtered by tags, only by prefix and duration. That is,PrefixandExpireAfterDaysinFS3LifecycleRuleshould work, butTagFilterslikely won't.
Another service¶
Pick Custom / Other and fill in the fields by hand. Almost always you'll need:
- Path Style Addressing — on. Virtual-hosted addressing among S3-compatible services is used almost exclusively by Amazon.
- Region — anything consistent; if the service has no regions,
us-east-1works.
After that — the Test Connection button: if the configuration is wrong, the report names the specific setting.
Next: 9. Testing