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.
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
[✓] 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
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
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
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
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:
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:
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.