← Back to all posts

Choosing Between AWS S3 vs Cloudflare R2, and Why I Ditched Self-Hosted Email for Kit.com

Today's build log: 8 hours deep in decision paralysis. Should I use AWS S3 or Cloudflare R2? Host on VPS or Cloudflare Pages? Self-host email or use Kit.com? Spoiler: I chose the free options.

Today was supposed to be simple: upload some images to my blog and add a newsletter signup. Instead, I spent 8 hours down rabbit holes comparing object storage pricing, CDN configurations, and email marketing platforms. Welcome to my brain.

But hey, at least I made some decisions. Let's talk about what I learned.

The Image Storage Crisis

Here's the thing about static blogs: images are a problem.

I'm building this site with Next.js as a static site generator. Everything is markdown files, deployed to Cloudflare Pages. Clean, simple, fast. But where do I put the images?

My first instinct was "just commit them to the Git repo." Bad idea. Really bad idea.

After asking Perplexity and Claude about this, here's what I learned:

  • GitHub repos have a 1GB soft limit
  • Git isn't designed for binary files
  • Every image update bloats your repo history forever
  • Your build times become miserable

So I needed external object storage. Which led me down the AWS S3 vs Cloudflare R2 rabbit hole.

AWS S3 vs Cloudflare R2: The Hotlink Attack Scenario

I'm paranoid about bandwidth attacks. Someone hotlinks your images on Reddit, goes viral, and suddenly you owe AWS $900 for egress fees. It happens.

So I did what any reasonable person would do: I asked Claude and Perplexity to compare costs for a 10TB hotlink attack scenario.

AWS S3 + Cloudflare CDN:

  • Best case (95% CDN cache hit): ~$70/month
  • Worst case (cache purge attack): $900+
  • Still charges egress fees even to Cloudflare

Cloudflare R2 + Cloudflare CDN:

  • Normal operations: ~$0.15/month (just storage)
  • Under 10TB attack: ~$32 (just request fees)
  • Zero egress fees. Ever.

Yeah, R2 wins. It's not even close.

The math is simple: R2 has zero egress fees by design. AWS charges $0.09/GB to send data anywhere, even to Cloudflare's CDN. With R2, you only pay for storage ($15/TB/month) and API requests ($0.36 per million reads). Bandwidth is completely free.

Even if someone launches a massive hotlink attack and generates 10TB of traffic, I'd pay around $32 in request fees. With S3, that same attack would cost $900+ in egress alone.

Decision made: Cloudflare R2 it is.

