feat(homepage): bring the fleet dashboard under version control

Homepage on esh-docker-vm:5100 was the one stack whose config lived only on
the host, edited in place. Its version history was six hand-rolled
services.yaml.bak-* files. Now canonical here and deployed with
deploy-stack.sh like everything else; the .bak files are gone.

Corrections from the audit:
- ANA-Firewall described a 'Fortigate 81F'. It is a FortiGate-80F running
  FortiOS 7.2.10, verified live against the device.
- NH3-Ansible pointed at 10.100.50.42 as an 'Ansible control node'. That host
  is nh3-extdev, the manager/external-dev successor after nh3-ansible was
  retired. Renamed and re-described.
- Dropped the UltraSeedbox layout group: nothing provides it, so it only ever
  rendered empty.

Adds .env.example and a README documenting the two-path service model (docker
label discovery across five engines vs manual entries), the labels-only-apply-
on-recreate rule, and the foot-guns found: HOMEPAGE_ALLOWED_HOSTS matches
host AND port so a bare IP does not cover IP:port; :2375 is plaintext and
unauthenticated on all five engines; ping: cards can only be judged from the
dashboard host.

Verified after deploy via /api/services: 105 cards across 19 groups, both
corrections live, ana-docker discovery intact.
This commit is contained in:
vh
2026-08-17 21:10:37 -07:00
parent 4b6daadb16
commit c5beeac32d
12 changed files with 586 additions and 0 deletions
+60
View File
@@ -0,0 +1,60 @@
# homepage — the fleet dashboard
`ghcr.io/gethomepage/homepage` on **esh-docker-vm** (`10.0.50.45:5100`), behind
Traefik as `eshhome` / `eshhome.esteban.net`. Config is plain YAML — no
database, no UI-written state — which is why it belongs in this repo like any
other stack.
**Brought under version control 2026-08-17.** Before that it was edited in
place on the host, and had accumulated six hand-rolled `services.yaml.bak-*`
files as its only version history. Those were removed; git is the history now.
Edit here, then `scripts/deploy-stack.sh esh-docker-vm homepage`.
## How services get on the dashboard
Two paths, and mixing them is the classic failure:
1. **Docker label auto-discovery** — the default. A stack carries
`homepage.group=` / `homepage.name=` / `homepage.icon=` / `homepage.description=`
/ `homepage.href=` labels and appears automatically. `conf/docker.yaml`
wires **five** engines over plaintext `:2375`: esh-docker-vm, ana-docker,
nh3-docker, ana-ml2, irv-ml1.
2. **Manual entries in `conf/services.yaml`** — for anything that is not a
labelled container on one of those five hosts: hardware, BMCs, hypervisors,
printers, and user-level systemd services (The Booth, Voice Design Studio).
⚠ **Never list a labelled container manually — it renders twice.** The
comments in `services.yaml` mark which groups are auto-populated (AI ×7,
Service Networking, Monitoring). Respect them.
⚠ **Labels only apply on container recreate.** Changing `homepage.group=` on a
compose file and running `restart` does nothing; the container must be
recreated.
## Layout
`conf/settings.yaml` owns tabs, group order, and column counts — `services.yaml`
owns *what exists*, `settings.yaml` owns *where it sits*. Four tabs: Main, AI,
Infrastructure, Toolchain. A group listed in `layout:` with no members simply
renders empty, so a group can look "dead" when its provider host is unreachable
rather than when the group is wrong.
## Foot-guns found in the 2026-08-17 audit
- **`HOMEPAGE_ALLOWED_HOSTS` matches host *and port*.** The entry `10.0.50.45`
does **not** cover `http://10.0.50.45:5100/` — that combination was being
rejected with `Host validation failed` in the container log while the Traefik
hostnames worked fine. Every `host:port` the dashboard is reached by needs
its own entry. See `.env.example`.
- **`:2375` is plaintext and unauthenticated** on all five engines. Fine on a
trusted LAN, and unchanged by this commit, but it is real exposure: anything
that can reach those ports has full Docker control of that host. `docker.yaml`
carries a commented TLS example for when that stops being acceptable.
- **`ping:` cards can only be judged from esh-docker-vm.** Probing them from
another box gives false FAILs — ICMP is filtered across some site links. All
34 entries were verified reachable *from the dashboard host* on 2026-08-17.
## Open question
`ESH-FileBot` (`10.0.50.70`) is still described as "role TBC" — it responds to
ping, but nobody has written down what it does. Worth resolving or removing.