Engineering

TLS for every topology

July 11, 2026 · 5 min read

One HTTPS story is easy to write when every server has a public IP and open :80/:443. Real fleets aren't that uniform: a VPN-only box that never sees the public internet, a fleet of subdomains sharing one apex, a server already sitting behind a load balancer someone else owns. We ended up shipping four TLS modes, not one, because the topology decides which certificate story is even possible.

TLS mode is a per-app setting — the dashboard's Settings tab, or buildSpec.tlsMode underneath. Pick whichever of the four below actually matches how the server is reachable.

The default: HTTP-01, no setup

For a normal, publicly reachable box, TLS needs nothing from you at all. Caddy obtains and renews the certificate itself, straight from the route's own site addresses, the moment the app's domain is configured. Use this unless the server can't open :80/:443 to the public internet or already sits behind your own load balancer — those are the only two cases where this default stops working.

This is also the mode where a server's own bootstrap has to be careful about who owns the port in the first place. If something else already holds :80/:443 when a box enrolls — an existing nginx, say — bootstrap detects it and skips starting Sproobo's own proxy rather than fighting over the port, the same class of collision we deleted for containers in general on why we rebuilt Sproobo on Docker-everything.

VPN-only and closed boxes: DNS-01 delegation

A server that's VPN-only, LAN-only, or otherwise firewalled off from the public internet can never complete an HTTP-01 challenge — there's no public path in for the challenge to land on. Delegated DNS-01 solves that with one CNAME record, created once at your own DNS provider, and nothing else:

_acme-challenge.example.com. CNAME a1b2c3.acme.sproobo.com.

Sproobo checks that record against two independent public resolvers every few minutes, or on demand with a "Verify now" button. Once it matches, Caddy issues an apex-plus-wildcard certificate through that delegation and the app redeploys automatically — no DNS-provider API keys or credentials are ever collected, just the one CNAME. It's the only mode built specifically for a box the outside world genuinely can't reach: the trade is a one-time DNS change instead of zero setup, which is exactly the deal a closed server should be making.

Subdomain fleets: one wildcard cert

A different shape of problem shows up when one apex needs to host many subdomains — a multi-tenant staging pattern, say, where every customer or preview gets its own hostname under the same root domain. Issuing a fresh certificate per subdomain doesn't scale the way it should. Wildcard mode, which shipped July 7, 2026, verifies a single CNAME once against a standalone WildcardDomain and issues one *.apex certificate. Every app created afterward as a child of that domain shares the same certificate automatically — zero additional DNS records and zero additional certificate issuance per subdomain added. Each subdomain is still its own app, with its own deploys and its own blue-green health gate; only the certificate is shared. It's a choice made at app-creation time; converting an existing app into or out of wildcard mode isn't supported from the dashboard yet.

Someone else's load balancer: external termination

Some apps are already behind TLS they don't need Sproobo to provide — an AWS ALB, a Cloudflare proxy, any load balancer that terminates TLS itself and forwards plain traffic downstream. External termination mode skips certificate issuance entirely for that app and serves it over plain HTTP on :80. Deliberately, there's no HTTP→HTTPS redirect for that host either — your load balancer is the one that owns TLS and expects to talk plain HTTP to what's behind it, so redirecting would just break the thing it's forwarding to. It's the simplest mode in one sense — Sproobo issues nothing and renews nothing for that host — and the one place where "automatic HTTPS" is deliberately not the default, because the automation genuinely belongs to infrastructure Sproobo doesn't own.

Two rules that hold no matter which mode you pick

Whichever of the four modes an app uses, two things about it never change. First, every domain is configured as apex and www together, always — give an app example.com and Sproobo configures both example.com and www.example.com, never just one. A validator rejects any route where one is missing its counterpart; both names populate the certificate's SAN set, and a canonical 301 redirects the non-preferred host to the one you picked — both stay served and certificate-covered so the redirect itself can't break.

Second, outside the external-termination case above, every host gets automatic HTTP→HTTPS upgrades platform-wide: a plain HTTP request gets redirected to HTTPS by default, with no per-app opt-in required to turn it on. Switching an app to external mode is the one deliberate way to turn that off for a given host, since Sproobo isn't the one terminating TLS there in the first place — every other mode gets the redirect automatically, by default, everywhere.

Four modes because four topologies actually exist in a real fleet, not because we wanted four ways to do the same thing. Read the full proxy, certificate, and firewall model on Networking & TLS, see where TLS mode fits into creating an app on Apps & deploys, or read the trust-boundary writeup behind the firewall and internal network on Security model.

← Back to the blog

Get started

Run this on a server you own.