Overview
By default, Tornado uploads files to our managed storage. You can configure your own cloud storage to receive downloads directly.Tornado supports all major S3-compatible providers, Azure Blob Storage, Google Cloud Storage, Alibaba OSS, and Google Drive delivery — giving you flexibility to use the storage solution that best fits your infrastructure.
Supported Providers
AWS S3 / S3-Compatible
AWS S3, Cloudflare R2, MinIO, DigitalOcean Spaces, Backblaze B2, Wasabi, OVH
Azure Blob Storage
Azure Storage Accounts with Blob containers
Google Cloud Storage
GCS buckets with service account authentication
Alibaba OSS
Alibaba Cloud Object Storage Service
Google Drive
Service-account delivery to a Drive folder (see Configure Google Drive)
Only S3 currently has a “Check” (
GET) endpoint to read back the saved configuration. The other providers don’t have one yet — if you need to confirm what’s configured for Blob/GCS/Drive/OSS today, the only way is to run a test job and inspect where the file lands.S3 / S3-Compatible Storage
Works with AWS S3 and any S3-compatible provider.Supported S3 Providers
Configure S3 Storage
Cloudflare R2 Setup
Cloudflare R2 Setup
1
Create R2 Bucket
In Cloudflare dashboard, go to R2 and create a new bucket.
2
Create API Token
Create an R2 API token with Object Read & Write permissions.
3
Get Account ID
Find your Account ID in the Cloudflare dashboard URL or overview page.
4
Configure Tornado
Required S3 Permissions
s3:ListBucket is not required and used to be listed here in error. Nothing in Tornado
enumerates your bucket: it writes to a key it computed itself, signs a URL for that key, and
deletes by key.s3:AbortMultipartUpload replaces it. Above 50 MB uploads are multipart, and without the
abort permission an upload that fails part-way leaves its parts in the bucket. They are not
objects, so they never appear in the object listing, and AWS bills them as storage until
something removes them. CreateMultipartUpload, UploadPart and CompleteMultipartUpload
need nothing added: AWS maps all three to s3:PutObject.For the full minimum and recommended sets, including the optional
s3:ListBucketMultipartUploads on the bucket ARN, see the
AWS S3 and S3-compatible guides.Azure Blob Storage
Use Azure Storage Accounts with Blob containers.Configure Azure Blob
Azure Setup Guide
Azure Setup Guide
1
Create Storage Account
In Azure Portal, go to Storage Accounts > Create.
- Choose Standard performance
- Select Hot access tier
- Enable Blob public access if needed for direct URLs
2
Create Container
In your Storage Account, go to Containers > + Container.Name it (e.g.,
tornado-downloads).3
Get Access Key
Go to Access keys in your Storage Account.Copy key1 or key2.
4
Configure Tornado
Alternative: SAS Token
POST /user/blob accepts a SAS token instead of the account key.
account_key OR sas_token, not both.
Required Azure Permissions
Sized for what Tornado actually calls, a SAS needs signed servicesb (blob), signed resource
types o (object), and the permission string rwd:
- Read (r) - Reading a delivered blob.
- Write (w) - Uploading. Azure defines
was “Create or write content, properties, metadata, or block list”, which covers Put Blob, Put Block and Put Block List. Create (c) on its own is not enough, because a retry overwrites an existing blob. - Delete (d) - Cleanup after the credential probe.
l) is not needed. Nothing in the delivery path enumerates the container, and l is
not even a valid permission on a blob-scoped SAS. Neither are a (add), t (tags), i or p.
With the account key instead of a SAS there is nothing to size: the key grants full access to
every container, blob, queue, table and file share in the account, and cannot be narrowed. Give
Tornado a storage account used only for deliveries.
Google Cloud Storage
Use GCS buckets with service account authentication.Configure GCS
GCS Setup Guide
GCS Setup Guide
1
Create GCS Bucket
In Google Cloud Console, go to Cloud Storage > Create Bucket.
- Choose a unique name
- Select your preferred region
- Choose Standard storage class
2
Create Service Account
Go to IAM & Admin > Service Accounts > Create Service Account.Name it (e.g.,
tornado-storage).3
Grant Permissions
Assign the Storage Object Admin role to the service account for your bucket:
4
Download JSON Key
In the service account details, go to Keys > Add Key > Create new key > JSON.Download and save the JSON file.
5
Configure Tornado
Use the JSON key content (minified):
Required GCS Permissions
Three object permissions, granted on the bucket and not on the project:storage.objects.create- every upload, and the credential probe.storage.objects.get- signed download URLs, andobjects.composereading its own source parts on files of 100 MB or more.storage.objects.delete- temp-part cleanup, probe cleanup, and overwriting on retry.
roles/storage.objectUser is the smallest predefined role that covers them;
roles/storage.objectAdmin also works. roles/storage.objectCreator does not: it carries
create and nothing else, so files of 100 MB or more fail and every download link returns 403.
See the Google Cloud Storage guide for the full breakdown.
Alibaba Cloud OSS
Alibaba OSS uses its own endpoint and credential format.Configure Alibaba OSS
OSS Endpoint Regions
Folder Prefix
All providers support an optionalfolder_prefix to organize your downloads:
The folder prefix is placed inside the base folder (
videos/ by default) and combined with any folder parameter you specify in individual job requests.Base Folder
All providers support an optionalbase_folder parameter to change the top-level folder where files are organized. By default, files are placed inside a videos/ folder.
Examples
Default behavior (nobase_folder specified):
base_folder:
folder_prefix:
If you don’t specify
base_folder, it defaults to videos for backward compatibility. The base_folder is always the top-level folder, with folder_prefix nested inside it.Presigned URLs
When you poll job status, thes3_url field contains a presigned/signed URL for your bucket:
Legacy Endpoint (S3 Only)
The/user/bucket endpoint still works for S3-compatible storage only:
Reset to Default Storage
To switch back to Tornado’s managed storage, use the DELETE endpoint for your provider:After removing, all new downloads will use Tornado’s managed storage. Existing files in your custom storage remain untouched.
Troubleshooting
Common Errors
Job completed, but the file isn’t in my storage
The job reportsCompleted but the file is nowhere in your bucket/container.
Almost always, the job was submitted with an API key that has no storage
configured, so it was uploaded to Tornado’s managed storage instead of yours.
Remember that storage is configured per API key, not per account — a config
on one key does not apply to another.
1
Confirm which key you used
Check the
x-api-key header on the request that created the job. Storage is
resolved from that key only.2
Verify that key has storage configured
For S3, read it back with
GET /user/s3. The
other providers have no read-back endpoint yet, so confirm with a test job.3
Configure storage on the correct key
Re-run the configuration endpoint using the key you actually send jobs with,
then re-run the job.
Testing Your Configuration
After configuring storage, create a test job to verify everything works:s3_url, your storage is configured correctly.
Inline Storage (Per-Request)
For marketplace users or one-off configurations, you can provide storage credentials directly in the job request:Inline storage credentials:
- Take priority over pre-configured storage
- Are validated before the job is accepted
- Are never logged. For direct API users they are not persisted; for marketplace users they are stored encrypted and reused automatically on subsequent requests
- Support 4 providers (S3, Azure Blob, GCS, OSS) — Google Drive is available via
/user/gdriveonly, not inline - Support
folder_prefixandbase_folderparameters
For API marketplace users (RapidAPI, Apify, Zyla), inline storage credentials are required for every request.
See the Marketplace Integration guide for details.
Security Best Practices
Use Least Privilege
Use Least Privilege
Create dedicated credentials with only the permissions needed:
- S3: Custom IAM policy with
s3:PutObject,s3:GetObject,s3:DeleteObjectands3:AbortMultipartUploadon one bucket - Azure: The account key cannot be scoped, so narrow the account instead: use a storage account dedicated to Tornado deliveries. A SAS is narrower but costs you every download link
- GCS: Service account with
roles/storage.objectUseron the specific bucket, granted on the bucket and not the project
Rotate Credentials Regularly
Rotate Credentials Regularly
Set up credential rotation:
- AWS: Use IAM Access Analyzer
- Azure: Set SAS token expiration
- GCS: Rotate service account keys
Enable Bucket Logging
Enable Bucket Logging
Monitor access to your storage:
- S3: Enable Server Access Logging
- Azure: Enable Storage Analytics
- GCS: Enable Cloud Audit Logs
