The SaaS Trap Nobody Talks About
We’ve all drunk the Kool-Aid. SaaS is magic. Cloud is infinite. Just swipe your credit card and watch your problems disappear into the ether of someone else’s servers.
Except they don’t disappear. They multiply. Like gremlins fed after midnight.
Here’s the thing about modern cloud platforms like AWS: they’re not lying when they promise you can start small. A Lambda function here, an API Gateway there—you’re cruising at $5/month feeling like a cloud architect genius. You’ve read all the Medium articles. You know the patterns. You’re optimized.
Then reality kicks in the door.
The Five Nines Shakedown
Let me tell you a story that every backend engineer knows but pretends they don’t.
You start with a simple REST endpoint. Lambda + API Gateway. Beautiful. Serverless. Cheap. The cloud gods smile upon you. $5/month.
Then you need reliability. Add SQS for async processing. Still reasonable. Maybe $8/month now.
Then you need state. Add RDS because you’re not an animal. $15/month. Getting spicy, but acceptable.
But here’s where the nightmare begins. Because you can’t just have a database on the public internet like some kind of barbarian. You need:
- A VPC (free, but cursed)
- Private subnets (free, but mandatory)
- A NAT Gateway so your Lambda can reach the internet ($32/month just existing)
- VPC Endpoints for every AWS service your Lambda touches ($7/month per endpoint)
- S3 endpoint. DynamoDB endpoint. Secrets Manager endpoint. The bill grows like kudzu.
Suddenly your cute little $5 serverless function costs $50-70/month. And $40 of that? Network plumbing tax. Not compute. Not storage. Just the privilege of having private networking in 2025.
The five nines SLA isn’t free. It’s a protection racket with better documentation.
The Vendor Lock-In Handcuffs
But wait, there’s more! The cost isn’t even the worst part.
I built Metis using AWS CDK. It’s deployed with all the AWS-native services—DynamoDB for state, EventBridge for events, Lambda for compute. Beautiful architecture. Completely imprisoned.
Want to move to another cloud? Rewrite everything. Want to self-host? Good luck finding DynamoDB in a Docker image. Want to just run it on a VPS? You’re essentially starting from scratch.
This is the silent killer: you’re not just paying AWS monthly rent, you’re building your entire project in their proprietary dialect. Every service you use is another chain. Every managed offering is another dependency you can’t replicate elsewhere.
To go portable, I’d need to rebuild Metis with the open-source equivalents—PostgreSQL instead of DynamoDB, RabbitMQ instead of SQS, Redis instead of ElastiCache. All the boring, battle-tested tools that run anywhere and don’t hold your architecture hostage.
The cloud isn’t just expensive. It’s a hotel you can never check out of.
The Breaking Point
So I decided to start smart. Beginning with something simpler: this blog.
Get the self-hosted infrastructure right with a straightforward use case, learn the operational patterns, build confidence with backups and monitoring. Then tackle Metis migration with the open-source stack—Redis, RabbitMQ, PostgreSQL—tools that I can run anywhere, on any provider, or on a server in my closet if I want to.
What if I waited until I had real paying customers—critical mass that justified cloud provider margins—before I handed over the keys to my margins and my architecture?
Revolutionary concept, I know. Hosting things yourself. Like it’s 2008.
Who said that in 2025 going back to basics isn’t sexy?
Microservices? Sure, when you need them. Cloud? Absolutely, when there’s a reason. But not because it’s in the 2025 playbook—because there’s actual need for it. And right now? There isn’t. I’m not against these patterns. I’m just not cosplaying as a unicorn startup when I’m a one-person side project.
Enter the Barbarian: Hetzner
I bought a dedicated server from Hetzner. An i7 with 64GB RAM. The whole machine. Not a slice. Not a “compute unit.” The whole damn machine.
Cost? Less than what AWS wanted for NAT Gateway + VPC Endpoints.
The normies in the cloud-native Slack channels gasped. “But what about autoscaling?” What about it? I have 64GB of RAM and exactly zero users. I’ll worry about autoscaling when I have champagne problems.
“But what about redundancy?” Buddy, my blog has three subscribers. Redundancy is a luxury for people who have users.
Building the Stack (AKA Doing It Old School)
Here’s what a production-grade self-hosted setup looks like in 2025 when you’re not LARPing as Netflix:
The Foundation
- Hetzner bare metal - i7, 64GB RAM, actual spinning rust you can point at
- Debian (latest stable) - boring is beautiful, and Debian is the most boring of all
- Hetzner Storage Box - because backups or death
The Edge (Because I’m Not Stupid)
- Cloudflare handles:
- DNS (free)
- TLS termination (free)
- DDoS protection (free)
- IP hiding (free)
- Making me look like I spent money (priceless)
The Fortress
OpenSSH locked down tighter than my wedding ring:
- Key-based auth only
- ED25519 keys (because it’s 2025)
- No password login (I’m not a monster)
- No root SSH (see above)
- Keys managed in Termius because I’m not editing
authorized_keyslike a caveman
Fail2ban watching SSH like a paranoid bouncer:
- Automatic IP banning after failed attempts
- Because script kiddies never sleep
- SSH hardening that actually works
UFW Firewall with exactly three ports open:
- 22 (SSH, key-only, Fail2ban-protected)
- 80 (HTTP, redirects to 443)
- 443 (HTTPS, the only port that matters)
Netdata for system monitoring:
- Real-time metrics
- CPU, RAM, disk, network
- Because flying blind is for pilots, not sysadmins
- Beautiful dashboards that don’t cost $200/month

