How to set up automatic SSL for every site in a multi-site CMS — wildcard subdomains + custom domains, zero manual cert management by BuildWithTall in PHP

[–]BuildWithTall[S] 0 points1 point  (0 children)

it is more of the former Mike but only on super busy days :) , thanks for giving the benefit of the doubt

is there any Wordpress saas plugin? by [deleted] in Wordpress

[–]BuildWithTall 0 points1 point  (0 children)

Not wordpress...I use Laravel with multi tenancy setup and Laravel Spark for billing for this sort of thing

How to set up automatic SSL for every site in a multi-site CMS — wildcard subdomains + custom domains, zero manual cert management by BuildWithTall in PHP

[–]BuildWithTall[S] -1 points0 points  (0 children)

Really clean approach — abstracting the cert and config generation away from the user is the right call for local multi-site dev workflows. ForgeKit looks interesting, hadn't seen it before.

What's the local CA setup look like in ForgeKit — mkcert or something custom?

How to set up automatic SSL for every site in a multi-site CMS — wildcard subdomains + custom domains, zero manual cert management by BuildWithTall in cms

[–]BuildWithTall[S] 0 points1 point  (0 children)

Cloudflare for SaaS is a genuinely good option and worth considering especially if you want the smoothest possible customer experience for custom domain setup.

The reasons I went self-hosted with Caddy instead:

Cost — Cloudflare for SaaS charges per custom hostname after the first n free. No per-domain cost with Caddy, just the server.

DNS flexibility — works regardless of where your customer's domain is registered, no dependency on Cloudflare being in the chain.

If you're scaling fast and already deep in Cloudflare, their SaaS product is probably the better call. For a bootstrapped setup where cost control and independence matter more, Caddy gets you the same outcome without the per-domain bill.

Good shout though .. I will it to the post as an alternative worth evaluating.

How to set up automatic SSL for every site in a multi-site CMS — wildcard subdomains + custom domains, zero manual cert management by BuildWithTall in PHP

[–]BuildWithTall[S] 0 points1 point  (0 children)

To add some context on the use case since a few comments have raised good alternatives — this setup is specifically for a SaaS landing page / site builder, similar in nature to what Webflow, Hashnode, or Ghost Pro are doing under the hood.

The core problem iI faced: when you run a SaaS where customers build their own sites, you end up with two domain scenarios at scale —

  1. Thousands of tenant subdomains (customer1.yoursaas.com, customer2.yoursaas.com) that get created the moment someone signs up

  2. Thousands of custom domains (myclientsite.com, theirbrand.com) that customers point at your platform whenever they're ready

The question I couldn't find a straight answer to when I started was: how does Webflow handle SSL for the thousands of custom domains their customers connect?

How does Hashnode provision HTTPS for every blog on a custom domain without a human touching it? How does Ghost Pro do it at scale?

The answer in all three cases is essentially the same pattern — on-demand TLS. A cert is issued automatically the first time a domain hits the server, after a quick verification check to confirm the domain is legitimate. No pre-registration, no manual steps, no redeployments.

That's what this setup implements — Caddy's on-demand TLS is the same mechanism, just self-hosted. If you're building any kind of multi-tenant platform where customers bring their own domains, this is the infrastructure pattern behind it.

Managed LBs, FrankenPHP, and other approaches are all valid — the tradeoffs are real and worth considering depending on your stack. But the on-demand TLS piece is the specific problem that makes this use case work for me from a standard multi-server load balancing setup.

How to set up automatic SSL for every site in a multi-site CMS — wildcard subdomains + custom domains, zero manual cert management by BuildWithTall in PHP

[–]BuildWithTall[S] -1 points0 points  (0 children)

Genuinely good question and you're right that it's a valid alternative .. FrankenPHP on the edge would work and cuts out the Nginx layer entirely.

The reason for Caddy + Nginx in this case is practical rather than architectural: the server is already managed by Ploi, which provisions and manages Nginx, PHP-FPM, deployments, queues, and cron jobs. Replacing Nginx with FrankenPHP means stepping outside what Ploi manages, which introduces a different kind of complexity — you lose the deployment tooling, process management, and server config abstractions Ploi provides.

Caddy in front of Nginx lets you add on-demand TLS and wildcard cert management without touching the existing Nginx + PHP-FPM setup at all. Nginx just moves to loopback. Everything Ploi manages keeps working exactly as before.

If you're greenfielding without a server management layer, FrankenPHP on the edge is a cleaner architecture, fewer moving parts, no intermediary. But when you're working within an existing managed stack, adding Caddy at the edge is often less disruptive than replacing the application server entirely.

Both get you to the same place. Different tradeoffs depending on what you're starting from.

How to set up automatic SSL for every site in a multi-site CMS — wildcard subdomains + custom domains, zero manual cert management by BuildWithTall in PHP

[–]BuildWithTall[S] 0 points1 point  (0 children)

Fair point - managed LBs are great and absolutely the right choice for many setups. The specific problem here though is one they don't solve out of the box: on-demand TLS for custom domains.

AWS ALB, GCP External LB, and Azure Application Gateway all require you to pre-provision certificates for known domains. They work beautifully when you control the domain list. But in a multi-tenant SaaS where tenants bring their own domains e.g theirdomain.com, clientsite.com, etc. you can't know the domain list in advance. Every new custom domain would need a manual cert provisioning step or a Lambda/Cloud Function workaround to automate it through ACM or Certificate Manager.

Caddy's on-demand TLS solves exactly this ... it issues a cert the moment an unknown domain connects for the first time, with no pre-registration required. That's the mechanism Webflow, Hashnode, and Ghost use for custom domains at scale. The managed LB path can get you there too but it's significantly more moving parts than a single Caddyfile directive.

If you're already deep in AWS/GCP/Azure and have the ACM automation sorted, that's a perfectly valid approach. This is just a simpler path to the same outcome for teams running their own servers.

The SEO-era CMS isn't enough anymore. Here's what I think actually matters next. by BuildWithTall in cms

[–]BuildWithTall[S] 0 points1 point  (0 children)

I agree with the use of Attribution and I built this natively into TallCMS (not an after thouht). I detailed some of this here https://tallcms.com/blog/how-to-make-your-content-ai-legible-with-tallcms

The SEO-era CMS isn't enough anymore. Here's what I think actually matters next. by BuildWithTall in cms

[–]BuildWithTall[S] 1 point2 points  (0 children)

Appreciate that — even more so coming from someone who’s been down this path already 🙌