Cloudflare R2 — Next Steps & External Setup
Everything you need to do outside the codebase to enable Cloudflare R2 file storage.
1. Rails Credentials
Run bin/rails credentials:edit and add:
cloudflare:
r2_account_id: "your-cloudflare-account-id"
r2_access_key_id: "your-r2-access-key-id"
r2_secret_access_key: "your-r2-secret-access-key"
r2_bucket: "your-bucket-name"
2. Create an R2 Bucket
- Go to Cloudflare Dashboard
- Select your account
- Go to R2 Object Storage in the sidebar
- Click Create bucket
- Name: Choose a name (e.g.,
yourapp-production) - Location: Choose a location hint (auto is fine)
3. Enable Public Access (Custom Domain)
- In your bucket settings, go to Settings → Public access
- Under Custom Domains, click Connect Domain
- Enter a subdomain:
cdn.yourdomain.com(orassets.yourdomain.com) - Cloudflare will automatically create a DNS record
- Wait for the SSL certificate to be issued
Why custom domain? The
storage.ymlis configured withpublic: true, which means ActiveStorage will generate direct public URLs to your R2 bucket. A custom domain gives you clean URLs likehttps://cdn.yourdomain.com/...instead of the raw R2 URLs.
4. Create API Tokens
- Go to R2 Object Storage → Manage R2 API Tokens
- Click Create API Token
- Token name:
yourapp-production - Permissions: Object Read & Write
- Specify bucket: Select your bucket (or "Apply to all buckets")
- Click Create API Token
- Copy:
- Access Key ID →
r2_access_key_id - Secret Access Key →
r2_secret_access_key
- Access Key ID →
5. Get Account ID
- In the Cloudflare Dashboard sidebar, your Account ID is shown under the account name
- Or go to any zone → Overview → right sidebar shows Account ID
- Copy this to
r2_account_id
6. CORS Configuration (if needed)
If you get CORS errors when loading images directly from R2:
- Go to your bucket → Settings → CORS Policy
- Add a rule:
[ { "AllowedOrigins": ["https://yourdomain.com"], "AllowedMethods": ["GET", "HEAD"], "AllowedHeaders": ["*"], "MaxAgeSeconds": 86400 } ]
7. Deployment Checklist
- R2 bucket created (for file uploads)
- Custom domain connected (for public URLs)
- API token created with Read & Write permissions
- All 4 Cloudflare credentials added (
r2_account_id,r2_access_key_id,r2_secret_access_key,r2_bucket) - CORS configured if needed
- Upload an image (e.g., project logo) — verify it's stored in R2 and publicly accessible
- Images load from
cdn.yourdomain.comin browser - Image variants (thumbnails) generate correctly