CORS on Cloudflare R2
This guide covers the manual CORS setup when Relyn’s auto-attempt didn’t go through. Takes about a minute in the Cloudflare dashboard.
Apply the policy
Section titled “Apply the policy”-
Open the bucket in Cloudflare R2. In the Cloudflare dashboard, go to R2 → Overview, click the bucket you just connected to Relyn, then Settings in the top tab bar.
-
Scroll to “CORS Policy” and click Add CORS policy (or Edit if one already exists).
-
Paste the JSON policy. Two versions, depending on whether you want the minimum-to-test or production-ready setup.
Minimal (just enough to test from local dev)
[{"AllowedOrigins": ["http://localhost:5173"],"AllowedMethods": ["GET"]}]Production-ready (recommended) — replace
https://studio.relyn.appwith your studio URL if you self-host:[{"AllowedOrigins": ["https://studio.relyn.app","http://localhost:5173"],"AllowedMethods": ["GET", "PUT", "HEAD", "POST", "DELETE"],"AllowedHeaders": ["*"],"ExposeHeaders": ["ETag"],"MaxAgeSeconds": 3600}] -
Save. CORS changes propagate within a few seconds.
-
Back in Relyn, open the bucket and click Diagnose — the yellow warning will clear once the preflight check confirms the policy works.
What each field does
Section titled “What each field does”- AllowedOrigins — exact web origins the browser is allowed to call from. No wildcards needed for Relyn.
- AllowedMethods —
GET,PUT,HEADcover normal uploads + reads.POSTandDELETEare for multipart uploads and bulk-delete from the gallery. - AllowedHeaders: [”*”] — Relyn sends a few custom headers in presigned PUTs (content-type, x-amz-*). Wildcard is safe because the upload URL is short-lived and scoped to one object.
- ExposeHeaders: [“ETag”] — required so multipart uploads can read the part ETag back. Single-part uploads don’t strictly need it; exposing ETag is harmless.
- MaxAgeSeconds: 3600 — how long the browser caches the CORS preflight. One hour is comfortable.
Why Relyn doesn’t keep retrying this
Section titled “Why Relyn doesn’t keep retrying this”The auto-attempt fires once, on bucket connect, when you’ve just provided fresh credentials. That’s the only moment the request makes sense — you’re actively setting the bucket up and we have your explicit attention.
After that, the bucket belongs to you again. Relyn doesn’t keep retrying
PutBucketCors in the background because the keys you give us may
legitimately be scoped to object operations only (Get / Put /
Delete on objects), without PutBucketCors on the bucket itself. That’s
a sensible permission posture and we don’t want a UI that pretends otherwise.
Further reading
Section titled “Further reading”- Cloudflare R2: Configure CORS for buckets — official docs
- W3C CORS specification — if you want to read the spec