sojorn/sojorn_docs/deployment/R2_CUSTOM_DOMAIN_SETUP.md

6.9 KiB

R2 Custom Domain Setup Guide

This guide walks through setting up a production-ready custom domain for the Sojorn R2 bucket.

Why Custom Domain?

The R2 public development URL (https://pub-*.r2.dev) has significant limitations:

  • ⚠️ Rate limited - not suitable for production traffic
  • ⚠️ No Cloudflare features (Access, Caching, Analytics)
  • ⚠️ No custom SSL certificates
  • ⚠️ Not recommended by Cloudflare for production

A custom domain provides:

  • Unlimited bandwidth and requests
  • Full Cloudflare features (caching, CDN, DDoS protection)
  • Custom SSL certificates
  • Professional appearance
  • Better SEO and branding

If your main domain is sojorn.com, use a subdomain for media:

  • media.sojorn.com - Professional, clear purpose
  • cdn.sojorn.com - Common CDN pattern
  • images.sojorn.com - Descriptive alternative

Recommended: media.sojorn.com

Setup Steps

Step 1: Connect Domain to R2 Bucket

  1. Go to Cloudflare DashboardR2sojorn-media bucket
  2. Click "Settings" tab
  3. Under "Public Access", click "Connect Domain"
  4. Enter your chosen subdomain: media.sojorn.com
  5. Click "Connect Domain"

Cloudflare will automatically:

  • Create a DNS CNAME record pointing to R2
  • Provision an SSL certificate
  • Enable CDN caching

Step 2: Verify Domain Configuration

Wait 1-2 minutes for DNS propagation, then test:

# Check DNS record
nslookup media.sojorn.com

# Test direct access (upload a test file first)
curl -I https://media.sojorn.com/test-image.jpg
# Should return: HTTP/2 200

Step 3: Configure Environment Variable

Set the public URL in Supabase secrets:

# Set the R2 public URL secret
npx supabase secrets set R2_PUBLIC_URL=https://media.sojorn.com --project-ref zwkihedetedlatyvplyz

# Verify all R2 secrets are set
npx supabase secrets list --project-ref zwkihedetedlatyvplyz

Expected secrets:

  • R2_ACCOUNT_ID - Your Cloudflare account ID
  • R2_ACCESS_KEY - R2 API token access key
  • R2_SECRET_KEY - R2 API token secret key
  • R2_PUBLIC_URL - Your custom domain URL (e.g., https://media.sojorn.com)

Step 4: Deploy Updated Edge Function

The edge function now uses the R2_PUBLIC_URL environment variable:

# Deploy the updated edge function
npx supabase functions deploy upload-image --project-ref zwkihedetedlatyvplyz

# Verify deployment
npx supabase functions list --project-ref zwkihedetedlatyvplyz

Step 5: Test End-to-End

  1. Upload a test image through the app
  2. Check the database for the generated URL:
    SELECT id, image_url, created_at
    FROM posts
    WHERE image_url IS NOT NULL
    ORDER BY created_at DESC
    LIMIT 1;
    
  3. Verify URL format: Should be https://media.sojorn.com/{uuid}.{ext}
  4. Test in browser: Open the URL directly - image should load
  5. Check in app: Image should display in the feed

Troubleshooting

Domain Not Connecting

Error: "Failed to connect domain" Solution:

  • Verify domain is managed by Cloudflare (same account)
  • Check domain isn't already connected to another R2 bucket
  • Ensure subdomain doesn't have conflicting DNS records

SSL Certificate Issues

Error: "SSL handshake failed" or "NET::ERR_CERT_COMMON_NAME_INVALID" Solution:

  • Wait 5-10 minutes for SSL certificate provisioning
  • Verify domain shows "Active" status in R2 bucket settings
  • Check Cloudflare SSL/TLS mode is set to "Full" or "Full (strict)"

Images Return 404

Error: Images uploaded but return 404 on custom domain Solution:

  • Verify domain connection is "Active" in R2 settings
  • Check file actually exists: curl -I https://{ACCOUNT_ID}.r2.cloudflarestorage.com/sojorn-media/{filename}
  • Verify bucket name matches in edge function (should be sojorn-media)

Old Dev URLs Still Used

Problem: New uploads use dev URL instead of custom domain Solution:

  • Verify R2_PUBLIC_URL secret is set: npx supabase secrets list
  • Redeploy edge function: npx supabase functions deploy upload-image
  • Check edge function logs for errors: npx supabase functions logs upload-image

Cloudflare Caching Configuration

After connecting the domain, optimize caching in Cloudflare Dashboard:

  1. Go to your domain in Cloudflare Dashboard
  2. Navigate to Rules → Page Rules
  3. Create a rule for media.sojorn.com/*:
    • Cache Level: Standard
    • Edge Cache TTL: 1 month
    • Browser Cache TTL: 1 hour

This ensures images are cached at Cloudflare's edge for fast global delivery.

Security Considerations

CORS Configuration

The R2 bucket CORS is already configured for all origins (*):

{
  "Allowed Origins": "*",
  "Allowed Methods": ["GET", "HEAD", "PUT"],
  "Allowed Headers": "*"
}

For production, consider restricting origins:

{
  "Allowed Origins": ["https://sojorn.com", "https://app.sojorn.com"],
  "Allowed Methods": ["GET", "HEAD"],
  "Allowed Headers": ["*"]
}

Access Control

Images are publicly readable by design. To restrict access:

  1. Use signed URLs (requires code changes)
  2. Implement Cloudflare Access rules
  3. Add authentication checks before generating upload URLs

Cost Considerations

R2 Pricing (as of 2026)

  • Storage: $0.015/GB per month
  • Class A Operations (writes): $4.50 per million requests
  • Class B Operations (reads): $0.36 per million requests
  • Data Transfer: FREE (no egress fees)

Custom Domain Benefits

  • Cloudflare CDN: Free caching reduces R2 read operations
  • No Egress Fees: Unlike AWS S3, R2 doesn't charge for bandwidth
  • Edge Caching: Reduces origin requests by 95%+

Monitoring

Track R2 usage in Cloudflare Dashboard:

  1. Go to R2 → sojorn-media bucket
  2. Check Metrics tab for:
    • Storage size
    • Request count
    • Bandwidth usage

Set up alerts for:

  • Storage exceeding threshold (e.g., 10GB)
  • Unusual request spikes
  • Error rate increases

Quick Reference

Required Supabase Secrets

R2_ACCOUNT_ID=<your-cloudflare-account-id>
R2_ACCESS_KEY=<your-r2-access-key>
R2_SECRET_KEY=<your-r2-secret-key>
R2_PUBLIC_URL=https://media.sojorn.com

Deploy Commands

# Set secret
npx supabase secrets set R2_PUBLIC_URL=https://media.sojorn.com --project-ref zwkihedetedlatyvplyz

# Deploy function
npx supabase functions deploy upload-image --project-ref zwkihedetedlatyvplyz

# View logs
npx supabase functions logs upload-image --project-ref zwkihedetedlatyvplyz

Test Commands

# Check DNS
nslookup media.sojorn.com

# Test HTTPS
curl -I https://media.sojorn.com/

# Upload test file
curl -X PUT "https://<account-id>.r2.cloudflarestorage.com/sojorn-media/test.txt" \
  -H "Authorization: Bearer <token>" \
  --data "test content"

# Verify via custom domain
curl -I https://media.sojorn.com/test.txt

Next Steps: After completing this setup, proceed to the main IMAGE_UPLOAD_IMPLEMENTATION.md guide for testing the full upload flow.