Fixed monthly infrastructure cost to run the entire stack that powers our £49/mo Lite tier: £13.60. That is not a typo. Variable costs (Claude API, Stripe fees, Twilio per-message) sit on top of the £13.60 and only scale as customers do. Here are the receipts, the design decisions, and the points where this stack is guaranteed to break.
I'm a solo founder. No co-founder, no funding, no developer-hour budget for Kubernetes or AWS bills that scale faster than revenue. The constraint shaped every architectural choice. If you are an indie founder building something similar in 2026, the line items below might save you a thousand pounds and a month of YAML.
The receipts (fixed costs)
consentleads.uk
£0.00
demo.consentleads.uk over HTTPS, no port forwarding
£0.00
[email protected] + outbound webhook to FastAPI
£0.00
Almost the entire fixed cost is "the things that aren't free." Brave Search at £4 covers all the sourcing for our cold outreach pipeline. The £8.85 misc is a handful of pence-level transactional fees that I rounded up to a flat number for honesty. The domain is the only thing where the cost is real and unavoidable.
The variable costs
Variable costs are the ones that scale with usage. They are the right shape: zero customers means zero cost, customers paying us means costs that are a fraction of revenue.
At 10 paying Lite customers, total monthly bill: £13.60 fixed + (10 × £2.34) variable = £37 a month to deliver £490 of MRR. Gross margin sits around 92% before my time. That is the unit economics indie SaaS dreams about.
Architectural decisions, justified
The free-tier stack is only free because of design decisions, not luck. Here are the ones I would not change.
Oracle ARM Always Free instead of AWS/Render/Fly
Oracle gives you 2 ARM-based vCPUs, 24 GB RAM, 200 GB block storage, 10 TB outbound transfer, and a public IPv4, all on the "Always Free" tier. For a small SaaS, this is more than enough. Equivalent AWS spend would be roughly £80-120 a month for a comparable EC2 instance with the same RAM.
The catch: Oracle Always Free instances can be reclaimed if idle. I run a cron job every 30 minutes that pings the demo URL, so the instance counts as "in use" and stays put. So far, 8 months in, zero reclaims.
Cloudflare Tunnel instead of a load balancer
Cloudflare Tunnel exposes a localhost port on the Oracle box to the internet over HTTPS, no NAT punching, no port forwarding, no ALB. Free. You install cloudflared, point it at your FastAPI on localhost:8000, and Cloudflare publishes it at demo.consentleads.uk. Done.
It also gives you Cloudflare's edge for free: DDoS protection, geographic caching, Bot Fight Mode if you turn it on. The only competitor at this price point is ngrok's free tier, which has session limits.
JSONL on disk instead of Postgres
Every piece of state lives in a flat JSONL file on the Oracle box. Customer configs live at demo/customers/{ig_user_id}/config.json. Conversation logs at demo/customers/{ig_user_id}/conversations/{psid}.jsonl. Suppression list at demo/suppressions.jsonl. Cold-email send logs at logs/send_*.log.
Why? Because at 0 - 50 paying customers, JSONL is faster to debug than a database. You can cat the file, you can tail -f it, you can grep across all conversations. You do not need a connection pool, you do not need migrations, you do not need an ORM. The whole “data layer” is open() and json.loads.
This will break at scale. Sometime around 100 active customers I will need SQLite (and SQLite-on-disk is still single-process, no migration drama). Postgres comes in at ~500+ customers if I am still running this solo. Until then, JSONL is the right answer because I can debug it without leaving my terminal.
cron and at instead of a job queue
UK cold-email batches fire at 10:00 and 15:00 UTC via Linux at jobs, scheduled the day before by schedule_30_day.py. Daily sourcing (Google Places) runs at 05:30 UTC via cron. Reply triage runs every 4 hours via cron. Bounce handler runs at 03:00 daily via cron.
I could have set up Celery + Redis. I did not. Cron is 50 years old, in the kernel, never crashes, has zero ops burden. The at daemon handles one-shot future-dated jobs which is exactly what cold-email batching needs.
The whole orchestration layer is about 40 lines of shell. The "queue" is the Linux process scheduler. The "monitoring" is journalctl -u consentleads-demo --no-pager -n 30.
FastAPI + uvicorn + systemd, no Docker
The web app is a single FastAPI process managed by systemd. No Docker, no docker-compose, no Kubernetes. Restart is sudo systemctl restart consentleads-demo. Logs go to a file via StandardOutput=append:/home/ubuntu/freelance/logs/demo.log.
Container orchestration would be the right answer at 5+ environments. I have one. Adding Docker would be 8 hours of work and zero new capability.
Notion for CRM instead of a real database
The CRM is just a Notion database with 800 prospect rows. Notion has a free Personal plan, a usable API, and the front-end I would have to build otherwise. The data sync is a Python script that POSTs to https://api.notion.com/v1/pages.
This is the decision that bothers me most architecturally. Notion's API is rate-limited (3 req/sec) and the data shape is more rigid than I'd like. But the alternative is building a CRM UI, which costs more time than £0 a month is worth. At ~5 paying customers I'll migrate to SQLite + a tiny admin UI.
The general pattern: when a managed service's free tier covers your usage, use it. When the free tier ends and the priced tier is <£20/mo, pay for it. Only build it yourself when both (a) free tiers are gone and (b) priced tiers cost more than the engineering hours you would spend rebuilding it. Most indie SaaS goes broke building things they could have rented for £15.
Where this stack is guaranteed to break
I have written down the next four migrations so I do not pretend I have a permanent solution.
Resend free tier - breaks at ~3,000 emails/mo
Current cold-outreach volume: ~50 sends/day weekdays = ~1,100/mo. Headroom until forced upgrade: about 1,900 emails/mo. At 2 paying Lite customers (cold outreach plus their transactional + welcome emails), I cross into Resend Pro (£16/mo). That triggers our 30-day campaign volume doubling, which is the point of getting paying customers.
JSONL on disk - breaks at ~100 active customers
The bottleneck is list_all() in customer_store.py, which globs every customer directory and reads every config.json. That gets slow when each /dashboard request triggers it. The fix is SQLite, one file, indexed on email + stripe_customer_id + ig_user_id. ~3 days to migrate, no schema headache because the existing JSONL is the schema.
Notion CRM - breaks at ~5 paying customers
Mostly a UX problem. The Notion CRM is brilliant for me; it is hostile to a sub-contractor I might pay to triage replies. The fix is a tiny in-house CRM at /dashboard/admin that lives in the same SQLite as above. ~3 days of work after the JSONL migration.
Oracle Always Free - could change at any time
Oracle Always Free is a marketing program. If Oracle ever decides to pull the tier, we get 60 days notice and need to migrate. Plan B is Hetzner ARM dedicated, £5/mo, no perceptible difference for our workload. Plan C is AWS Lightsail at ~£15/mo. Either way the migration is "rsync the freelance directory, install Python 3.11 + uvicorn, restart". Half a day.
What I'd do differently if I was starting today
Three things, in order of usefulness.
Skip Notion as primary CRM. Build the in-house CRM from day one using SQLite + a 200-line FastAPI admin. It would have been 2 days of work upfront and would have saved me writing 4 different Python scripts to sync data to and from Notion's API. The Notion + custom-sync pattern is fragile and I keep finding edge cases.
Use Cloudflare D1 for early state. D1 is Cloudflare's edge SQLite. It is free up to 5 GB. If I had started with D1 I could have kept the FastAPI on Oracle but pushed customer state to the edge, which would have let me move the dashboard to Cloudflare Workers and drop the Oracle dependency for most requests. I did not because D1 was beta when I started. It is GA now.
Buy a proper Resend domain from day one. I started with the apex domain (consentleads.uk) for both transactional and cold outreach. They have different reputation profiles. Cold outreach burns sender reputation, transactional is fine. They should be on separate subdomains from day one. Now I have to migrate transactional to a clean subdomain before scaling.
If you are building something similar
The whole stack is reproducible in a long weekend if you have a Stripe account and a Cloudflare account.
- Oracle Cloud account (free), provision an ARM Always Free VM in London region
- SSH in, install Python 3.11, uvicorn, FastAPI, install
cloudflared - Point a Cloudflare Tunnel from
cloudflared tunnel createatlocalhost:8000, attach todemo.your-domain.uk - Write the FastAPI routes for whatever your product is
- Cloudflare Pages for the marketing site, deploy via
wrangler pages deploy - Resend account (free), verify your domain (3 DNS records, 10 minutes)
- Stripe account, set up a payment link, point its
checkout.session.completedwebhook at your FastAPI - Anthropic API key, plug into your FastAPI handler
- Cron for daily jobs,
atfor one-shot scheduled jobs, JSONL for state
Total cost to be in production with a real domain, real HTTPS, real email delivery, real payments: under £15/mo until your first 10 customers. The hardware exists for free because Oracle wants you to upgrade later. Cloudflare's free tier exists because they make money on enterprise. Resend's free tier exists because they want you to grow into the paid tier.
The infrastructure cost is solved. The constraint is finding people who want what you are building.
One thing I am not optimistic about
Cold outreach reputation is the bottleneck I worry about most. Resend has tightened bounce thresholds. Gmail has reduced spam-folder tolerance. Outlook has gotten stricter on SPF/DKIM/DMARC alignment.
You can build a Claude-powered reply system on £13.60/month. You cannot reach the customers who need it for £13.60/month. Distribution costs - paid ads, content, partnerships - are where the real spend goes, and where the real risk lives.
That is the part I am still figuring out. If you have working playbooks for indie SaaS distribution in the UK, my email is below and I will trade you receipts.
I am Sal. Consent Leads is a UK studio shipping Lite (£49/mo, Instagram DM autoresponder) and three larger tiers for service businesses. If you want to argue with any of the architectural decisions above, my email is [email protected]. If you want to compare receipts, even better.