gateway: serve the dashboard at wild-pc.<domain>, 404 unrouted subdomains
The dashboard's deployment kept the pre-rename name `wildpc`, so it was published at wildpc.<domain> while everything else had moved to Wild PC naming. Rename the deployment and its program to `wild-pc` (the subdomain is the deployment name) and follow the `_DASHBOARD` constant in both the Caddyfile generator and doctor — that constant also drives the `:9000` redirect and doctor's `wildpc program build` hint, which is why the program is renamed alongside the deployment. Browsing the old name exposed a second problem: in acme mode every route lives inside one `*.<domain>` wildcard site, so an unrouted host still matches the site and completes its TLS handshake. Caddy then ran off the end of the block and returned a bare 200 with an empty body — a typo'd or renamed subdomain looked *up* in a browser while rendering nothing. Each wildcard site now ends with an unmatched `handle` that responds 404. The API subdomain is untouched: the dashboard derives its API origin by stripping the first label, so wild-pc.<domain> still resolves to wildpc-api.<domain>, and the WebSocket origin gate matches on gateway.domain rather than a hostname. Also seed the bootstrap dashboard deployment with the `requires: wildpc-api` block the live deployment already carried, so a fresh install declares the dependency.
This commit is contained in:
@@ -254,6 +254,23 @@ def _host_static_block(label: str, host: str, serve_dir: str, spa: bool) -> list
|
||||
]
|
||||
|
||||
|
||||
def _no_route_fallback() -> list[str]:
|
||||
"""The trailing catch-all for a wildcard site: an explicit 404 for a host that
|
||||
matched `*.<domain>` but no route.
|
||||
|
||||
Without it Caddy runs off the end of the site block and returns a bare
|
||||
`200 Content-Length: 0` — a typo'd or stale subdomain looks *up* to a browser
|
||||
(TLS negotiates, the request succeeds) while rendering nothing. A `handle`
|
||||
with no matcher is the fallback of its handle group, so it only fires when
|
||||
every `@host_*` matcher above missed."""
|
||||
return [
|
||||
" handle {",
|
||||
' respond "no wildpc route for this host" 404',
|
||||
" }",
|
||||
"",
|
||||
]
|
||||
|
||||
|
||||
def _public_site_block(host: str, kind: str, target: str, spa: bool = True) -> list[str]:
|
||||
"""A standalone Caddy site for a custom ``public_host`` (apex or another zone).
|
||||
|
||||
@@ -281,7 +298,7 @@ def _public_site_block(host: str, kind: str, target: str, spa: bool = True) -> l
|
||||
# Wild PC's own control plane: the dashboard frontend and the API it calls. These
|
||||
# names are the subdomains they're published at in acme mode, and the pair served
|
||||
# on the :<port> site in off mode (no domain → no subdomains).
|
||||
_DASHBOARD = "wildpc"
|
||||
_DASHBOARD = "wild-pc"
|
||||
_API = "wildpc-api"
|
||||
|
||||
|
||||
@@ -346,6 +363,7 @@ def generate_caddyfile_from_registry(
|
||||
lines += _host_remote_block(r.name or r.address, host, r.target)
|
||||
else:
|
||||
lines += _host_matcher_block(r.name or r.address, host, r.target)
|
||||
lines += _no_route_fallback()
|
||||
lines.append("}")
|
||||
lines.append("")
|
||||
# Public exposure: public deployments are also reachable by their public
|
||||
@@ -371,6 +389,7 @@ def generate_caddyfile_from_registry(
|
||||
lines += _host_remote_block(label, host, r.target)
|
||||
else:
|
||||
lines += _host_matcher_block(label, host, r.target)
|
||||
lines += _no_route_fallback()
|
||||
lines.append("}")
|
||||
lines.append("")
|
||||
for r in custom_pub:
|
||||
|
||||
Reference in New Issue
Block a user