Docs
Bring your own bucket
On the bucket plans your files live in your Cloudflare R2, Amazon S3 or DigitalOcean Spaces bucket — you own the storage and its bill. Postila handles uploads, your file registry, the SDK, and delivery through our edge: cached, with image transforms and the protection you choose. This guide takes you from an empty cloud account to a connected bucket.
BYO Free vs BYO
Both plans work the same way: your visitor's browser uploads straight into your bucket with a presigned URL, and our edge reads the file from your bucket to deliver it, caching it so repeat views don't touch your bucket. They differ in limits and protection:
| BYO Free — free | BYO — $7/mo | |
|---|---|---|
| Uploads / month | 500 | 50,000 |
| Largest file | 25 MB | 5 GB |
| Viewing / month | Unlimited | 500 GB · 3M requests (soft — never cut off) |
| Image transforms / month | 500 new sizes — past that, the original is served | 3,000 new sizes — past that, the original is served |
| Protection | Public only | Public · hotlink · signed — enforced at our edge |
| Delivery | Through Postila’s edge, cached | Through Postila’s edge, cached |
Create a bucket
We recommend Cloudflare R2: egress is $0, so delivering your files costs you nothing regardless of traffic (S3 charges ~$0.09/GB for the same bytes).
1. Cloudflare dashboard → R2 → Create bucket (any name).
2. R2 → Manage R2 API Tokens → Create API token.
3. Permissions: "Object Read & Write", scoped to THIS bucket only.
4. Copy the Access Key ID + Secret Access Key (shown once).
5. Your endpoint is: https://<ACCOUNT_ID>.r2.cloudflarestorage.com1. AWS console → S3 → Create bucket (Block Public Access ON — see below).
2. IAM → Users → Create user (programmatic access).
3. Attach an inline policy scoped to just this bucket (Get/Put/Delete Object).
4. Create an access key; copy the Access Key ID + Secret.
5. Your endpoint is: https://s3.<REGION>.amazonaws.com1. DigitalOcean control panel → Spaces Object Storage → Create bucket (pick a region, e.g. nyc3).
2. Spaces Object Storage → Access Keys → Create Access Key.
3. Access scope: "Limited Access" → this bucket only → Read/Write/Delete.
4. Copy the Access Key ID + Secret Key (the secret is shown once).
5. Your endpoint is: https://<REGION>.digitaloceanspaces.comScoped credentials
Create a token that can touch only this bucket — never an account-wide key. Postila stores your credentials envelope-encrypted at rest and verifies them hourly with a tiny self-cleaning test object. For S3, this is the inline IAM policy shape:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:PutObject", "s3:GetObject", "s3:DeleteObject", "s3:ListBucket"],
"Resource": ["arn:aws:s3:::YOUR_BUCKET_NAME", "arn:aws:s3:::YOUR_BUCKET_NAME/*"]
}
]
}CORS (required)
BYO uploads are browser → bucket PUTs, so your bucket's CORS policy must allow your app's origin — without it every upload fails in the browser with an opaque error. Paste this on the bucket (R2: Settings → CORS policy; S3: Permissions → CORS; Spaces: Settings → CORS Configurations), replacing the origin with your site:
[{
"AllowedOrigins": ["https://your-app.example.com"],
"AllowedMethods": ["PUT", "GET", "HEAD"],
"AllowedHeaders": ["*"],
"ExposeHeaders": ["ETag"],
"MaxAgeSeconds": 3600
}]Keep the bucket private
Our edge reads your bucket with your credentials (a signed request), so the bucket never needs to be public. Keep it private (on S3, leave Block Public Access on). That makes our edge the only way in, which is what gives hotlink and signed protection their teeth. Your delivery URLs are stable Postila links, whatever the bucket's settings.
Protect your files
Protection is enforced by our edge — there is nothing to configure on your bucket. Set the default in the console under Settings → Delivery protection, or per file:
- Public — anyone with the link can view it. The only option on BYO Free.
- Hotlink (BYO) — only the sites you list can embed the file. This checks the browser's
Origin/Referer, which non-browser clients can fake, so use signed links for anything sensitive. - Signed (BYO) — links your backend signs with the SDK's
getSignedDeliveryUrl. They name one file and expire when you say.
Connect it
With the bucket, token, and CORS in place: console → Settings → Storage and follow the guided wizard (or the manual form). Postila runs a live write/read/delete check against your bucket before anything is saved, verifies CORS for your app origins, and shows exactly what to fix if either fails. One more thing worth knowing: we never delete objects from your bucket — deleting a file in Postila removes our records and cached copies only.