One proxy, atomically reconfigured
Every app and service sits behind a single Sproobo-owned Caddy container. Route changes are validated before they're live, certificates renew themselves, and nothing about getting a domain working requires you to touch the box directly.
The shared proxy
A server gets one ingress container that owns :80 and :443. Route changes go through Caddy's admin API as an atomic config load, and caddy validate gates every change. A bad route can't leave the box half-broken. The last-known-good config is retained, so a failed reload falls back to what was already working rather than an empty proxy.
Caddy reaches your app or service by its container DNS name over the internal network, not a host port. See the internal network below.
Apex + www together by default
Give an app example.com and Sproobo configures both example.com and www.example.com together. This isn't a checkbox: a validator rejects any route where an apex domain lacks its www counterpart or vice versa. Both names populate the Caddy site address and 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 never breaks. Subdomains, wildcard children, and apps deliberately served without www instead declare a single explicit host.
Four ways to get a certificate
TLS mode is a per-app setting (dashboard Settings tab, or buildSpec.tlsMode under the hood). Pick the one that matches how the server is reachable:
Default: HTTP-01
The normal path. Caddy obtains and renews the certificate itself, straight from the route's site addresses, with no extra setup on your side. Use this unless the server can't open :80/:443 to the public internet or sits behind your own load balancer.
Delegated DNS-01
For a VPN-only, LAN-only, or otherwise firewalled server that can never complete an HTTP-01 challenge from the public internet. Switching an app to this mode gives you one CNAME to create at your own DNS provider, _acme-challenge.<apex> pointing at a label under acme.sproobo.com, and nothing else. Sproobo checks it 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 record.
Wildcard: one cert, many subdomains
For a fleet of subdomains under one apex (a multi-tenant staging pattern, say). Verify a single CNAME once against a standalone WildcardDomain and Sproobo issues one *.apex certificate. Every app you then create as a child of that domain shares the same cert automatically: zero additional DNS records and zero additional certificate issuance per subdomain. It's chosen at app-creation time; changing an existing app into or out of wildcard mode isn't supported from the dashboard yet.
External termination
For an app already sitting behind your own TLS-terminating load balancer or CDN (an AWS ALB, a Cloudflare proxy). Sproobo skips certificate issuance entirely and serves the app over plain HTTP on :80, with no HTTP→HTTPS redirect for that host, since your LB is the one that owns TLS and forwards plain HTTP downstream.
HTTP upgrades to HTTPS, automatically
Outside of the external-termination case above, every host gets Caddy's automatic HTTPS behavior platform-wide: plain HTTP requests get a redirect to HTTPS by default, with no per-app opt-in required. Switching an app to external mode is the one deliberate way to turn that off for a given host, since in that mode Sproobo isn't the one terminating TLS in the first place.
Alias domains: old names that redirect
Beyond the domains it serves, an app can carry alias domains: extra hostnames that don't serve anything themselves but 301-redirect every request to the app's canonical host, path and query preserved. Old brands, defensive registrations, and alternate TLDs land on the real site instead of a parked page. DNS on its own can't do this, because a redirect is an HTTP response rather than a record, so it has to come from the proxy on your server.
Each alias is its own group, under the same shape rule as the app's own domains: a single host, or an apex together with its www counterpart. Half-pairs stay rejected, and www.oldbrand.com redirects straight to the canonical host with no intermediate hop. Every alias host gets its own automatic HTTP-01 certificate, independent of the app's TLS mode, so an app on delegated DNS-01 or riding a wildcard cert still picks up ordinary certificates for its aliases. Up to ten alias groups per app, and an alias can't take a hostname another app on the same server already claims.
Aliases are not available in external termination mode: your own load balancer owns TLS for those hosts, so Sproobo isn't in a position to issue a certificate for them.
DNS is checked but never blocking. Point an alias's A/AAAA records at the same address as the canonical host; if they don't match yet, the alias still saves and the dashboard shows a warning chip against that row rather than refusing the change. A mis-pointed alias fails only its own certificate, since issuance is per hostname, and retries on its own. Your main domain is never affected.
Add them in the dashboard's Domains & TLS card, or from the CLI with sproobo apps set-domains --alias. Like any domain or TLS change, aliases are staged: the redirect route and the certificates go live on the app's next deploy, so redeploy right after saving.
The internal network: sproobo-int
Every app and service container attaches to one internal Docker network, sproobo-int. The proxy reaches an app's upstream, and an app reaches a bound service, purely by container DNS name on that network, no host ports are published for any of it. The only container published to 0.0.0.0 on the box is the proxy container itself, on :80/:443; everything else is unreachable from outside the box even if the host firewall were wide open.
The firewall that doesn't lie
The host-level firewall is ufw on Debian-family servers and firewalld on RHEL-family, but the part that actually enforces a rule against a Docker-published port is the DOCKER-USER iptables/nftables chain, since Docker's own NAT rules run ahead of the host firewall and would otherwise bypass it silently. Sproobo reconciles declared rules into DOCKER-USER as well, so a deny is actually effective rather than a rule that looks right in ufw status while the port stays reachable underneath.
The dashboard's firewall page reflects this directly: it merges what you've declared against what the agent's latest fact snapshot actually observed on the host, and surfaces any observed rule with no declared counterpart as drift, a rule the box picked up outside Sproobo.
Bootstrap checks who already holds :80/:443 before starting the Sproobo proxy. If something else already owns them (your own nginx, say), bootstrap skips starting sproobo-proxy and tells you to point your existing proxy at the sproobo-int network instead, rather than starting a second process to fight over the same port.
Next
- Read the full trust-boundary and firewall lockout-prevention model on Security model.
- See where TLS mode fits into creating and configuring an app on Apps & deploys.
- Walk the full enroll-to-deploy flow on Getting started.