The first version of this site ran on Django and Wagtail. Self-hosted PostgreSQL. Tailscale mesh for admin access. Cloudflare Tunnel so the server had no open ports — invisible to the public internet, no address to find, no login page to attack. The public site was pre-built HTML on Cloudflare Pages. Total monthly cost: zero. Annual cost: twelve dollars for the domain.

I was proud of it. The architecture was principled. I'd written up the reasoning in detail — own your infrastructure, use one tool instead of three, make the attack surface disappear. Every layer was replaceable, nothing proprietary, content belonged to the client. It was the kind of stack you design when you're thinking about what's correct.

Then I tried to get someone else to edit content on it.

The Friction That Mattered

Wagtail is a good CMS. But onboarding an editor meant giving them Tailscale access, walking them through a Django admin that's powerful but not obvious, and being around to troubleshoot when something didn't look right. The security model that made the server invisible to attackers also made it invisible to collaborators. The "own everything" philosophy was really "I maintain everything, and everyone else waits for me."

I didn't realize this was a problem until I compared it to Sanity. Invite someone by email, they open a browser, they start editing structured content. No VPN. No walkthrough. No setup call. The first time I watched someone go from invite to published content in under ten minutes, the Wagtail setup felt like a vanity project.

Building the Same Landing Page Enough Times

Meanwhile, I kept building landing pages. A consultant site. A hauler. A landscaper. Each one was an Astro site on Cloudflare Pages — the deployment pattern from the original stack still worked, because pre-built HTML on a global CDN is genuinely the right call for sites where most visitors are reading. But the content, the branding, the page structure — I was copy-pasting and tweaking the same files every time.

At some point the template stopped being a template and started being a platform. The backend became an Elixir service where a vertical definition — consultant, hauler, landscaper — configures vocabulary, offerings, scheduling, branding. A tenant is one operator running one vertical. Provisioning creates the tenant, seeds defaults, and the frontend builds a static site from a manifest API.

The shared pieces moved into a package: types, API functions, components, layouts. Each tenant site is still an independent Astro project, but the common patterns live in one place. New tenant: copy the template, set two environment variables, start editing.

What Survived and What Didn't

The deployment architecture from the original stack mostly survived. Static HTML on Cloudflare Pages, near-zero cost, no server processing per page view. The principles about pre-building what you can and using free tiers as real infrastructure — those held up. I still believe "invisible is more secure than fortified" for anything that doesn't need to face the internet.

What didn't survive was the self-hosted CMS. Wagtail, Tailscale, the private mesh — all replaced by Sanity's hosted service. The "own your infrastructure" principle bent when it met the reality of getting non-technical people productive. Sanity's editor invites and structured content model solved the collaboration problem I hadn't admitted I had.

The backend language changed too. Django and Python made sense when I was thinking about the AI ecosystem — Python-first tooling for structured extraction, data processing, embeddings. But the platform needed something different: concurrent connections, real-time features, multi-tenant isolation. Elixir handles those naturally. The AI work happens in dedicated pipelines now, not in the web backend.

What This Means if You're Not Technical

If you run a small business and someone tells you a website costs fifty dollars a month before you've written a word, something is wrong. The hosting for every site on this platform costs nothing. Not a trial, not a promo — Cloudflare's free tier is permanent and handles real production traffic. The only recurring cost is the domain name, roughly twelve dollars a year.

That's the real point of the JAMstack approach. Pre-build the pages as simple HTML files, serve them from a global network, and the infrastructure cost drops to nearly zero. You don't need a server running twenty-four hours a day to show someone your offerings page. You need files on a CDN. The complexity lives in the build step, which happens once when content changes — not on every page load.

The CMS is free at the scale most small businesses operate. Structured fields for titles, summaries, body content — not a blank text box where formatting breaks. Click publish, the site rebuilds, new content deploys globally in about two minutes. No command line, no file transfers.

The Tradeoff

The honest version: this stack is cheaper and more flexible than Wix or Squarespace, but it's not maintenance-free. Someone built the platform. Someone maintains the templates. When something needs to change that's outside the CMS — a new page type, a design update, a feature — that's development work.

The bet is that the development cost is worth it because you own everything. Content lives in structured formats you can export. The sites are portable — Astro builds to HTML that runs anywhere. Nothing is locked into a proprietary platform. If any vendor changes their terms, you migrate. The twelve-dollar domain is the only thing you can't replace for free.

Whether that tradeoff makes sense depends on what you value. If you want zero maintenance and don't mind the monthly fee and the lock-in, Squarespace is fine. If you want ownership, low ongoing cost, and the ability to grow into features like scheduling, lead capture, and AI-powered content — that's what this platform is for.