Files
zeekayandHanzo Dev 941c100892 fix(maintenance): serve the page with hanzoai/static 0.4.1, not a nginx image that never existed
lux-mainnet/maintenance-page had been in ImagePullBackOff for 14 days
(94,026 failed pulls) on ghcr.io/hanzoai/web:1.27-alpine. That repository
does not exist -- GHCR answers NAME_UNKNOWN for hanzoai/web with a token
that reads hanzoai/gateway and hanzoai/iam fine, so it is genuinely gone,
not a scope problem. The mainnet maintenance page could not be raised.

This manifest was already wrong in the other direction: it declared
ghcr.io/hanzoai/static:0.1.0, a tag that has never been published either.

Repin to 0.4.1 -- the exact tag the healthy sibling runs (zen/zen-landing,
1/1 Ready) -- and adopt that deployment's proven shape. hanzoai/static
>=0.4.0 takes FLAGS, not env, and listens on :3000, so:

  - args --root=/srv --spa --port=3000
  - containerPort/probes 3000, Service targetPort 80 -> 3000
  - index.html mounted at /srv/index.html

The nginx `default.conf` key is dropped: hanzoai/static reads no nginx
conf, so mounting it only pretended to work. --spa is the try_files
equivalent. The /api/ -> 503 JSON stanza goes with it; nothing routes to
this Service (it has no Ingress on either cluster), so no caller loses it.

lux-explorer carries a byte-identical copy of this file that was never
applied; fixed the same way so the second copy is not a second landmine.

Verified on do-sfo3-lux-k8s: pulled in 1.553s, 1/1 Running, and the page
plus its SPA fallback both return 200 through the Service.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-26 15:46:04 -07:00

146 lines
3.7 KiB
YAML

# Maintenance page — served by hanzoai/static (never nginx; see the org rule).
# hanzoai/static >=0.4.0 is configured by FLAGS (--root/--port/--spa), not env,
# and listens on :3000. It reads no nginx conf, so the old `default.conf` key is
# gone: `--spa` is the try_files equivalent. Modelled on the proven
# hanzoai/universe infra/k8s/zen/landing.yaml (zen-landing, 1/1 on 0.4.1).
---
apiVersion: v1
kind: ConfigMap
metadata:
name: maintenance-page
namespace: lux-explorer
data:
index.html: |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Lux Explorer - Maintenance</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: linear-gradient(135deg, #0f0c29 0%, #302b63 50%, #24243e 100%);
color: #fff;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
.container {
text-align: center;
max-width: 600px;
padding: 2rem;
}
.logo {
font-size: 3rem;
font-weight: 700;
margin-bottom: 1rem;
background: linear-gradient(90deg, #f7931a, #e94560);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
h1 {
font-size: 1.5rem;
font-weight: 400;
margin-bottom: 1.5rem;
color: #ccc;
}
p {
font-size: 1.1rem;
line-height: 1.6;
color: #aaa;
}
.spinner {
margin: 2rem auto;
width: 40px;
height: 40px;
border: 3px solid rgba(255,255,255,0.1);
border-top-color: #f7931a;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
</style>
</head>
<body>
<div class="container">
<div class="logo">Lux Explorer</div>
<h1>Scheduled Maintenance</h1>
<div class="spinner"></div>
<p>Lux Explorer is upgrading to a new high-performance backend. Please check back shortly.</p>
</div>
</body>
</html>
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: maintenance-page
namespace: lux-explorer
labels:
app: maintenance-page
spec:
replicas: 1
selector:
matchLabels:
app: maintenance-page
template:
metadata:
labels:
app: maintenance-page
spec:
containers:
- name: static
image: ghcr.io/hanzoai/static:0.4.1
args: ["--root=/srv", "--spa", "--port=3000"]
ports:
- containerPort: 3000
name: http
resources:
requests:
cpu: 10m
memory: 16Mi
limits:
cpu: 50m
memory: 32Mi
volumeMounts:
- name: html
mountPath: /srv/index.html
subPath: index.html
readOnly: true
readinessProbe:
httpGet:
path: /
port: 3000
initialDelaySeconds: 2
periodSeconds: 5
livenessProbe:
httpGet:
path: /
port: 3000
initialDelaySeconds: 5
periodSeconds: 10
volumes:
- name: html
configMap:
name: maintenance-page
---
apiVersion: v1
kind: Service
metadata:
name: maintenance-page
namespace: lux-explorer
labels:
app: maintenance-page
spec:
type: ClusterIP
selector:
app: maintenance-page
ports:
- port: 80
targetPort: 3000
protocol: TCP
name: http