Skip to content

Cloudflare R2

R2 has no charge for data going out, which suits files that people open again and again. Read Files in your own bucket first if you have not.

  1. In the Cloudflare dashboard open Storage & databases → R2, and create a bucket. Note its name. Choose the default location unless you know you need a jurisdiction.
  2. On the R2 Overview page, under Account Details, next to API Tokens choose Manage, then Create Account API token. (A User API token works too, but it stops working when the user leaves the account, so prefer an account token.)
  3. For Permissions choose Object Read & Write. Under the bucket scope choose Apply to specific buckets only and pick this bucket. Bucket scoping exists only for the Object Read & Write and Object Read permissions.
  4. Create the token and copy the Access Key ID and the Secret Access Key. The secret is shown once; it cannot be shown again.
  5. Copy your Account ID too: it is in the dashboard (search for Copy account ID, or on Workers & Pages → Account Details) and in the endpoint shown on the token’s confirmation page.

R2 has no separate ListBucket right to give; Object Read & Write covers read, write and list objects in the bucket. Cloudflare’s page does not say in so many words that it covers deleting an object, and what R2 answers to a HEAD for a file that is missing is not described either. Both are checked by Check and connect (the delete is one of its steps), and a live run will settle them for this page.

Choose Connect a bucket, set Provider to Cloudflare R2, and fill:

FieldValue
Account IDyour Cloudflare account ID
Bucketthe bucket’s name
Folderplune
Access key IDthe token’s Access Key ID
Secret access keythe token’s Secret Access Key — stored encrypted, never shown again

There is no Region field: R2’s region is always auto. Plune reaches the bucket at https://<account id>.r2.cloudflarestorage.com. Signed links work only on that address — R2 does not sign for a custom domain, so a domain you attached to the bucket for public downloads is not used by Plune.

Then Check and connect; the causes of a failure are on When something is wrong.

A bucket created with the EU or FedRAMP jurisdiction is reachable only at its own address (https://<account id>.eu.r2.cloudflarestorage.com, …fedramp.…), and the Cloudflare R2 provider builds the default address only. Connect such a bucket with the provider Other instead: Server address is the jurisdiction address, Region is auto, and Path-style is on. This has not yet been tried against a live bucket.

Screenshots and videos open without it. Traces and text need one rule, and so does a file a person adds in the dashboard: GET and PUT from the dashboard’s address. In the R2 dashboard open the bucket, then Settings → CORS Policy → Add CORS policy, choose the JSON tab, paste this and Save:

[
{
"AllowedOrigins": ["https://app.plune.ai"],
"AllowedMethods": ["GET", "PUT"],
"AllowedHeaders": ["content-type"],
"MaxAgeSeconds": 3600
}
]

On the beta, write https://beta.plune.ai. A change can take up to 30 seconds to apply, in rare cases; browsers may also cap MaxAgeSeconds at two hours. CORS explains the rule and how to check it.

To let objects expire on your side, open the bucket, then Settings → Object Lifecycle Rules → Add rule, scope it to the prefix plune/, choose to delete objects after the number of days you want, and Save changes. R2 removes an object typically within 24 hours of its expiry. Setting rules by API needs a different token (one with the Workers R2 Storage Write permission group); the dashboard is the simple way. A rule on plune/ of about 200 days is a suggestion: see Two clocks for what happens when it is shorter or longer than Plune’s own history.

R2’s S3 API has no versioning, so a delete frees the space.