When people find out we run TableWork on a Mac Pro in my office rather than AWS or GCP, the first question is usually: why? The second question is usually: is that safe?
The short answers are: cost and control. And yes, we think so — but only because we built the backup and redundancy infrastructure to justify the claim.
The economics
A production-grade managed Postgres cluster on AWS (RDS Multi-AZ) for a startup's workload runs about $300 to $600 per month before egress and storage. Add a Redis instance, a worker queue, and a vector database, and you're at $800 to $1,200 per month before you've written a single line of application code.
A Mac Pro M2 Ultra — which is what we're running — costs $6,000 upfront and about $30 per month in electricity. That's a 10-month payback period at $600/month cloud spend. After month 10, the infrastructure is free.
The trade-off is operational complexity and single-point-of-failure risk. We decided we could engineer around the risks. Here's how.
## The architecture
The Mac Pro runs everything in Docker containers on a private network: Postgres (via supabase/postgres), pgBouncer for connection pooling, Redis for queuing and caching, Meilisearch for full-text search, MinIO for local object storage, and our application containers.
Cloudflare Tunnel handles ingress. There's no open port on the machine — Cloudflare's edge connects to our tunnel daemon running on the Mac Pro. Traffic from tablework.io hits Cloudflare's global edge network, which routes to the tunnel. DDoS protection, TLS termination, and geo-routing come with that for free.
## Backup and recovery
The biggest risk with self-hosting is: what happens if the machine fails? The answer is:
1. Continuous WAL archiving to Cloudflare R2. Every transaction is archived to object storage within seconds. Point-in-time recovery is possible to within 5 minutes.
2. Daily full dumps encrypted and uploaded to R2. Retained for 30 days.
3. Weekly restore tests in a sandboxed environment on a second Mac Mini. If the restore fails, we know before we need it.
4. The machine itself has 4TB of RAID storage with redundant drives. A single drive failure doesn't cause downtime.
The restore target is 4 hours of downtime in a worst-case scenario (full hardware failure, new machine required). For a startup's first-year operations, we think that's acceptable. Enterprise customers with stricter SLA requirements should contact us to discuss options.
## What cloud still handles
We're not pure self-hosted. Cloudflare handles CDN, DNS, DDoS protection, edge workers, and R2 for backup and file storage egress. We don't self-host those. The bet is that the compute and stateful data layers benefit most from local control, while the CDN and object storage layers benefit most from global distribution.
## Honest assessment
Self-hosting introduces operational complexity that most startups should avoid. We chose it because:
1. The team is small (one person). A $1,000/month cloud bill is a meaningful constraint when you're not yet revenue-generating.
2. The architecture expertise is available. I've run production databases on bare metal before. This isn't my first time managing a Postgres instance.
3. The backup infrastructure is solid. We didn't just put the database on a Mac and hope for the best.
If your operational context is different — larger team, higher revenue, less infrastructure expertise — the managed cloud path is probably right for you. We're not advocating for this approach generally. We're explaining why it made sense for us specifically.
Want to try this in TableWork?
Start a 14-day Pro trial. No card needed.
Start free trial