Day 5: Choosing our hosting - how we'll run this for under $20/month

Day 5 of 30. Today we're talking money - specifically, how to spend as little of it as possible.

#infrastructure #costs #cloudflare-r2 #hetzner

Day 5 of 30. Today we’re talking money - specifically, how to spend as little of it as possible.

Hosting costs can have a significant impact on a bootstrapped project. We’ve seen projects spend $1000+/month on infrastructure for apps with zero users, especially when running on bigger cloud providers like AWS or Azure. We’re optimizing for affordable until our needs justifies otherwise.

Our target is to spend less than $20 USD/month for our hosting costs and CI/CD infrastructure. Here’s how we’re getting there.

The options we considered

tech-compare - Hosting provider comparison
[✓] Hetzner CHOSEN

[+] Pros

  • + CX22: 2 vCPUs, 4GB RAM, 40GB SSD for $4.50/month
  • + Same specs on DigitalOcean would cost $24/month
  • + Data centers in EU and US
  • + Reliable - been around since 1997
  • + No surprise pricing

[-] Cons

  • - Less known in the US market
  • - Fewer managed services
  • - DIY approach required
Verdict

Exceptional value. We'll benchmark to confirm performance matches the price.

[ ] Vercel / Netlify / Railway

[+] Pros

  • + Great Developer Experience
  • + Generous free tiers
  • + Painless deployment

[-] Cons

  • - Free tiers have limits that could get expensive fast
  • - Serverless doesn't play well with headless browsers
  • - Would need separate compute for Playwright workers
  • - Costs become unpredictable at scale
Verdict

Great for static sites or simple APIs. Not right for a screenshot service.

[ ] AWS / GCP / Azure

[+] Pros

  • + Almost infinitely scalable
  • + Every service imaginable

[-] Cons

  • - Overkill for our scale
  • - Pricing is confusing and easy to mess up
  • - Free tiers expire or have gotchas
  • - We'd spend more time on infrastructure than product
Verdict

We can migrate to cloud providers later when running on Docker.

[ ] DigitalOcean / Linode / Vultr

[+] Pros

  • + Solid middle ground
  • + Simple, predictable pricing
  • + Good documentation
  • + Good reputation in indie hacker community

[-] Cons

  • - More expensive than Hetzner for same specs
  • - $24/month for equivalent to Hetzner CX22
Verdict

Our usual goto. But we found something cheaper to try.

Why Cloudflare R2 for storage?

Screenshots need to live somewhere, and an S3 compatible storage is the standard. There is cost for storage, and cost for serving the data, called egress. Try the calculator below to compare costs across providers:

storage-calculator - Cloud storage cost comparison
1 TB 50 TB
0 TB 200 TB
Cloudflare R2 $76.65/mo
$0.015/GB storage 10 GB free
Backblaze B2 $30.66/mo
$0.006/GB storage + $0.01/GB egress (3x free) 10 GB free
AWS S3 $209.92/mo
$0.023/GB storage + $0.09/GB egress
Azure Blob $181.25/mo
$0.018/GB storage + $0.087/GB egress
Google Cloud $225.28/mo
$0.02/GB storage + $0.12/GB egress
Best value at 5 TB storage + 1 TB egress

Backblaze B2 - Zero egress fees make a huge difference at scale

R2 gives us 10GB storage and 10 million reads/month free. That’s a lot of screenshots before we pay anything. And when we do pay, it’s $0.015/GB/month for storage with zero egress fees.

For a service that’s literally serving images, zero egress fees is huge.

Our infrastructure breakdown

Here’s exactly what we’re running and what it costs:

cost-breakdown - Monthly infrastructure costs
Total monthly cost: $5.30/mo
VPS (2 vCPU, 4GB RAM)
Hetzner CX22
$4.50
Object Storage FREE
Cloudflare R2 - 10GB free tier
-
Domain
NameCheap - ~$10/year
$0.80
Email (transactional) FREE
Resend - Free tier
-
SSL FREE
Let's Encrypt
-
CI/CD FREE
GitHub Actions
-
Container Registry FREE
GitHub Packages
-
Budget usage $5.30 / $20.00 (27%)
[✓] Well under budget!