Setting Up R2 (Or: Why I Didn't Actually Configure Anything)

Once I committed to R2, I went deep into research mode. Spent hours chatting with Claude and Perplexity about WAF rules, rate limiting, cache policies, signed URLs, API token management, and all that security theater.

Then I realized something: I'm on Cloudflare's free plan.

Most of those advanced security features? Not available on the free tier. WAF custom rules? Nope. Advanced rate limiting? Nope. Bot Management? Nope.

And honestly? I didn't care. Here's what I actually did:

What I actually set up:

  • Added a custom domain to my R2 bucket
  • That's it

What Cloudflare automatically handled for me:

  • SSL certificate (auto-provisioned via Let's Encrypt)
  • CDN caching (default aggressive caching for static assets)
  • Basic DDoS protection (included on free plan)
  • Edge network delivery (300+ locations worldwide)

Claude and Perplexity kept suggesting I implement signed URLs for "maximum security." The idea is you generate time-limited URLs that expire after an hour or whatever, so even if someone hotlinks your images, the URLs stop working.

Sounds cool. Also sounds complicated and time-consuming.

I made a pragmatic decision: R2 + Cloudflare CDN is probably enough.

Here's my reasoning:

  1. R2 has zero egress fees, so even if someone hotlinks my images, I'm not paying for bandwidth
  2. Cloudflare's CDN will cache everything anyway, so R2 barely gets hit
  3. I'm running a personal blog, not hosting classified documents
  4. The worst case scenario is... someone uses my CDN for free? And I pay a few cents in request fees?

I can always add signed URLs later if I actually need them. For now, I'm shipping with the basics.

One thing that did confuse me: after uploading 2-3 test images, my R2 dashboard showed 106 Class A operations and 313 Class B operations. I thought I was being attacked.

Cloudflare R2 dashboard showing 106 Class A and 313 Class B operations for only 368KB of storage

Nope. Turns out that's completely normal. It's Cloudflare's CDN warming caches across edge locations, DNS verification, SSL provisioning, and health checks. After 24-48 hours, those numbers drop to near zero because everything stays cached.

Good enough for day one.

Hosting: VPS vs Cloudflare Pages

I also briefly considered moving from Cloudflare Pages to a VPS server. The idea was more control, more flexibility, maybe faster builds.

Then I remembered why I chose Cloudflare Pages in the first place:

  • Free (as in $0/month)
  • Fast (deployed on Cloudflare's edge network)
  • Simple (git push = auto deploy)
  • No server maintenance

With a VPS, I'd be managing Nginx configs, SSL certificates, server updates, backups... for what benefit? Slightly more control?

No thanks. I like writing blog posts in markdown files and pushing to GitHub. Cloudflare Pages handles the rest.

Decision made: Staying on Cloudflare Pages.

The Email Marketing Pivot: Mautic to Kit.com

Yesterday I spent 6 hours setting up Mautic, a self-hosted email marketing platform. It was painful but it worked.

Today I discovered Kit.com (formerly ConvertKit) has a free plan with 10,000 subscribers and unlimited sending.

Wait, what?

I spent all day yesterday fighting through Mautic installation errors, PHP version conflicts, memory limit issues, and Nginx configurations... and there's a free SaaS option that does everything I need?

Here's the thing: my use case isn't complicated.

I don't have email sequences. I'm not building complex automation workflows. I don't need A/B testing or advanced segmentation or lead scoring.

I just need to send broadcast emails to people who want to read my blog posts. That's it.

Let's compare:

Self-hosted Mautic:

  • Cost: $5/month VPS + $19.95/month SendGrid = $25/month
  • Setup time: 6 hours of debugging
  • Maintenance: Manual updates, backups, security patches
  • Features: Everything (automation, sequences, landing pages, etc.)
  • Reality: Using 5% of the features

Kit.com Free Plan:

  • Cost: $0/month (up to 10,000 subscribers)
  • Setup time: 10 minutes
  • Maintenance: Zero
  • Features: Broadcast emails, basic forms, tagging
  • Reality: Exactly what I need right now

For a blog that currently has zero subscribers, spending $25/month and 6 hours of setup time on features I'm not using was absurd.

I pivoted immediately.

Implementing Kit.com Newsletter

Setting up Kit.com was embarrassingly easy compared to yesterday's Mautic nightmare.

What I actually did:

  1. Created a Kit.com account (free)
  2. Created a form in the dashboard
  3. Got the form embed code

Kit.com dashboard showing simple form builder interface for newsletter signup

  1. Asked Claude Code to implement it for me
  2. Claude built the React component, added it to all the pages, created the modal, fixed CSP issues
  3. Done

Yeah, I didn't write any of the implementation code myself. I just told Claude Code "add Kit.com newsletter forms to my blog" and it handled everything.

I went with the embed form approach because it's fast and easy. Kit.com gives you a script tag, you drop it in, it works. No complicated API integration needed for basic newsletter signups.

Sure, I could use the Kit.com API directly for more control.

But why? The embed form does everything I need right now. When I need more advanced features like custom workflows, programmatic tagging, or subscriber management, I'll implement the API. Not today.

What I Actually Learned Today

After 8 hours of research and implementation, here's what stuck:

1. Cloudflare R2 eliminates egress anxiety

  • Zero bandwidth costs regardless of traffic
  • ~4x cheaper than AWS S3 for CDN use cases
  • Perfect for static assets (images, videos, etc.)

2. Don't self-host what you don't need to

  • Mautic was cool but overkill for a blog with zero subscribers
  • Kit.com's free tier is more than enough for now
  • I can always migrate later if I outgrow it

3. Free tiers are incredible in 2025

  • Cloudflare Pages: Free hosting + CDN
  • Cloudflare R2: 10GB storage + 10M requests/month free
  • Kit.com: 10,000 subscribers + unlimited emails free
  • Total cost: $0/month

4. "Good enough" beats perfect

  • Didn't implement signed URLs or custom WAF rules
  • Cloudflare's free tier handles the basics automatically
  • Ship now, optimize later if needed

5. Decision paralysis is real

  • Spent 6 hours comparing S3 vs R2
  • The answer was obvious after 30 minutes
  • Just pick something and ship

The Wins

Despite the analysis paralysis, I'm happy with where I landed:

  • Image storage: Cloudflare R2 + CDN (attack-proof, $0/month)
  • Hosting: Cloudflare Pages (fast, simple, $0/month)
  • Email marketing: Kit.com (free up to 10k subscribers)
  • Total monthly cost: $0

Tomorrow I'm writing actual blog content instead of obsessing over infrastructure.

Maybe.


Today's Stack: Next.js, Cloudflare Pages, Cloudflare R2, Kit.com

Hosting: Cloudflare everything (R2 + Pages + CDN)

Cost: $0/month (living the free tier dream)

Time spent researching: 6 hours

Time spent implementing: 2 hours

Decisions made: 3 (Cloudflare R2 over AWS S3, Cloudflare Pages over VPS, Kit.com over Mautic)

Lessons learned: Yesterday's 6 hours on Mautic wasn't wasted - now I know how self-hosted email works, even if I'm not using it

Thanks for reading! Follow my journey as I build in public.

Follow @narongritsy on X

Other Posts