Files
home-network-k3s-impl/platform/homepage/deployment.yaml
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

105 lines
4.7 KiB
YAML

---
# Homepage (gethomepage) — the apex landing dashboard at https://home.keithjackson.dev. Plain
# manifests (not a HelmRelease): the whole app is a single stateless Deployment + a config ConfigMap,
# and hand-authoring the ConfigMap gives exact control over the service links without guessing a
# chart's values schema (same plain-manifest style as apps/vms/unifi). Rendered by its OWN non-gating
# post-platform Flux Kustomization (clusters/base/homepage.yaml, dependsOn platform-config,
# wait:false) — a leaf UI must never sit in the gating `platform` tier (DECISIONS-LOG: "Headlamp
# gating stall").
apiVersion: apps/v1
kind: Deployment
metadata:
name: homepage
namespace: homepage
labels:
app.kubernetes.io/name: homepage
spec:
replicas: 1
revisionHistoryLimit: 3
selector:
matchLabels:
app.kubernetes.io/name: homepage
template:
metadata:
labels:
app.kubernetes.io/name: homepage
annotations:
# Re-roll the pod when the config changes (ConfigMap subPath mounts do NOT hot-reload).
checksum/config: config-v2
spec:
automountServiceAccountToken: false
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
containers:
- name: homepage
# Renovate maintains this pin (ghcr.io/gethomepage/homepage). Config lives in /app/config.
image: ghcr.io/gethomepage/homepage:v2.1.2
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 3000
protocol: TCP
env:
# Referenced by HOMEPAGE_ALLOWED_HOSTS below so the in-pod liveness/readiness probes
# (which hit the pod IP, not the public host) are accepted by Homepage's host guard.
- name: MY_POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
# REQUIRED by Homepage >= 1.0 — requests whose Host header is not in this list get 403.
# The public apex host (served via the Gateway) + the pod IP (for kubelet probes).
- name: HOMEPAGE_ALLOWED_HOSTS
value: "home.keithjackson.dev,$(MY_POD_IP):3000"
resources:
requests:
cpu: 25m
memory: 128Mi
limits:
memory: 256Mi
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
# NOTE: readOnlyRootFilesystem intentionally left unset — Homepage (Next.js) writes a
# runtime build/cache under /app/.next at boot. Same deferred-hardening note as headlamp.
livenessProbe:
httpGet:
path: /api/healthcheck
port: http
initialDelaySeconds: 5
periodSeconds: 15
readinessProbe:
httpGet:
path: /api/healthcheck
port: http
initialDelaySeconds: 5
periodSeconds: 15
volumeMounts:
# Homepage expects each config file present; mount them read-only by subPath so the rest
# of /app/config stays writable (it writes ./logs there at runtime).
- { name: homepage-config, mountPath: /app/config/settings.yaml, subPath: settings.yaml, readOnly: true }
- { name: homepage-config, mountPath: /app/config/services.yaml, subPath: services.yaml, readOnly: true }
- { name: homepage-config, mountPath: /app/config/bookmarks.yaml, subPath: bookmarks.yaml, readOnly: true }
- { name: homepage-config, mountPath: /app/config/widgets.yaml, subPath: widgets.yaml, readOnly: true }
- { name: homepage-config, mountPath: /app/config/docker.yaml, subPath: docker.yaml, readOnly: true }
- { name: homepage-config, mountPath: /app/config/kubernetes.yaml, subPath: kubernetes.yaml, readOnly: true }
# proxmox.yaml is ALSO a required file in Homepage v2.1.2's skeleton — provide it so the
# app never copies a skeleton into the read-only /app/config (EACCES crash otherwise).
- { name: homepage-config, mountPath: /app/config/proxmox.yaml, subPath: proxmox.yaml, readOnly: true }
- { name: homepage-config, mountPath: /app/config/custom.css, subPath: custom.css, readOnly: true }
- { name: homepage-config, mountPath: /app/config/custom.js, subPath: custom.js, readOnly: true }
# Writable scratch for Homepage's runtime logs (it writes /app/config/logs).
- { name: logs, mountPath: /app/config/logs }
volumes:
- name: homepage-config
configMap:
name: homepage
- name: logs
emptyDir: {}