loom.hypertheory-labs.dev serves a documentation site that exists only here, so the Gateway no longer matches production listener for listener. A route pinned to loom will not apply against production and it is the only one of which that is true. Recorded as a divergence with an explicit end state, like the last plain Ingress, rather than silently weakening the invariant the page opens with. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
4.1 KiB
Put something on the internet, the way production would
This cluster is staging for the production cluster, and that is the reason it exists rather than a use it happens to have.
Production's route manifests apply here unmodified. The only difference between the two Gateway definitions is the TLD —
.devhere,.comthere. Secret names are identical.
So the point of this page is what to leave out, not what to add.
Carry no hostname of your own
Routes pin to a listener by sectionName and inherit its hostname. That is
what makes them portable — a route that carries its own hostnames: stops
inheriting and stops working in the other environment.
Four listeners match production one for one: web (plain HTTP), and
websecure, theoria and notes over HTTPS. Pin to the one whose hostname you
want.
A fifth, loom, has no production counterpart. It serves a documentation
site that exists only here. So the one-for-one claim now holds of four
listeners and not of the Gateway — a route pinned to loom will not apply
against production, and that is the only listener of which that is true.
A divergence with an explicit end state, like the plain
Ingressbelow: either production grows aloomlistener, or this stays staging-only and production keeps four. Written down so it cannot become permanent by nobody remembering it was a choice.
One route is the exception and keeps its hostname: the HTTP-to-HTTPS
redirect, because the web listener declares no hostname at all — dropping it
there would widen the redirect from one host to every host.
The Gateway is not in the controller's namespace, on purpose
The Gateway lives in traefik; the controller runs in traefik-system.
Only the Gateway's namespace affects how parentRefs resolve, and
production names traefik — so production's refs resolve here verbatim.
Moving the controller would have meant an uninstall against a live service for
something no application can observe.
Plain HTTP does not answer for everything
Only one hostname redirects from HTTP. The others have no route on the web
listener and return 404 on plain HTTP. That mirrors production exactly, and
it is a consequence of the exception above rather than an oversight.
A typo attaches to nothing, silently
A route with a wrong sectionName binds to no listener and reports nothing.
kubectl get gateway traefik-gateway -n traefik \
-o jsonpath='{range .status.listeners[*]}{.name}: attached={.attachedRoutes}{"\n"}{end}'
attachedRoutesis the number that actually bound. Check it, not whether the route exists.
TLS is issued here and only terminated here
cert-manager owns every certificate, via DNS-01 against Cloudflare. Do not configure the proxy's own ACME resolver.
A certificate issues without the hostname resolving publicly, because the challenge is DNS-based. Iterate against the staging issuer — production rate limits are easy to hit during a rebuild.
A failed issuance backs off starting at one hour, and deleting the
CertificateRequest does not reset it — it looks hung and is not. Delete and
re-apply the Certificate.
The older path still works
One service is on a plain Ingress rather than the Gateway, and stays that
way until it is migrated. Production uses no Ingress at all; when that last one
moves, the environments match exactly. The divergence has an explicit end
state, so it cannot quietly become permanent.
Checking this is still true
Verified 2026-09-08.
kubectl get gatewayclass # ACCEPTED=True
kubectl get gateway -n traefik # PROGRAMMED=True, with an address
curl -sS -o /dev/null -w "%{http_code}\n" https://loom.hypertheory-labs.dev/
curl -sS -o /dev/null -w "%{http_code}\n" https://class.hypertheory-labs.dev/
# A hostname with no listener MUST 404. A 200 means a route was widened.
curl -skS -o /dev/null -w "%{http_code}\n" \
--resolve bogus.hypertheory-labs.dev:443:<any node IP> https://bogus.hypertheory-labs.dev/