explorer.testnet.lux.network (502), explorer.devnet.lux.network (404) and both
per-env bridge UIs (TLS handshake failure) are now 200 and render their own app,
verified through a real browser, not a status code.
ROOT CAUSE 1 — `certResolver: letsencrypt` is a no-op on this cluster.
The lux-system hanzo-ingress DaemonSet is started with no
--certificatesresolvers.* argument, so the named resolver does not exist and
every host whose only TLS source was a certResolver was served the self-signed
"INGRESS DEFAULT CERT":
openssl s_client -servername bridge.lux-dev.network
subject=CN=INGRESS DEFAULT CERT issuer=CN=INGRESS DEFAULT CERT
The four bridge hosts had a correct IngressRoute and a healthy 1/1 backend the
whole time — `curl -k` returned 200 and <title>Bridge</title> — so every probe
that skipped verification called them fine. cert-manager (ClusterIssuer
letsencrypt-prod, Cloudflare DNS-01) is the one mechanism here that issues real
certificates, and IngressRoute tls.secretName consumes it (precedent:
lux-ns/exchange-proxy). So: one Certificate per route, tls.secretName on the
route, certResolver deleted.
subject=CN=bridge.lux-test.network issuer=C=US, O=Let's Encrypt, CN=YR2
ROOT CAUSE 2 — explorer.{testnet,devnet}.lux.network were routed to the API.
Neither host appeared in any IngressRoute. Their only route was the legacy k8s
Ingress lux-explorer/explorer-{testnet,devnet} -> ExternalName
explorer-{testnet,devnet}-v2 -> explorer.lux-{testnet,devnet}.svc:8090 — the Go
indexer, which has no `/` handler. Devnet therefore 404'd with the app 1/1 and
"routing fine"; testnet 502'd because that Service additionally had zero
endpoints. Mainnet looked healthy only because a SECOND route,
lux-mainnet/lux-explorer-mainnet, claims explorer.lux.network for the frontend
and outranks the Ingress.
Both hosts are added to their network's existing IngressRoute — the same
frontend-plus-data-path shape mainnet already uses — and the two legacy
Ingresses are deleted. One host, one route, all three networks identical.
ROOT CAUSE 3 — lux-testnet explorer + explore-fe-lux were scaled to 0.
git declared replicas: 1 for explorer and said nothing at all about
explore-fe-lux, so nothing put either back. Scaled to 1; both reached Ready on
the first attempt with no restarts, so the zero was drift, not a crashloop
being papered over. explore-fe.yaml commits the frontend (and its
explore-env-lux ConfigMap) so this cannot silently recur.
Also certified the api-explore.* hosts on the same two routes: they answered
`curl -k .../health` 200 but failed verification for the same reason, and
leaving them out would have been a half-fix.
Rendered, not just 200 (Playwright, page inner text):
explorer.testnet.lux.network "LUX TESTNET Total blocks 981 Total
transactions 971 Wallet addresses 44"
explorer.devnet.lux.network "LUX DEVNET Total blocks 174 Total
transactions 173 Wallet addresses 10"
bridge.lux-test.network "Teleport / From / Source / Connect Wallet"
bridge.lux-dev.network same
No regression: bridge.lux.network, bridge-api/zoo/pars, explore.lux.network,
explorer.lux.network, faucet.lux-test.network all still 200 with valid TLS.
All five files are `kubectl diff -f` clean against live, and lux-testnet's
kustomization now tracks ingress.yaml (its exclusion note described a strip-csp
middleware the live object does not reference) plus the new explore-fe.yaml.
Known, NOT fixed here: the zoo/hanzo/pars devnet+testnet explorer routes carry
the same dead certResolver and their hosts still fail TLS; api-explore.lux-dev.network
is claimed by two routes and the losing one serves it.
Co-authored-by: Hanzo Dev <[email protected]>
157 lines
7.3 KiB
YAML
157 lines
7.3 KiB
YAML
# DEVNET brand explorer IngressRoutes (hanzo.ai/v1alpha1 — the canonical
|
|
# routing CRD used by the hanzoai/ingress (Traefik) controller; standard k8s
|
|
# Ingress is NOT how lux explorers route).
|
|
#
|
|
# Replaces the prior devnet routes that pointed the user-facing host at the
|
|
# unified Go explorer (`explorer:80`, which 404s on these hosts). Now each
|
|
# brand's frontend host -> explore-fe-<brand>:80 (the per-brand Next.js SPA),
|
|
# while api-explore.* + the SPA's data paths (/v1/*, /health, /envs.js, svgs)
|
|
# go to explorer:8090. Modeled byte-for-byte on the working
|
|
# lux-testnet/lux-explorer-zoo-testnet shape.
|
|
#
|
|
# Middlewares (cors-allow-all, mainpage-rewrite, blockscout-prefix-<brand>)
|
|
# already exist in lux-devnet.
|
|
#
|
|
# TLS: `certResolver: letsencrypt` names a resolver that DOES NOT EXIST — the
|
|
# lux-system hanzo-ingress DaemonSet carries no --certificatesresolvers.* args,
|
|
# so every host whose only TLS source is a certResolver is served the
|
|
# self-signed "INGRESS DEFAULT CERT" and fails verification. cert-manager
|
|
# (ClusterIssuer letsencrypt-prod, Cloudflare DNS-01) is the one mechanism on
|
|
# this cluster that issues real certificates; the lux route below now uses it
|
|
# via tls.secretName. The zoo/hanzo/pars routes further down still carry the
|
|
# dead certResolver and their hosts still fail TLS — same one-line fix, not
|
|
# done here only because those hosts were out of scope for this pass.
|
|
---
|
|
apiVersion: cert-manager.io/v1
|
|
kind: Certificate
|
|
metadata:
|
|
name: explorer-devnet-tls
|
|
namespace: lux-devnet
|
|
spec:
|
|
secretName: explorer-devnet-tls
|
|
issuerRef: { group: cert-manager.io, kind: ClusterIssuer, name: letsencrypt-prod }
|
|
# Every host this IngressRoute matches, including the api-explore.* set, which
|
|
# was reachable but uncertified for the same reason.
|
|
dnsNames:
|
|
- explore.lux-dev.network
|
|
- explorer.lux-dev.network
|
|
- explore-dev.lux.network
|
|
- explorer.devnet.lux.network
|
|
- api-explore.lux-dev.network
|
|
- api-explorer.lux-dev.network
|
|
- api-explore-dev.lux.network
|
|
---
|
|
apiVersion: hanzo.ai/v1alpha1
|
|
kind: IngressRoute
|
|
metadata:
|
|
name: lux-explorer-devnet
|
|
namespace: lux-devnet
|
|
labels: { app: lux-explorer, chain: lux, network: devnet }
|
|
spec:
|
|
entryPoints: [websecure]
|
|
tls: { secretName: explorer-devnet-tls }
|
|
routes:
|
|
# SPA data paths on the frontend host -> indexer/GraphQL backend
|
|
- kind: Rule
|
|
priority: 10000
|
|
match: (Host(`explore.lux-dev.network`) || Host(`explorer.lux-dev.network`) || Host(`explore-dev.lux.network`) || Host(`explorer.devnet.lux.network`)) && (PathPrefix(`/v1/`) || Path(`/health`) || Path(`/envs.js`) || Path(`/icon.svg`) || Path(`/logo.svg`) || Path(`/icon-lux.svg`) || Path(`/logo-lux.svg`))
|
|
middlewares: [{ name: cors-allow-all }]
|
|
services: [{ name: explorer, port: 8090 }]
|
|
# Frontend host -> per-brand SPA.
|
|
# explorer.devnet.lux.network is here because it is the host the world
|
|
# actually uses (it mirrors explorer.lux.network on mainnet, which the
|
|
# lux-mainnet/lux-explorer-mainnet IngressRoute serves the same way). Its
|
|
# only previous route was the legacy k8s Ingress lux-explorer/explorer-devnet
|
|
# -> ExternalName explorer-devnet-v2 -> explorer:8090, i.e. the Go API, which
|
|
# has no `/` handler: 404 with the app 1/1 and routing "fine". That Ingress
|
|
# is deleted; this route replaces it.
|
|
- kind: Rule
|
|
match: Host(`explore.lux-dev.network`) || Host(`explorer.lux-dev.network`) || Host(`explore-dev.lux.network`) || Host(`explorer.devnet.lux.network`)
|
|
services: [{ name: explore-fe-lux, port: 80 }]
|
|
# API host -> backend
|
|
- kind: Rule
|
|
match: Host(`api-explore.lux-dev.network`) || Host(`api-explorer.lux-dev.network`) || Host(`api-explore-dev.lux.network`)
|
|
middlewares:
|
|
- { name: mainpage-rewrite }
|
|
- { name: blockscout-prefix-cchain }
|
|
- { name: cors-allow-all }
|
|
services: [{ name: explorer, port: 8090 }]
|
|
---
|
|
apiVersion: hanzo.ai/v1alpha1
|
|
kind: IngressRoute
|
|
metadata:
|
|
name: lux-explorer-zoo-devnet
|
|
namespace: lux-devnet
|
|
labels: { app: lux-explorer, chain: zoo, network: devnet }
|
|
spec:
|
|
entryPoints: [websecure]
|
|
tls: { certResolver: letsencrypt }
|
|
routes:
|
|
- kind: Rule
|
|
priority: 10000
|
|
match: (Host(`explore-zoo-dev.lux.network`) || Host(`explore.zoo-dev.network`) || Host(`explorer.zoo-dev.network`)) && (PathPrefix(`/v1/`) || Path(`/health`) || Path(`/envs.js`) || Path(`/icon.svg`) || Path(`/logo.svg`) || Path(`/icon-zoo.svg`) || Path(`/logo-zoo.svg`))
|
|
middlewares: [{ name: cors-allow-all }]
|
|
services: [{ name: explorer, port: 8090 }]
|
|
- kind: Rule
|
|
match: Host(`explore-zoo-dev.lux.network`) || Host(`explore.zoo-dev.network`) || Host(`explorer.zoo-dev.network`)
|
|
services: [{ name: explore-fe-zoo, port: 80 }]
|
|
- kind: Rule
|
|
match: Host(`api-explore-zoo-dev.lux.network`) || Host(`api-explore.zoo-dev.network`) || Host(`api-explorer.zoo-dev.network`)
|
|
middlewares:
|
|
- { name: mainpage-rewrite }
|
|
- { name: blockscout-prefix-zoo }
|
|
- { name: cors-allow-all }
|
|
services: [{ name: explorer, port: 8090 }]
|
|
---
|
|
apiVersion: hanzo.ai/v1alpha1
|
|
kind: IngressRoute
|
|
metadata:
|
|
name: lux-explorer-hanzo-devnet
|
|
namespace: lux-devnet
|
|
labels: { app: lux-explorer, chain: hanzo, network: devnet }
|
|
spec:
|
|
entryPoints: [websecure]
|
|
tls: { certResolver: letsencrypt }
|
|
routes:
|
|
- kind: Rule
|
|
priority: 10000
|
|
match: (Host(`explore-hanzo-dev.lux.network`) || Host(`explore.hanzo-dev.network`) || Host(`explorer.hanzo-dev.network`)) && (PathPrefix(`/v1/`) || Path(`/health`) || Path(`/envs.js`) || Path(`/icon.svg`) || Path(`/logo.svg`))
|
|
middlewares: [{ name: cors-allow-all }]
|
|
services: [{ name: explorer, port: 8090 }]
|
|
- kind: Rule
|
|
match: Host(`explore-hanzo-dev.lux.network`) || Host(`explore.hanzo-dev.network`) || Host(`explorer.hanzo-dev.network`)
|
|
services: [{ name: explore-fe-hanzo, port: 80 }]
|
|
- kind: Rule
|
|
match: Host(`api-explore-hanzo-dev.lux.network`) || Host(`api-explore.hanzo-dev.network`) || Host(`api-explorer.hanzo-dev.network`)
|
|
middlewares:
|
|
- { name: mainpage-rewrite }
|
|
- { name: blockscout-prefix-hanzo }
|
|
- { name: cors-allow-all }
|
|
services: [{ name: explorer, port: 8090 }]
|
|
---
|
|
apiVersion: hanzo.ai/v1alpha1
|
|
kind: IngressRoute
|
|
metadata:
|
|
name: lux-explorer-pars-devnet
|
|
namespace: lux-devnet
|
|
labels: { app: lux-explorer, chain: pars, network: devnet }
|
|
spec:
|
|
entryPoints: [websecure]
|
|
tls: { certResolver: letsencrypt }
|
|
routes:
|
|
- kind: Rule
|
|
priority: 10000
|
|
match: (Host(`explore-pars-dev.lux.network`) || Host(`explore.pars-dev.network`) || Host(`explorer.pars-dev.network`)) && (PathPrefix(`/v1/`) || Path(`/health`) || Path(`/envs.js`) || Path(`/icon.svg`) || Path(`/logo.svg`))
|
|
middlewares: [{ name: cors-allow-all }]
|
|
services: [{ name: explorer, port: 8090 }]
|
|
- kind: Rule
|
|
match: Host(`explore-pars-dev.lux.network`) || Host(`explore.pars-dev.network`) || Host(`explorer.pars-dev.network`)
|
|
services: [{ name: explore-fe-pars, port: 80 }]
|
|
- kind: Rule
|
|
match: Host(`api-explore-pars-dev.lux.network`) || Host(`api-explore.pars-dev.network`) || Host(`api-explorer.pars-dev.network`)
|
|
middlewares:
|
|
- { name: mainpage-rewrite }
|
|
- { name: blockscout-prefix-pars }
|
|
- { name: cors-allow-all }
|
|
services: [{ name: explorer, port: 8090 }]
|