How to Serve Media Files via a Custom Subdomain Using Backblaze B2 and Cloudflare
If you store media files in an object storage service like Backblaze B2, the last thing you want is exposing a raw storage URL like f003.backblazeb2.com/file/your-bucket/image.jpg to your users. It looks unprofessional, leaks your storage provider, and gives you zero control over caching or routing.
In this guide you'll learn how to serve your files through a clean branded subdomain — something like media.yourdomain.com — using Backblaze B2 as the storage backend and Cloudflare to handle DNS, CDN caching, and URL rewriting.
The best part: Backblaze and Cloudflare are bandwidth alliance partners, which means traffic between them is free. You only pay for storage, not egress.
What You Need
- A Backblaze B2 account
- A domain name (registered anywhere)
- A Cloudflare account (free tier is enough)
If your domain is not registered on Cloudflare, don't worry — there are two ways to handle that, covered at the end of this guide.
Step 1: Create a Public Bucket on Backblaze B2
Log into Backblaze B2 and create a new bucket.
- Set the bucket to Public
- Note your bucket name — you'll need it for the rewrite rule
- Note your endpoint URL — it looks like
f003.backblazeb2.com
The
f003part varies by account. Check your bucket details to confirm yours.
Once your bucket is created, upload a test file so you can verify the setup end to end.
Step 2: Add a CNAME Record in Cloudflare
In your Cloudflare dashboard, go to DNS → Records → Add record.
| Field | Value |
|---|---|
| Type | CNAME |
| Name | media |
| Target | f003.backblazeb2.com |
| Proxy | Enabled (orange cloud on) |
| TTL | Auto |
Click Save.
This creates media.yourdomain.com as a proxied alias to your Backblaze endpoint. Cloudflare sits in between — handling caching, HTTPS, and routing.
Step 3: Add a URL Rewrite Rule (Critical)
This step is the one most guides skip — and it's the most important one.
Without a rewrite rule, your subdomain points to the root of the Backblaze endpoint, not your specific bucket. That means anyone could theoretically use your domain to serve files from any Backblaze bucket. The rewrite rule locks requests to your bucket's path.
In Cloudflare, go to Rules → Transform Rules → URL Rewrite → Create rule.
Configure it as follows:
When incoming requests match:
Hostname equals media.yourdomain.com
Then rewrite the path — Rewrite to (Dynamic):
concat("/file/your-bucket-name", http.request.uri.path)
Replace your-bucket-name with the actual name of your Backblaze bucket.
What this does: A request to media.yourdomain.com/product/iphone-14.jpg gets rewritten internally to /file/your-bucket-name/product/iphone-14.jpg before Backblaze receives it. Your users never see the bucket path.
Step 4: Verify It Works
Once DNS propagates (usually within a few minutes on Cloudflare), test by visiting:
https://media.yourdomain.com/your-test-file.jpg
You can also verify DNS resolution from the command line:
nslookup media.yourdomain.com 1.1.1.1
If it returns an IP address, the record is live. If you get Non-existent domain, the record hasn't saved correctly — go back and check Step 2.
Step 5: Configure Your Backend to Use the Custom Domain
Your backend is probably still generating URLs pointing to the raw Backblaze endpoint. Update it to use your new subdomain.
Django (settings.py):
# Before
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
AWS_S3_ENDPOINT_URL = 'https://s3.us-west-004.backblazeb2.com'
AWS_S3_CUSTOM_DOMAIN = 'f003.backblazeb2.com'
# After
AWS_S3_CUSTOM_DOMAIN = 'media.yourdomain.com'
MEDIA_URL = 'https://media.yourdomain.com/'
Next.js (next.config.js) — allow the domain for image optimization:
module.exports = {
images: {
domains: ['media.yourdomain.com'],
},
}
Environment variable approach:
MEDIA_BASE_URL=https://media.yourdomain.com
Then reference it anywhere you build file URLs:
# Python example
image_url = f"{settings.MEDIA_URL}{instance.image.name}"
From this point, every media file your app references will be served through Cloudflare — with CDN caching on top at no extra bandwidth cost.
What If Your Domain Is Not on Cloudflare?
You have two options depending on what your domain provider supports.
Option A: Add the CNAME at Your Domain Provider (No Migration)
If your domain provider supports CNAME records and URL rewrite rules, you can add the CNAME there directly without touching Cloudflare:
Type: CNAME
Name: media
Value: f003.backblazeb2.com
The limitation here is that most shared hosting providers (cPanel, Asura, etc.) don't offer Cloudflare-style URL rewrite rules. Without the rewrite rule from Step 3, your subdomain will point to the Backblaze root, not your specific bucket — which is a security and routing issue.
If your provider supports it, great. If not, use Option B.
Option B: Migrate Your DNS to Cloudflare (Recommended)
This is easier than it sounds. You're not moving your hosting — just changing where DNS is managed.
- Create a free Cloudflare account and add your domain
- Cloudflare will scan and import your existing DNS records automatically
- Verify all records imported correctly (A records, MX for email, existing CNAMEs)
- Go to your domain registrar and update the nameservers to the ones Cloudflare provides:
e.g.
aria.ns.cloudflare.com
bob.ns.cloudflare.com
- Wait for propagation — typically 30 minutes to 24 hours
- Once propagated, follow Steps 2 and 3 above in your Cloudflare dashboard
Your hosting, VPS, SSL certs, and everything else stays exactly where it is. Only DNS management moves to Cloudflare.
Summary
| Step | What You Do |
|---|---|
| 1 | Create a public Backblaze B2 bucket |
| 2 | Add a proxied CNAME in Cloudflare DNS |
| 3 | Add a URL rewrite rule scoped to your bucket path |
| 4 | Verify DNS resolution and file serving |
| 5 | Update your backend to use the custom domain |
You now have a clean branded media URL, free bandwidth between Cloudflare and Backblaze, CDN edge caching globally, and full control over how your files are served — without exposing your storage provider or paying egress fees.