Skip to content

CORS on Amazon S3

S3 uses the same CORS policy shape as Cloudflare R2 (the spec is shared). This guide walks the AWS Console path; if you use aws s3api put-bucket-cors or Terraform / CloudFormation, the JSON below works the same.

  1. Sign into the AWS Console and navigate to S3Buckets.

  2. Click your bucket name, then the Permissions tab in the top navigation.

  3. Scroll to “Cross-origin resource sharing (CORS)” and click Edit.

  4. Paste the JSON below, replacing https://studio.relyn.app with 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
    }
    ]
  5. Save changes. AWS applies CORS within seconds.

  6. Back in Relyn, open the bucket and click Diagnose. The yellow warning clears once the preflight confirms.

Terminal window
aws s3api put-bucket-cors --bucket YOUR_BUCKET --cors-configuration '{
"CORSRules": [
{
"AllowedOrigins": ["https://studio.relyn.app", "http://localhost:5173"],
"AllowedMethods": ["GET", "PUT", "HEAD", "POST", "DELETE"],
"AllowedHeaders": ["*"],
"ExposeHeaders": ["ETag"],
"MaxAgeSeconds": 3600
}
]
}'

The CLI shape wraps the same rules in a CORSRules array — content is identical.

  • Block Public Access doesn’t affect CORS. You can keep “Block all public access” enabled — the CORS preflight is unauthenticated by spec but reading objects still requires presigned URLs.
  • If your bucket lives behind CloudFront with custom origin headers, CORS headers need to be passed through. That’s a CloudFront behaviour config separate from this.