Skip to main content

Public Access and Custom Domains

To serve R2 assets to end-users (like images on a website), you must route traffic through Cloudflare's CDN using Custom Domains.

The Request Flow​

Understanding the architecture is crucial for debugging and performance tuning.

Connecting a Custom Domain​

Using the dashboard is simple, but Infrastructure as Code is better.

Via Dashboard: R2 -> Settings -> Public Access -> Connect Domain. Via Wrangler CLI:

wrangler r2 bucket domain add production-assets --domain assets.example.com

Securing the Public Domain (WAF Rules)​

Once connected, assets.example.com is public. To prevent hotlinking or malicious scraping, you must implement Web Application Firewall (WAF) rules in the Cloudflare Dashboard under Security -> WAF.

Example 1: Prevent Hotlinking​

Block requests where the Referer header doesn't match your domain.

  • Expression: (http.host eq "assets.example.com" and not http.referer contains "yourwebsite.com")
  • Action: Block

Example 2: API Token Requirement​

If your frontend app dynamically fetches assets, require a custom header.

  • Expression: (http.host eq "assets.example.com" and http.request.headers["x-asset-token"] ne "super-secret-key")
  • Action: Block

Cache Invalidation (Purging)​

When you overwrite an object in R2 (e.g., updating logo.png), the Edge Cache does not automatically clear. Users will still see the old logo until the Cache-Control max-age expires.

You must manually purge the cache via the Dashboard or API.

Purging via API (cURL)​

curl -X POST "https://api.cloudflare.com/client/v4/zones/<ZONE_ID>/purge_cache" \
-H "Authorization: Bearer <CLOUDFLARE_API_TOKEN>" \
-H "Content-Type: application/json" \
--data '{"files":["https://assets.example.com/logo.png"]}'

Best Practice: Append content hashes to filenames (e.g., logo.v123.png) in your build process to avoid caching issues entirely, rather than relying on manual purges.