DEV Community

Erik for Allscreenshots

Posted on

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.

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 cheap until our needs justifies otherwise.

Our target for allscreenshots is to spend less than $20 USD/month for our hosting costs and CI/CD infrastructure. In this post we're diving into how we intend to get there.

The options we considered

Vercel / Netlify / Railway

Options like these are the current developer choice, especially for NextJS platforms. The platforms provide a great Developer Experience (DX), generous free tiers and overall, painless deployment.

Why we didn't choose them:

While this might be viable options for some, we had a free reasons not to go for them:

  • Free tiers have limits which exceed our needs, which could get expensive fast
  • Serverless doesn't play well with headless browsers (cold starts kill us)
  • We'd still need separate compute for Playwright workers
  • Costs become unpredictable at scale

For a static site or simple API, these are great. For a screenshot service running headless Chrome, they're not the
right fit.

AWS / GCP / Azure

The enterprise options. Almost infinitely scalable, but at cost of money and complexity.

Why we didn't choose them:

  • 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 which we rather spend on improving the product

While in the future we might need a bigger scale, we don't see the need today. However, since we're running on Docker
images, migrating to a cloud provider could be relatively straightforward in the future.

DigitalOcean / Linode / Vultr

These VPS providers provide a solid middle ground. They have simple and predictable pricing, good docs, and offer good
capacity at reasonable costs.

Benefits:

  • $5-10/month droplets are capable enough
  • Managed databases available
  • Good reputation in the indie hacker community

Vultr is our favorite and goto hosting provider, and we've used Vultr successfully in other projects.
However, we found something cheaper which we are willing to give a try.

Hetzner

A German hosting company that's popular in Europe but less known in the US.

Why we chose them:

  • CX22 VPS: 2 vCPUs, 4GB RAM, 40GB SSD - $4.50/month
  • Same specs on DigitalOcean: $24/month
  • Data centers in EU (good for GDPR) and US
  • Reliable, been around since 1997
  • No surprise pricing - what you see is what you pay

The value is above seems like a very good deal, and we'll do some proper benchmarks just to make sure Hetzner is up to the job.

Our infrastructure breakdown

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

Service Provider Cost
VPS (2 vCPU, 4GB RAM) Hetzner CX22 $4.50/month
Object Storage (screenshots) Cloudflare R2 $0 (free tier)
Domain NameCheap ~$10/year
Email (transactional) Resend $0 (free tier)
SSL Let's Encrypt $0
CI/CD GitHub Actions $0
Container Registry GitHub Packages $0

Total: ~$5.50/month (plus ~$0.80/month domain cost)

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

Why Cloudflare R2 for storage?

Screenshots need to live somewhere, and an S3 compatible storage is the standard. We have several options:

  • AWS S3: This is the standard, and quite affordable for storage, but egress fees add up when serving images.
  • Backblaze B2: Cheap storage, free egress through Cloudflare, but no experience with this.
  • Cloudflare R2: S3-compatible, zero egress fees, generous free tier.

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 no egress fees.

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

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 it backed up). But managed Postgres starts at $15+/month, with unpredictable costs at scale.

Managed Redis - We're not using Redis yet. Postgres handles our job queue, and caching will be done on the application layer. This is one less service to pay for and manage, which keeps things simple.

Log aggregation - We're using Docker's built-in logging for now. More fancy observability, like Datadog, New Relic or ELK can wait.

Monitoring - A free uptime checker (we're using UptimeRobot) and basic health endpoints.

CDN - Cloudflare's free tier in front of everything. Free SSL, free caching, free DDoS protection.

When we'll upgrade

We're not being cheap for the sake of it, plus, we see this more as being frugal with our budget.
We're trying to make a conscious choice about how we spend our budget, and we allow for growth.

These are example scenarios, and will most likely change over time, but a possible future plan could look like the following:

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

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

At $500/month revenue: Revisit all infrastructure decisions. We'll have data on what actually needs scaling.

Until then, we're using a slightly scrappy approach. If you have comments or suggestions, we'd love to hear from you!

The risks of cheap 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 + a couple Playwright instances. But we can't run
ten parallel browser sessions. We'll optimize carefully and queue jobs, and most likely we'll spin up more machines when we require more capacity.

No geographic redundancy. All our infra is in one Hetzner data center. If that data center has issues, we're down.
Again, acceptable at this stage, but it's something we'll look into when we need to.

Manual scaling. Adding capacity means provisioning new VPS instances manually since there is no auto-scaling. This is fine fine for now to keep
our costs under control, but might change in the near future.

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.

The essays are free to read online, but we'd recommend bookmarking them for reference.


Current stats:

  • Hours spent: 10 (previous 8 + 2 today)
  • Lines of code: ~250
  • Monthly hosting cost: $5.50
  • Revenue: $0
  • Paying customers: 0
  • Storage configured: ✓
  • Monitoring active: ✓
  • Backups automated: ✓

If you want to see the service in action, checkout allscreenshots for a free trial.

Top comments (0)