Files
home-network-k3s-impl/platform/homepage
jakman85andClaude Opus 4.8 b6a48203bc fix(homepage): add required proxmox.yaml config to stop CrashLoopBackOff
Homepage v2.1.2 treats proxmox.yaml as a required config file (present in
the image skeleton dir /app/src/skeleton alongside services/settings/
bookmarks/widgets/docker/kubernetes/custom.*). On startup it copies a
default skeleton into /app/config for any required file that is missing.
The ConfigMap provided every skeleton file except proxmox.yaml, so the pod
tried to copyfile the proxmox skeleton into the read-only subPath-mounted
/app/config and crashed with EACCES -> CrashLoopBackOff -> Gateway "no
healthy upstream".

Provide an empty proxmox.yaml in the ConfigMap and mount it via subPath
like the other config files, so Homepage finds all required files and
never writes at runtime. Verified the full required set against the running
image's skeleton dir (9 files); proxmox.yaml was the only missing one.
Bumped checksum/config annotation to re-roll the pod.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-08-28 12:59:09 -05:00
..

platform/homepage

Homepage (gethomepage) — the apex landing dashboard at https://home.keithjackson.dev, aggregating links to the cluster's services.

  • Serves: a single pane of glass for the homelab (docs/09 apex UI).
  • Tier: non-gating post-platform Flux Kustomization (clusters/base/homepage.yaml, dependsOn: platform-config, wait: false) — mirrors headlamp / oauth2-proxy. A leaf UI must never gate the platform tier (DECISIONS-LOG "Headlamp gating stall").
  • Namespace: homepage — a PLATFORM namespace (no app-namespace=true), so the Kyverno app-scoped policies (default-deny gen, auth-mode, egress-class) do not apply; we ship an explicit default-deny + Cilium ingress policy as defense-in-depth.

What this component owns

Plain manifests (not a HelmRelease — the app is one stateless Deployment + a config ConfigMap):

File Purpose
namespace.yaml homepage ns, gateway-access=shared
configmap.yaml Homepage config (settings/services/bookmarks/widgets + empty docker/kubernetes + custom.css/js)
deployment.yaml ghcr.io/gethomepage/homepage (non-root, subPath config mounts, HOMEPAGE_ALLOWED_HOSTS)
service.yaml ClusterIP 80 -> 3000
networkpolicy.yaml default-deny (DNS-only egress) + Cilium Gateway-only ingress on 3000
httproute.yaml apex ingress on the Gateway https-apex listener

Apex nuances (why this isn't just another *.home route)

  1. TLS: the apex home.keithjackson.dev is already a SAN on the wildcard Certificate (platform/gateway/wildcard-certificate.yaml) — no new cert.
  2. Gateway listener: the wildcard listeners' hostname *.home.keithjackson.dev does not match the bare apex. This component's route binds a dedicated https-apex listener added to the shared Gateway (platform/gateway/gateway.yaml); http-apex-redirect covers :80.
  3. HOMEPAGE_ALLOWED_HOSTS: Homepage >= 1.0 returns 403 for any Host not in this list — set to home.keithjackson.dev + the pod IP (for kubelet probes).

Forward-auth — FOLLOW-UP (not yet enforced)

The HTTPRoute is annotated auth-mode: forward-auth (intended posture: oauth2-proxy -> Keycloak). The Gateway ext-authz attachment that actually enforces forward-auth does not exist yet — it is a Phase-6 WS-NET TODO (platform/oauth2-proxy is the authenticator; there is no CiliumEnvoyConfig / ext-authz wiring anywhere in the repo). Until that mechanism lands, Homepage — like every other forward-auth app (jackett, qbittorrent, pihole, radarr, sonarr) — is reachable unauthenticated. When the Gateway ext-authz pattern is built, attach it to this route (and the others) with allowed-groups: platform-admins. PM decision flagged in the deploy report.

Deliberately deferred (avoid scope creep)

  • Service-status widgets (Grafana/Plex/Sonarr/… API tiles) need per-service API-key secrets — not wired; tiles are simple links. Add as SOPS secrets + widgets.yaml later.
  • Kubernetes widget would need a read-only ServiceAccount + RBAC — skipped (kubernetes.yaml empty, automountServiceAccountToken: false).
  • Brand icons (selfh.st/dashboard-icons) need world:443 egress — we use bundled mdi-* icons so egress stays DNS-only.