ezS3.net
Back to blog
Configuring Cloudflare R2 with ezS3

Configuring Cloudflare R2 with ezS3

Cloudflare R2 is S3-compatible object storage with simple pricing. Create an R2 token, connect it to ezS3, and use auto CORS so browser uploads work.

5 min read

Cloudflare R2 is an S3-compatible object storage service designed to keep pricing straightforward (notably, R2 does not charge for egress). Because it speaks the S3 API, you can connect it to ezS3 the same way you would connect AWS S3 — using an access key, secret key, endpoint, and bucket name.

Why Cloudflare R2?

  • S3-compatible API: Works with standard S3 tooling and SDKs
  • Predictable costs: No egress fees (and generally simpler pricing than S3)
  • Great for web apps: Plays nicely with presigned URLs and browser uploads (with CORS configured)

Prerequisites

Before you begin, make sure you have:

  • A Cloudflare account with R2 enabled
  • An R2 bucket (or create one in Step 1)
  • A place to store your Secret Access Key (you can only view it once)

Step 1: Create an R2 bucket

  1. Log in to the Cloudflare dashboard
  2. Go to R2 (R2 Object Storage)
  3. Click Create bucket
  4. Pick a bucket name (lowercase, no spaces is safest)

Step 2: Create an R2 S3 API token (Access Key + Secret Key)

Cloudflare R2 uses R2 API tokens as S3 credentials.

  1. In the Cloudflare dashboard, go to R2Manage R2 API tokens

  2. Create a token (either Account API token or User API token)

  3. Under Permissions, pick the smallest permission that works for you:

    • Admin Read & Write: bucket management + full object access (only use if you truly need it)
    • Admin Read only: list buckets, view bucket configuration, and read/list objects (useful if you need visibility across buckets)
    • Object Read & Write (recommended): read, write, and list objects (and you can scope it to specific buckets)
    • Object Read only: read and list objects (and you can scope it to specific buckets)

    If you choose an Object permission, you will not be able to list buckets via the API. In that case, ezS3 won’t be able to discover buckets for you — you’ll need to type the bucket names manually in ezS3’s provider connection form.

  4. If you chose Object Read & Write or Object Read only, scope it to your bucket(s)

  5. Leave Client IP Address Filtering empty (unless you have a known static outbound IP you want to restrict to). Setting this incorrectly can prevent ezS3 from using the token.

  6. Create the token and copy both values:

    • Access Key ID
    • Secret Access Key (you will not be able to view this again)

Step 3: Find your R2 S3 endpoint (and region)

R2’s S3 endpoint is based on your Cloudflare Account ID:

  • Endpoint: https://<<ACCOUNT_ID>>.r2.cloudflarestorage.com

For most S3 clients, the bucket region is:

  • Region: auto

If a tool won’t accept auto, Cloudflare notes that a blank region (or us-east-1) will usually alias to auto for compatibility.

If you created a jurisdictional bucket, you must use the matching endpoint:

  • EU buckets: https://<<ACCOUNT_ID>>.eu.r2.cloudflarestorage.com
  • FedRAMP buckets: https://<<ACCOUNT_ID>>.fedramp.r2.cloudflarestorage.com

Step 4: Connect Cloudflare R2 to ezS3

  1. In ezS3, go to Storage Providers
  2. Click Add ProviderCloudflare R2
  3. Fill in:
    • Endpoint: https://<<ACCOUNT_ID>>.r2.cloudflarestorage.com (or jurisdiction endpoint)
    • Region: auto (or us-east-1 if needed)
    • Bucket scopes (optional): Leave blank to list all buckets the token can access, or enter a comma-separated list of bucket names
    • Access Key ID / Secret Access Key: from Step 2
  4. Leave Allow ezS3 to update bucket CORS settings (recommended) on. When you save or test the connection, ezS3 can add the ezs3.net origin to your R2 bucket’s CORS policy so browser uploads work. You usually don’t need to configure CORS manually.

Once saved, ezS3 should be able to list objects immediately (assuming your token is scoped correctly).

Optional: Configure CORS manually

If you turn off CORS auto-update or prefer to manage CORS yourself, you can set it in the Cloudflare dashboard or with Wrangler.

In the Cloudflare dashboard:

  1. In the Cloudflare dashboard, open R2 and select your bucket
  2. Go to Settings
  3. Under CORS Policy, click Add CORS policy
  4. In the JSON tab, paste a policy like this (adjust origins as needed):
[
  {
    "AllowedOrigins": ["https://ezs3.net"],
    "AllowedMethods": ["GET", "PUT", "HEAD", "DELETE"],
    "AllowedHeaders": ["*"],
    "ExposeHeaders": ["ETag"],
    "MaxAgeSeconds": 3600
  }
]

Origins must match exactly (no path, no trailing slash). In rare cases, CORS changes can take up to ~30 seconds to propagate.

Or with npx wrangler:

  1. Install / run Wrangler and log in:
npx wrangler login
  1. Create a cors.json file (example below).
{
  "rules": [
    {
      "allowed": {
        "origins": ["https://ezs3.net"],
        "methods": ["GET", "PUT", "HEAD", "DELETE"]
      }
    }
  ]
}
  1. Apply the CORS policy to your bucket:
npx wrangler r2 bucket cors set <<BUCKET_NAME>> --file cors.json
  1. Verify what’s currently set:
npx wrangler r2 bucket cors list <<BUCKET_NAME>>

Troubleshooting

Access denied / signature errors

  • Confirm you’re using the correct endpoint for your bucket’s jurisdiction (default vs EU vs FedRAMP)
  • Confirm the token has Object Read & Write (or at least the permissions you need)
  • If the token is bucket-scoped, ensure your bucket is included

Browser says “CORS policy blocked”

  • Make sure AllowedOrigins includes the exact origin the browser is running on
  • If you’re testing locally, add http://localhost:<port> as an additional allowed origin
  • Make sure AllowedHeaders includes any headers your request is sending (using ["*"] is easiest to start)

Ready to try it? Sign up for ezS3 and connect your Cloudflare R2 bucket.

Read next