The Web Layer
Caddy as reverse proxy because:
- Automatic HTTPS (Certbot can die mad about it)
- Caddyfile reads like English
- No OpenSSL RSI from typing nginx config
The Runtime
Docker + Docker Compose because:
- I’m not installing MySQL globally like it’s 2012
- Reproducible deployments
docker-compose up -dis the extent of my deployment ceremony
The Application
Ghost (self-hosted) in a container:
- Full data ownership
- No vendor lock-in
- Markdown-first writing
- Membership support for when I inevitably monetize
- MySQL 8 for persistence (in another container, because separation of concerns)
The Plumbing
Amazon SES for email because even barbarians need:
- Transactional emails (login links, password resets)
- SPF/DKIM/DMARC configured via Cloudflare DNS
- Not ending up in spam folders
The Safety Net
- mysqldump + tar for backups
- rsync over SSH to Hetzner Storage Box
- cron running nightly because automation or death
- Actual restore testing (yes, I tested it, no, you probably haven’t)
The Result
A secure, minimal, production-grade blog that:
- Costs less than a decent lunch in Athens
- Gives me full ownership of my content
- Has clear backup/recovery paths
- Deploys with
git pull && docker-compose up -d - Doesn’t require a PhD in AWS networking
- Won’t bankrupt me if a post goes viral
- Can be replicated on any provider in an afternoon
What’s Next: Liberating Metis
The blog was phase one. Learning the patterns. Building confidence. Getting comfortable with backups, monitoring, and operations.
Phase two? Rebuilding Metis with the open-source stack.
Out with:
- DynamoDB → PostgreSQL (runs anywhere)
- SQS → RabbitMQ (battle-tested since 2007)
- ElastiCache → Redis (the Swiss Army knife of caching)
- AWS CDK → Docker Compose (infrastructure as readable code)
The goal isn’t to avoid the cloud forever. When Metis has paying customers with SLAs and uptime requirements, I’ll graduate to proper cloud infrastructure. But I’ll do it with portable architecture that doesn’t chain me to a single vendor.
I can move to AWS. Or GCP. Or Azure. Or back to Hetzner. Or a Raspberry Pi in my living room if I’m feeling spicy. The architecture doesn’t care.
That’s the freedom I’m building toward.
The Philosophy
Look, I’m not anti-cloud. I work with AWS every day at my real job. I know the patterns. I respect the complexity.
But for side projects? For things that don’t have product-market fit yet? For blogs and authorization platforms that serve dozens of requests per day?
The cloud is financial masochism dressed up as best practices.
You’re paying enterprise prices for hobbyist traffic. You’re configuring VPC endpoints for a site your mom hasn’t even visited yet. You’re debugging IAM policies at 2 AM for a project that makes $0/month. You’re locking yourself into proprietary services that make your architecture impossible to move.
There’s a simpler way. It involves:
- One server
- One Caddyfile
- One Docker Compose file
- One backup script
- One monitoring dashboard
- Zero venture capital
- Zero vendor lock-in
Is it “web scale?” No. Will it autoscale to handle the HN front page? Also no.
But it costs $30/month instead of $300, it took me an afternoon to set up, and when I wake up tomorrow, the bill will be exactly the same. And if I want to move it? I can. Anywhere. Anytime.
That’s not barbarism. That’s engineering.
Want to argue about autoscaling and disaster recovery? Find me on LinkedIn where I promise to take your concerns very seriously while continuing to pay $30/month for infrastructure.
Running your own infrastructure horror stories? I collect them. Email me.
Member discussion: