May 30, 2026 · issue #5

The cloud bill is an architecture review

The whole control plane runs on $5.96 a month.

hetzner cx22          $4.59
cloudflare r2         $0.12
boringstack.org dns   $1.25
resend (free tier)    $0.00
────────────────────────────
total                 $5.96/mo

That bill runs two production apps: borela.dev (a babysitter service for SQLite-on-VPS apps — backup verification, restore drills, agent heartbeats) and api.boringstack.org (this newsletter backend). Same VPS, different systemd users, different ports, different SQLite files. Adding the second app cost zero dollars.

You can’t trace a bug from a Vercel invoice. You can trace one from this.

$4.59 — Hetzner cx22

One €4.51 (≈$4.59) Hetzner cx22. 2 vCPU, 4 GB RAM, 40 GB SSD. Currently running:

Two apps. Four processes. One box.

The platform-PaaS equivalent for one of these apps — say, Render with a worker service, a Postgres add-on, and a managed Redis — runs $30–80/mo. You pay it per app. So the platform version of this exact setup is $60–160/mo, not $4.59.

The architecture lesson: co-tenancy works on a boring stack because every component is a process, not a platform. systemd doesn’t care that two apps share a box. Caddy doesn’t care. SQLite definitely doesn’t care — it’s a file. The marginal cost of adding bsb next to borela was the disk and RAM that weren’t being used yet. Roughly zero.

$0.12 — Cloudflare R2

R2 stores backup snapshots. Both databases together are under 50 MB; we keep ~30 days of snapshots; storage cost rounds to twelve cents.

Egress is free, which is the actually-important number on this line. R2 doesn’t charge to pull data out, which means a restore drill costs $0 to run. That’s not a cost story — it’s an availability story. The reason most backup setups quietly atrophy is that the test costs money or attention or both. When the test is free and one command, you actually run it.

That’s the next issue.

One honest note: bsb doesn’t ship Litestream. The OSS boring-stack skill still defaults to Litestream for fresh projects, but on this specific VPS, borela-agent was already running to back up borela.dev’s own DB, so adding a second project block to its config was simpler than standing up a parallel Litestream service. The bill bends to what’s already on the box. If borela-agent weren’t here, this line would still be $0.12 of R2 storage — plus a litestream-bsb.service doing the same job from a different angle.

$1.25 — boringstack.org DNS + registrar

Cloudflare registrar at cost. Nothing clever.

The architecture lesson is: this is the only line on the bill you genuinely cannot self-host. Every other line has an opt-out — you could move the VPS, swap object storage providers, run your own MTA. The domain doesn’t have an opt-out. Somebody owns the root and you rent a label off of it.

Spend the $15/year. Move on.

$0.00 — Resend (free tier)

Resend’s free tier is 3,000 emails/month, 100/day. We’re sending well under that — confirmation flow plus a handful of newsletter issues per month, to a small audience. The free tier covers our year-one needs roughly 100x over.

The architecture lesson: most managed services have a free tier that’s bigger than your year-one needs. Use them. Don’t apologize. Don’t run your own SMTP server because of a principle. Save the principle for the place it matters — the database, the part that owns user data, the part that has to survive a vendor bankruptcy. Email isn’t that.

What’s not on the bill

Component This stack Platform equivalent
Object cache (Redis) $0 — SQLite is fast enough $10–25/mo
Queue (Sidekiq, SQS, etc.) $0 — in-process worker tick $5–20/mo
Observability (logs, metrics) $0 — journalctl + free-tier uptime check $20–100/mo
CI / build / deploy $0 — make build && scp && systemctl restart from a laptop $0–50/mo
Application hosting (counted in $4.59) $25/mo per app

Four lines that aren’t there because the architecture doesn’t have somewhere to put them. There’s no Redis line because there’s no Redis. There’s no CI line because the deploy is a shell script. The bill isn’t smaller because we’re cheap. It’s smaller because there are fewer components.

The actual lesson

Every line on your bill is a component you’ll have to debug at 3am someday.

The bill is the blast radius in dollars.

A $6/mo bill has a 4-component blast radius: VPS, object storage, registrar, email. Pick a problem and you can be reading the right log file in under sixty seconds.

A $200/mo bill has a 30-component blast radius: PaaS host, managed Postgres, managed Redis, a queue, a CDN, a log aggregator, an APM, a feature-flag service, an auth provider, a transactional mailer, a marketing mailer, a status page, a CI runner, a container registry, an error tracker, and so on. Pick a problem and you have to figure out which dashboard owns it before you can look at it.

Bugs scale with components, not with traffic. A small app on a small bill has a small bug surface by construction. That’s not frugality. That’s an architecture choice expressed as a dollar amount.

The deal, again

This is issue #5. Next Tuesday: the first restore drill — actually pulling the SQLite DB out of R2 onto a fresh box and proving the backup works. Stopwatch and screenshots.

Boring is not free. Boring is cheap and small enough to fit in your head.

Star the repo. Reply with your stack and your bill. I read every reply.