explorer: read the chain that answers, and let the browsers reach the frontends
CI/CD / render (push) Failing after 0s

The four headline cards on explore.lux.network were zeros because the indexer
was pointed at luxd-rpc, and luxd-rpc fronts a StatefulSet whose five bootstrap
addresses are DigitalOcean droplets that no longer accept a connection. That
node never names a frontier, never creates the C-chain, and answers 404 for
every path under /v1/chain/c/rpc; the indexer read nothing from it and reported
`indexed: true` over an empty database. lux-chain answers eth_chainId 0x17871
and a height, so it is what cchain reads now. public_rpc gains the /rpc the
browser needs -- the path it named 404s, so every RPC-backed control on the
page had nothing to dial.

The five explore-fe deployments had no way in. Each host resolves to Cloudflare
and Cloudflare handed the request to an ingress with no router that matched,
which is the 404 they have all been serving. Each brand now names its own hosts,
carried over from the by-hand ingress-chains.yaml minus explore.spc.network,
which does not resolve.

The explorer pod's `explore` sidecar was explore-fe-lux a second time -- same
image, same digest, same brand -- published on a Service port no router named.
The indexer keeps the job only it does.

Co-authored-by: Hanzo AI <[email protected]>
This commit is contained in:
2026-09-08 22:33:11 -07:00
co-authored by Hanzo AI
parent 8ed9b670fb
commit 15dda3bedf
6 changed files with 107 additions and 124 deletions
+17
View File
@@ -92,3 +92,20 @@ configMaps:
NEXT_PUBLIC_APP_HOST: explore.lux.network
NEXT_PUBLIC_APP_PROTOCOL: https
NEXT_PUBLIC_IS_TESTNET: 'false'
# The hosts this brand answers on. Without this the Deployment runs and nothing
# can reach it: every explore.* host resolves to Cloudflare and Cloudflare hands
# the request to an ingress with no router that matches, which is the 404 these
# five have been serving. The set is the one k8s/lux-mainnet/ingress-chains.yaml
# carried by hand, minus explore.spc.network, which does not resolve.
routes:
- name: explore-hanzo
spec:
entryPoints: [websecure]
routes:
- match: Host(`explore-hanzo.lux.network`) || Host(`explore.hanzo.network`) || Host(`explore.hanzo.ai`)
kind: Rule
services:
- name: explore-fe-hanzo
port: 3000
tls: {}
+17
View File
@@ -96,3 +96,20 @@ configMaps:
NEXT_PUBLIC_APP_HOST: explore.lux.network
NEXT_PUBLIC_APP_PROTOCOL: https
NEXT_PUBLIC_IS_TESTNET: 'false'
# The hosts this brand answers on. Without this the Deployment runs and nothing
# can reach it: every explore.* host resolves to Cloudflare and Cloudflare hands
# the request to an ingress with no router that matches, which is the 404 these
# five have been serving. The set is the one k8s/lux-mainnet/ingress-chains.yaml
# carried by hand, minus explore.spc.network, which does not resolve.
routes:
- name: explore-lux
spec:
entryPoints: [websecure]
routes:
- match: Host(`explore.lux.network`) || Host(`explore.lux.cloud`)
kind: Rule
services:
- name: explore-fe-lux
port: 3000
tls: {}
+17
View File
@@ -87,3 +87,20 @@ configMaps:
NEXT_PUBLIC_APP_HOST: explore.lux.network
NEXT_PUBLIC_APP_PROTOCOL: https
NEXT_PUBLIC_IS_TESTNET: 'false'
# The hosts this brand answers on. Without this the Deployment runs and nothing
# can reach it: every explore.* host resolves to Cloudflare and Cloudflare hands
# the request to an ingress with no router that matches, which is the 404 these
# five have been serving. The set is the one k8s/lux-mainnet/ingress-chains.yaml
# carried by hand, minus explore.spc.network, which does not resolve.
routes:
- name: explore-pars
spec:
entryPoints: [websecure]
routes:
- match: Host(`explore-pars.lux.network`) || Host(`explore.pars.network`)
kind: Rule
services:
- name: explore-fe-pars
port: 3000
tls: {}
+17
View File
@@ -96,3 +96,20 @@ configMaps:
NEXT_PUBLIC_APP_HOST: explore.lux.network
NEXT_PUBLIC_APP_PROTOCOL: https
NEXT_PUBLIC_IS_TESTNET: 'false'
# The hosts this brand answers on. Without this the Deployment runs and nothing
# can reach it: every explore.* host resolves to Cloudflare and Cloudflare hands
# the request to an ingress with no router that matches, which is the 404 these
# five have been serving. The set is the one k8s/lux-mainnet/ingress-chains.yaml
# carried by hand, minus explore.spc.network, which does not resolve.
routes:
- name: explore-spc
spec:
entryPoints: [websecure]
routes:
- match: Host(`explore-spc.lux.network`)
kind: Rule
services:
- name: explore-fe-spc
port: 3000
tls: {}
+17
View File
@@ -92,3 +92,20 @@ configMaps:
NEXT_PUBLIC_APP_HOST: explore.lux.network
NEXT_PUBLIC_APP_PROTOCOL: https
NEXT_PUBLIC_IS_TESTNET: 'false'
# The hosts this brand answers on. Without this the Deployment runs and nothing
# can reach it: every explore.* host resolves to Cloudflare and Cloudflare hands
# the request to an ingress with no router that matches, which is the 404 these
# five have been serving. The set is the one k8s/lux-mainnet/ingress-chains.yaml
# carried by hand, minus explore.spc.network, which does not resolve.
routes:
- name: explore-zoo
spec:
entryPoints: [websecure]
routes:
- match: Host(`explore-zoo.lux.network`) || Host(`explore.zoo.network`) || Host(`explore.zoo.ngo`)
kind: Rule
services:
- name: explore-fe-zoo
port: 3000
tls: {}
+22 -124
View File
@@ -7,11 +7,11 @@ cd:
#
# ⚠️ The ports/service block below is deliberate and load-bearing. This workload
# needs THREE service ports over TWO container ports, with the container port
# named differently from every service port:
# needs TWO service ports over ONE container port, with the container port named
# differently from both:
#
# live Service http:80->8090, http-v2:8090->8090, ui:3000->3000
# live containers explorer[api:8090], explore[ui:3000]
# Service http:80->8090, http-v2:8090->8090
# container explorer[api:8090]
#
# One `ports[]` entry cannot express that — it yields ONE container port and ONE
# service port from a single name. Two primitives were added to charts/app for
@@ -28,8 +28,7 @@ cd:
# across lux-devnet/mainnet/testnet target explorer:8090 BY NUMBER — every
# api-explore.* host and most explore.* hosts, across lux.network,
# hanzo.ai, hanzo.network, pars.network, zoo.network and osage.network —
# and exchange-api dials explorer.<ns>.svc:8090 for SUBGRAPH_URL. Port 3000
# (the `explore` UI sidecar) goes with it.
# and exchange-api dials explorer.<ns>.svc:8090 for SUBGRAPH_URL.
# 2. The pods stop becoming Ready. The probes say `api`; renaming the
# container port leaves them pointing at a port that is not declared, and
# kubelet fails `strconv.Atoi: parsing "api"` — the fault that held
@@ -147,9 +146,6 @@ service:
- name: http-v2
port: 8090
targetPort: 8090
- name: ui
port: 3000
targetPort: 3000
volumes:
- configMap:
name: explorer-chains
@@ -162,119 +158,12 @@ volumes:
claimName: explorer-data
imagePullSecrets:
- name: ghcr-luxfi
sidecars:
- env:
- name: PORT
value: '3000'
- name: ENVS_PRESET
value: none
- name: SKIP_ENVS_VALIDATION
value: 'true'
- name: NEXT_TELEMETRY_DISABLED
value: '1'
- name: NEXT_PUBLIC_NETWORK_ID
value: '96369'
- name: NEXT_PUBLIC_NETWORK_NAME
value: Lux Network
- name: NEXT_PUBLIC_NETWORK_SHORT_NAME
value: LUX
- name: NEXT_PUBLIC_NETWORK_CURRENCY_NAME
value: LUX
- name: NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL
value: LUX
- name: NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS
value: '18'
- name: NEXT_PUBLIC_NETWORK_RPC_URL
value: https://api.lux.network/v1/chain/c
- name: NEXT_PUBLIC_NETWORK_LOGO
value: /logo.svg
- name: NEXT_PUBLIC_NETWORK_ICON
value: /icon.svg
- name: NEXT_PUBLIC_BRAND
value: lux
- name: NEXT_PUBLIC_IS_TESTNET
value: 'false'
- name: NEXT_PUBLIC_APP_HOST
value: explore.lux.network
- name: NEXT_PUBLIC_APP_PROTOCOL
value: https
- name: NEXT_PUBLIC_API_HOST
value: api-explore.lux.network
- name: NEXT_PUBLIC_API_PROTOCOL
value: https
- name: NEXT_PUBLIC_API_BASE_PATH
value: /v1/indexer/cchain
- name: NEXT_PUBLIC_API_WEBSOCKET_PROTOCOL
value: wss
- name: NEXT_PUBLIC_NETWORK_ORG_NAME
value: Lux Industries Inc.
- name: NEXT_PUBLIC_NETWORK_WEBSITE_URL
value: https://lux.network
- name: NEXT_PUBLIC_NETWORK_GITHUB_URL
value: https://github.com/luxfi
- name: NEXT_PUBLIC_NETWORK_TWITTER_URL
value: https://x.com/luxdefi
- name: NEXT_PUBLIC_NETWORK_DISCORD_URL
value: https://discord.gg/luxnetwork
- name: NEXT_PUBLIC_COLOR_THEME_DEFAULT
value: dark
- name: NEXT_PUBLIC_ACCOUNT_AUTH_PROVIDER
value: oidc
- name: NEXT_PUBLIC_OIDC_SERVER_URL
value: https://lux.id
- name: NEXT_PUBLIC_OIDC_CLIENT_ID
value: lux-explore-client-id
# v2.8.1-lux: the landing page stops spending its top on a feature that is off
# (the fee-split panel rendered a status tag, two zero counters and a promise of
# a chart while the split has never fired), and the Validators page counts EVERY
# network rather than this chain's share — Zoo and Hanzo run as L2s on the
# primary network and Pars and Osage as their own L1s, so "how many validators
# secure Lux" is a question about all of them. The landing page said 21 and the
# Validators page said 6; both were right and nothing said which was which.
image: ghcr.io/luxfi/explore:v2.8.1-lux
imagePullPolicy: IfNotPresent
livenessProbe:
failureThreshold: 5
httpGet:
path: /
port: ui
scheme: HTTP
initialDelaySeconds: 90
periodSeconds: 60
successThreshold: 1
timeoutSeconds: 10
name: explore
ports:
- containerPort: 3000
name: ui
protocol: TCP
readinessProbe:
failureThreshold: 6
httpGet:
path: /
port: ui
scheme: HTTP
initialDelaySeconds: 30
periodSeconds: 15
successThreshold: 1
timeoutSeconds: 10
resources:
limits:
cpu: '1'
memory: 2Gi
requests:
cpu: 100m
memory: 256Mi
startupProbe:
failureThreshold: 30
httpGet:
path: /
port: ui
scheme: HTTP
initialDelaySeconds: 15
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 10
# The UI is NOT here. `explore-fe-lux` runs this same image at this same digest
# and owns explore.lux.network; a copy of it beside the indexer was a second
# answer to one question, reachable from nothing -- the Service published ui:3000
# and no router named it. What is left in this pod is the thing only this pod
# does: index every chain in `chains.yaml` and serve the API the five frontends
# read.
fsGroup: 65532
strategy: Recreate
topologySpread:
@@ -336,7 +225,16 @@ configMaps:
name: Lux C-Chain
chain_id: 96369
type: evm
rpc: http://luxd-rpc.lux-mainnet.svc.cluster.local:9630/v1/chain/c/rpc
# `lux-chain` is where mainnet answers. luxd-rpc fronts the in-cluster
# StatefulSet, whose five bootstrap addresses are DigitalOcean droplets
# that no longer accept a TCP connection -- so it never names a frontier,
# never creates the C-chain, and every path under /v1/chain/c/rpc on it
# is 404. Measured 2026-09-09: lux-chain answers eth_chainId 0x17871 and
# eth_blockNumber; luxd-rpc answers `404 page not found`. An indexer
# pointed at a node that cannot serve reads zero blocks and reports
# `indexed: true` over an empty database, which is what the four
# headline cards were showing.
rpc: http://lux-chain.lux-mainnet.svc.cluster.local/v1/chain/c/rpc
# What the BROWSER is told to dial, and it is not optional. `rpc` above is
# the address this PROCESS dials -- a cluster-internal service name that
# resolves nowhere outside the mesh. Without public_rpc the binary's
@@ -344,7 +242,7 @@ configMaps:
# a .svc.cluster.local name, and hands the SPA "" -- so every RPC-backed
# control disappears from explore.lux.network. Live has carried this since
# before this file did; do not drop it back out.
public_rpc: https://api.lux.network/v1/chain/c
public_rpc: https://api.lux.network/v1/chain/c/rpc
coin: LUX
enabled: true
default: true