Files
vh f6acb90d00 park(migration): promote the henge to permanent home on ana-docker
Operator-directed (Vuong 2026-08-13): migrated stonehenge-park off the nh3-docker
beta deployment to a permanent fixture on ana-docker (10.250.50.70) before the
v1.0.0 final cut. SQLite (park-data) migrated consistently (stop -> tar-copy ->
start; byte-identical). restic auto-covered by ana-docker's /var/lib/docker/volumes
source. Stable name park.phasefinal.com -> 10.250.50.70 (Cloudflare DNS-only) so
clients decouple from the host IP. Homepage tile 'The Henge' added. nh3-docker stack
left stopped as rollback pending park-dev cutover verification.
2026-08-13 14:28:42 -07:00
..

homepage

Canonical copies of the gethomepage.dev config for the fleet dashboard running on esh-docker-vm (10.0.50.45).

What lives here

File Purpose
settings.yaml Title, theme, background, quick-launch, group layout
services.yaml Manual entries — infra, BMCs, off-Docker endpoints, fleet hubs
bookmarks.yaml External links (UltraSeedbox, etc.)
widgets.yaml Top-of-page widgets (resource panel, search)
docker.yaml Per-host Docker socket providers for label-based auto-discovery
kubernetes.yaml, proxmox.yaml Empty / sample — kept so homepage doesn't warn on startup
custom.css, custom.js Placeholders
.env.example Template for widget secrets (Plex, Jellyfin, eventual Proxmox tokens)

The real .env (with Plex + Jellyfin keys) lives on esh-docker-vm next to the compose file and is gitignored.

Layout convention

settings.yaml drives the group layout across four tabs:

tab: Main
  Notes / News / Monitoring / Apps / Media / Games / UltraSeedbox
tab: AI              (the inference fleet, sorted by role)
  AI - Inference        LLM seats you call (gen, char-rp, char-rp-reasoning, summarizer)
  AI - Eval & Retrieval judges, reward, rerank, embed, image-quality
  AI - Gateways & Chat  routing gateway, control plane, chat frontends
  AI - Speech (TTS)     text-to-speech engines
  AI - Audio Tools      speech-to-text + audio dataset tooling
  AI - Image & Media    image/video generation + pipelines
  AI - Dormant          stopped stacks (rollback seats, retired auditions)
tab: Infrastructure
  Infra - ANA / NH3 / IRV / ESH   hardware + hypervisors + BMCs, per site
tab: Toolchain
  Service Networking / Toolchain  plumbing, rarely clicked

The AI tab replaced the old single flat AI Systems group (2026-07-14): a 20+ service list read as one endless column, so it was split by function. Group membership is the homepage.group=AI - <role> label on each compose file; a label change only takes effect when the container is recreated (docker compose up -d <svc>, or up --no-start <svc> to relabel a stopped stack without starting it).

  • Manual entries (this file) cover things without a Docker label: firewalls, switches, NAS web UIs, BMCs, hypervisors, and the cross-site hubs where direct IP:port URLs are stable.
  • Docker-labeled stacks auto-populate their group via the providers in docker.yaml. To drop a new service into a group, add homepage.group=<group> (plus .name, .icon, .description, .href) labels to its compose file and redeploy.

Placement rule (for new entries)

When deciding where a service lands, ask function first:

  1. Does it watch or back up the fleet? -> Monitoring
  2. Is it an inference / model service? -> the matching AI - <role> group (Inference / Eval & Retrieval / Gateways & Chat / Speech (TTS) / Audio Tools / Image & Media); a stopped-but-kept stack -> AI - Dormant
  3. Is it a user-facing app? -> Apps
  4. Is it media / games? -> Media or Games
  5. Is it a piece of hardware or a hypervisor? -> Infra - <site>
  6. Is it toolchain / plumbing (no human interaction on the golden path)? -> Service Networking

Site-specific sub-grouping is used for Infra - (device inventory maps to physical sites) and role-based sub-grouping for AI - (the fleet is large enough to warrant it). Other app groups are function-only.

Deploying changes

These files are the canonical source for the homepage config. The homepage compose file itself lives on esh-docker-vm (not yet tracked in this repo as a stack), so the usual scripts/deploy-stack.sh flow doesn't apply here yet.

Current workflow — push this directory onto the host:

rsync -av --delete \
  --exclude='.env' --exclude='.env.*' \
  --exclude='*.bak*' --exclude='logs/' \
  configs/homepage/ esh-docker-vm:/opt/docker/conf/homepage/

The real .env lives on esh-docker-vm next to the compose file and must not be overwritten (holds Plex/Jellyfin keys).

--delete footgun (learned 2026-07-20): the host keeps dated services.yaml.bak-* safety copies and a live logs/ dir that are not in this repo. A bare --delete rsync wipes both. The --exclude='*.bak*' and --exclude='logs/' above protect them. For a one-file tweak, skip --delete entirely and push the single file: rsync -av configs/homepage/services.yaml esh-docker-vm:/opt/docker/conf/homepage/services.yaml (back up the host copy first: ssh esh-docker-vm 'cp -a …/services.yaml …/services.yaml.bak-<date>-<what>').

The homepage container reloads most files on-change; if a new group in settings.yaml doesn't show up, docker compose restart on the host.

Follow-up: once the homepage compose file is pulled into stacks/homepage/compose.yaml, move these files to stacks/homepage/conf/ and drop this ad-hoc rsync in favor of scripts/deploy-stack.sh.

Secrets / env substitution

Any config can reference {{HOMEPAGE_VAR_NAME}} and homepage will substitute from the container env at render time. Current uses:

  • HOMEPAGE_VAR_PLEX_KEY (services.yaml -> Plex widget)
  • HOMEPAGE_VAR_JELLYFIN_KEY (services.yaml -> Jellyfin widget)

Keep these out of the tracked YAML; only .env.example ships the names.