Well under our $20 budget, leaving room for growth.

The hidden costs we’re avoiding

Managed databases - We’re running Postgres in Docker on the same VPS. Yes, we’re responsible for backups (automated with a cron job to R2, plus the machine itself is backed up). Managed Postgres starts at $15+/month, so hosting our own is the more budget friendly approach for now.

Managed Redis - We’re not using Redis yet. Postgres handles our job queue, and caching will be done on the application layer.

Log aggregation - We’re using Docker’s built-in logging for now. More fancy observability will be implemented at a later stage.

Monitoring - A free uptime checker (UptimeRobot) and basic health endpoints.

CDN - Cloudflare’s free tier in front of everything, which offers free SSL, free caching and free DDoS protection.

When we’ll upgrade

We’re not being cheap for the sake of it; we’re being frugal with our budget. These are example scenarios:

At 100 paying users: Move Postgres to a managed service. Backups and maintenance become worth paying for.

At 10,000+ daily screenshots: Consider a second worker VPS or upgrade to a beefier single machine.

At $500/month revenue: Revisit all infrastructure decisions. By then we’ll have more data on what actually needs scaling.

The risks of low cost hosting

Let’s be honest about the trade-offs:

Single point of failure. One VPS means one machine to fail. We’re accepting this risk. Hetzner has good uptime, and we can restore from backups to a new VPS in under an hour.

Limited resources. 4GB RAM is enough for Postgres + Spring Boot + several Playwright instances. But we can’t run many parallel browser sessions at this moment, so we’ll optimize carefully and queue jobs as much as we can.

No geographic redundancy. All our infra is in one Hetzner data center. If that data center has issues, we’re down. Unfortunate, but acceptable at this stage.

Manual scaling. Adding capacity means provisioning new VPS instances manually since there is no auto-scaling.

What we did today

  • Finalized hosting decisions
  • Set up Cloudflare R2 bucket for screenshot storage
  • Configured Cloudflare DNS and SSL
  • Created backup script for Postgres → R2
  • Set up UptimeRobot monitoring
  • Updated docker-compose with R2 credentials

Total spent so far: $4.50 for the Hetzner VPS (first month). Everything else is on a free tier.

Tomorrow: the core engine

On Day 6 we’re finally writing the fun code. Getting Playwright running, capturing our first programmatic screenshot, and learning what breaks when you try to render the web.

Book of the day

The Frugal Architect by Werner Vogels

Werner Vogels is Amazon’s CTO, and this collection of essays explores cost-conscious system design. The irony of AWS’s CTO writing about frugality isn’t lost on us, but the principles are solid.

His core laws include “make cost a non-functional requirement,” “unobserved systems lead to unknown costs,” and “cost-aware architectures implement cost controls.”

The key insight for us: cost efficiency isn’t something you bolt on later. It’s a design constraint from day one. Choosing Hetzner over AWS, R2 over S3, and Postgres-as-queue over Redis aren’t just about saving money - they’re about building a sustainable business where unit economics work even at small scale.


Day 5 stats

Hours
██░░░░░░░░░░░░░
10h
</> Code
█░░░░░░░░░░░░░░
250
$ Revenue
░░░░░░░░░░░░░░░
$0
Customers
░░░░░░░░░░░░░░░
0
Hosting
████░░░░░░░░░░░
$5.5/mo
Achievements:
[✓] Storage configured [✓] Monitoring active [✓] Backups automated
╔════════════════════════════════════════════════════════════╗
E

Erik

Building Allscreenshots. Writes code, takes screenshots, goes diving.

Try allscreenshots

Screenshot API for the modern web. Capture any URL with a simple API call.

Get started