The bucket itself does not have to be public. PostQueen can serve media from your own domain and
read it privately. That is decided in the Decide where media is read from step below, and it is
the choice on this page most worth reading twice.
Deciding whether you need it at all? Uploads and Storage compares it with
the local disk. This page is the setup, start to finish.
1
Create account and login to the console
Go to the Cloudflare Dashboard, and register if needed, then login.
2
Create a new Bucket
In the dashboard sidebar, head to the R2 page.
Create a new Bucket.

- Choose Automatic
- Choose Standard

3
Create your R2 Token
Create your R2 Token by going to R2 Object Storage:
Click on the API dropdown, and select Manage API tokens:
Copy your Account ID for later, and click on “Create an API token”:
Create an Account API token:
Under “Permissions” choose “Object Read & Write” and under “Specify bucket(s)” search for your created Bucket.





Should you later add a bucket for backups, give that its own token rather
than widening this one. The two jobs have no reason to share credentials,
and a backup tool has no business being able to delete the media it is
protecting.
4
Copy your credentials
After the R2 Token is created, copy your “Access Key ID” and “Secret Access Key”:
Paste the respective information into your configuration.

Leave
CLOUDFLARE_REGION as auto unless you deliberately pinned your bucket to one
location when you created it, in which case use that location hint instead.5
Decide where media is read from
CLOUDFLARE_BUCKET_URL is the address stored with every media row. It is
not only what your browser loads: several networks fetch it with their
own servers rather than accepting the file from you. Instagram and
Facebook take an image_url, and TikTok photo posts support nothing else.
So this address has to be reachable from the public internet, and it is
worth choosing deliberately.Serving through PostQueen needs nothing in Cloudflare, just the setting:
The
/api prefix is required. Inside the container nginx maps /uploads/
to a local directory and only /api/ reaches the backend.
6
Set the CORS policy (only if the browser uploads directly)
By default the browser uploads to R2 itself, using a URL PostQueen signs for
it, and that is a cross-origin request the bucket has to allow.Edit the CORS policy on the bucket and add the following, replacing the
origin with your own:
If you run with
UPLOAD_VIA_SERVER=true, skip this
step. The browser never talks to R2 in that mode, so no CORS policy applies.
Credentials, a bucket URL and, where the browser uploads directly, a CORS policy are the whole of
the R2 setup. Point
STORAGE_PROVIDER at cloudflare in
Uploads and Storage and new media goes to the bucket.Backing the bucket up
Media that lives in R2 is no longer in a Docker volume, so a volume backup does not include it. Backups and Upgrades covers what that changes.Unfinished uploads
A multipart upload that never completes leaves its parts in the bucket. They appear in no object listing and are still stored, so it is the kind of thing that grows quietly.Cloudflare adds a default lifecycle rule to every bucket that aborts them after
seven days, visible under Settings → Object lifecycle rules. Nothing to set
up; worth knowing it is what keeps an interrupted upload from costing you
indefinitely.
Next steps
Uploads and storage
Local disk against R2, the 1 GB limit, and what
UPLOAD_VIA_SERVER changesWhen an upload fails
Payload limits, the formats that cannot be fetched from a URL, and cancel-in-flight
Backups and upgrades
Which volumes carry real data once your media has moved out of them
Configuration reference
Every environment variable she reads, including the
CLOUDFLARE_ set