S3 Compatibility
Differences between the Shelby S3 Gateway and standard S3-compatible storage
The Shelby S3 Gateway implements a subset of the Amazon S3 API. While most S3 tools work out of the box, there are key differences from standard S3 (and S3-compatible services like MinIO or Cloudflare R2) that you should be aware of.
ETags Use SHA2-256, Not MD5
In standard S3, the ETag for a single-part upload is the MD5 hash of the object data. The Shelby S3 Gateway instead returns the blob merkle root — a SHA2-256 based hash derived from Shelby's erasure-coded storage commitments.
This means:
- ETags are consistent across all operations —
PutObject,GetObject,HeadObject, andListObjectsall return the same ETag for a given object. - ETags are not MD5 digests. S3 clients that compute a local MD5 and compare it to the returned ETag for integrity checking will see a mismatch. This does not indicate corruption.
- Tools like rclone that compare ETags across
ListObjectsandPutObjectresponses to detect changes work correctly, since all routes return the same value.
If your S3 client warns about ETag mismatches, you can typically disable MD5 checksum
verification. For example, in rclone, the gateway's consistent ETags ensure that rclone copy
and rclone sync correctly detect unchanged files without re-uploading.
Buckets Are Aptos Addresses
In standard S3, bucket names are globally unique strings (e.g., my-app-data). In Shelby,
a bucket is your Aptos account address (e.g., 0x0694a79...).
- You can only write to and delete from the bucket matching your signer's address.
- Bucket creation is implicit — there is no
CreateBucketoperation. Buckets exist as long as the corresponding Aptos account exists. ListBucketsreturns the set of account addresses configured in your gateway config.
Expiration Is Required on Upload
Standard S3 objects persist indefinitely (unless lifecycle rules are configured at the bucket level). Shelby requires an explicit expiration for every blob at upload time.
Set the expiration via S3 metadata headers:
| Header | Example |
|---|---|
x-amz-meta-expiration-seconds (recommended) | 86400 (24 hours) |
x-expiration-seconds (fallback) | 86400 |
Uploads without an expiration header will be rejected with an InvalidArgument error.
See Uploads for details.
No Object Overwrite
Standard S3 allows overwriting an existing object by uploading to the same key. Shelby does not support in-place overwrites because blobs are registered on-chain with a unique merkle commitment.
- Uploading the same content to an existing key is idempotent — the gateway detects the
matching merkle root and returns
200 OK. - Uploading different content to an existing key returns
409 ObjectAlreadyExists. To replace an object, delete it first, then upload the new version.
Supported Operations
The gateway implements a focused subset of the S3 API:
| Operation | Supported |
|---|---|
GetObject (with Range) | Yes |
HeadObject | Yes |
PutObject | Yes |
DeleteObject | Yes |
DeleteObjects (batch) | Yes |
ListObjectsV1 | Yes |
ListObjectsV2 | Yes |
ListBuckets | Yes |
HeadBucket | Yes |
CreateMultipartUpload | Yes |
UploadPart | Yes |
CompleteMultipartUpload | Yes |
AbortMultipartUpload | Yes |
CopyObject | No |
CreateBucket / DeleteBucket | No |
PutBucketPolicy / ACLs | No |
Object versioning | No |
Object tagging | No |
Server-side encryption (SSE) | No |
Presigned URLs | No |
No Server-Side Copy
CopyObject is not supported. To copy an object, download it with GetObject and re-upload
with PutObject.
Unsupported Headers
Many standard S3 request headers are accepted but silently ignored. The gateway will not return an error if you include them, but they have no effect:
| Header Category | Examples |
|---|---|
| Server-side encryption | x-amz-server-side-encryption, x-amz-server-side-encryption-customer-algorithm, x-amz-server-side-encryption-customer-key |
| Storage class | x-amz-storage-class (all objects are stored as STANDARD) |
| Object lock / legal hold | x-amz-object-lock-mode, x-amz-object-lock-legal-hold |
| Tagging | x-amz-tagging |
| ACL | x-amz-acl, x-amz-grant-read, x-amz-grant-write, x-amz-grant-full-control |
| Replication | x-amz-replication-status |
Unrecognized headers are silently ignored and will not cause request failures. This allows most S3 clients to work without disabling features they send by default.
Authentication
The gateway uses standard AWS SigV4 request signing. The accessKeyId and
secretAccessKey are shared secrets between your S3 client and the gateway — they are
not AWS credentials. See Configuration
for setup.