Skip to main content

Cloudflare R2 CORS Configuration

Hyperscape serves game assets (3D models, textures, audio) from Cloudflare R2 at assets.hyperscape.club. Cross-origin asset loading requires proper CORS configuration.

Problem

Without CORS configuration, browsers block asset loading from R2 with errors like:

Solution

Configure R2 bucket CORS to allow cross-origin requests from all Hyperscape domains.

Automatic Configuration (CI/CD)

The .github/workflows/deploy-cloudflare.yml workflow automatically configures CORS during deployment:

Manual Configuration

If you need to configure CORS manually:

Using Wrangler CLI

CORS Configuration File

The scripts/r2-cors-config.json file contains:
Configuration Details:

Using Cloudflare Dashboard

  1. Log in to Cloudflare Dashboard
  2. Navigate to R2hyperscape-assets bucket
  3. Go to SettingsCORS Policy
  4. Add CORS rule:
    • Allowed Origins: *
    • Allowed Methods: GET, HEAD
    • Allowed Headers: *
    • Exposed Headers: ETag, Content-Length, Content-Type
    • Max Age: 3600
  5. Click Save

Verification

Test CORS configuration:
Or test in browser console:

Allowed Domains

The CORS configuration allows requests from:
  • hyperscape.gg (production frontend)
  • *.hyperscape.gg (subdomains)
  • hyperbet.win (betting frontend)
  • *.hyperbet.win (subdomains)
  • hyperscape.bet (alternative domain)
  • *.hyperscape.bet (subdomains)
  • localhost:* (local development)
  • Any other origin (wildcard *)

Security Considerations

Why Wildcard Origin?

R2 assets are public read-only resources (3D models, textures, audio). There’s no security risk in allowing cross-origin access from any domain because:
  1. No authentication required - Assets are publicly accessible
  2. Read-only access - Only GET/HEAD methods allowed (no PUT/POST/DELETE)
  3. No sensitive data - Assets are game content, not user data

Alternative: Restricted Origins

If you want to restrict origins to specific domains:
Trade-offs:
  • ✅ More restrictive (only listed domains can load assets)
  • ❌ Requires updating config when adding new domains
  • ❌ Breaks local development on non-standard ports

Troubleshooting

CORS Errors Persist After Configuration

Cause: Browser cached old CORS preflight responses Solution: Hard refresh (Ctrl+Shift+R) or clear browser cache

Wrangler CORS Command Fails

Symptoms: wrangler r2 bucket cors set returns error Common Issues:
  1. Invalid JSON format:
  2. Missing authentication:
  3. Bucket doesn’t exist:

Assets Still Not Loading

Symptoms: 404 errors or CORS errors persist Checklist:
  1. Verify CORS is configured:
  2. Check asset exists in R2:
  3. Verify CDN URL is correct:
    • Client .env: PUBLIC_CDN_URL=https://assets.hyperscape.club
    • Server .env: PUBLIC_CDN_URL=https://assets.hyperscape.club
  4. Check R2 custom domain:
    • R2 bucket → Settings → Custom Domains
    • Verify assets.hyperscape.club is connected

Implementation Details

CORS Configuration Script

The scripts/configure-r2-cors.sh script:
  1. Reads CORS config from scripts/r2-cors-config.json
  2. Uses Wrangler CLI to apply configuration
  3. Verifies configuration was applied successfully
Script Location: scripts/configure-r2-cors.sh CORS Config: scripts/r2-cors-config.json

Wrangler API Format

The correct Wrangler R2 CORS API format (as of February 2026):
Previous format (deprecated):
The new format uses:
  • Nested allowed.origins/methods/headers structure
  • exposed array (not ExposeHeaders)
  • maxAge integer (not MaxAgeSeconds)
Fix Commit: 055779a (February 26, 2026)