Files
serverAppConfigs/docs/Infrastructure/Homepage.md
T
Frank cdae928f37 Homepage: settle design (grilling Q1-Q5), log open questions Q6-Q43, progress report
- Homepage.md: rewritten to the settled design (single site, user + /admin/
  pages, server-side status.json via a 3-min systemd-timer checker, terminal
  TUI theme). Added mermaid diagrams: site structure, status states, checker
  flow. Recorded the classification (user vs admin; *arr excluded; LLM admin;
  backends status-only) and the documented future shift to client-side probing.
- Homepage Design Grilling.md (new): the decision log — settled Q1-Q5 plus 38
  open questions (Q6-Q43) across 10 categories, each with a recommendation.
- docs/index.md: link the grilling page (satisfies the index-links-every-page test).
- report/homepage-grilling-2026-08-22.html: self-contained terminal-TUI progress
  report (settled decisions, verified stack baseline, overnight processing, work
  threads, the open questions, and how to continue).

Baseline recorded: Dankclaw fully up (10/10); the Dankserver media stack is down
(only Calibre-Web + the LLM are up; no .env on the target) — a separate thread.
No homepage code built yet; the design is pending the operator's answers to Q6-Q43.
2026-08-23 02:59:48 -07:00

5.9 KiB

Homepage

A password-protected web site on Dankclaw lists the services that are up, with a short description of each and a link to both the service and its usage documentation.

Served by: Caddy, file_server + basicauth — Docs: this page

Status — 2026-08-22: work in progress

The homepage is not finished. The static assets exist in shared/homepage/. They are not yet copied to /srv/homepage/ on the target. Caddy serves the basicauth challenge (HTTP 401) and the :80 redirect (HTTP 302). The page content is absent.

Do not treat the missing page as an outage. The Caddy site block and the redirect are live. Only the content and the deploy step remain.

Design decision — 2026-08-22

The live up/down check runs server-side. A checker on Dankclaw probes each backend and writes a same-origin status.json. The page fetches only that file and renders the badges. The browser never calls a backend directly. The checker runs as a systemd timer every 3 minutes.

The site has two pages. The root lists user-facing services only, with no host labels. An /admin/ subpage lists the admin and infrastructure services behind a separate password for the operator. Gitea is a user service. Hermes is an admin service. A "how it is built" page for visitors is optional and undecided.

The client-side probe design is blocked in this topology. The page origin is https://dankclaw.franksdank.cloud. The service URLs are http://<name>.franksdank.cloud. That is cross-origin, mixed content, and auth-gated (HTTP 401). All three fail a browser fetch.

Intended direction: move to client-side probing. Serve every service as a same-origin https path under dankclaw.franksdank.cloud. Add a health endpoint and CORS headers to each backend. Then the page probes each service directly. Keep this note until that shift is complete.

Structure

The site has three pages. The root page lists the user services. The /admin/ page lists the admin and infrastructure services. The /how/ page (optional) shows the architecture to visitors.

graph TD
    subgraph site["dankclaw.franksdank.cloud (Caddy)"]
        ROOT["/  user services<br/>(shared password)"]
        ADMIN["/admin/  admin services<br/>(operator password)"]
        HOW["/how/  how it is built<br/>(optional)"]
        STATUS["/status.json"]
    end
    TIMER["systemd timer<br/>every 3 minutes"]
    CHECKER["checker script<br/>probes each backend"]
    BACKENDS["backends on both hosts"]
    TIMER --> CHECKER
    CHECKER -->|writes| STATUS
    STATUS -->|polled| ROOT
    STATUS -->|polled| ADMIN
    CHECKER -->|probes| BACKENDS

Status model

Each service shows one of three states.

stateDiagram-v2
    [*] --> Up
    [*] --> Down
    [*] --> WIP
    Up --> Down: probe fails
    Down --> Up: probe succeeds
    WIP --> Up: work completes
  • Up — the probe reached the backend.
  • Down — the probe failed (connection refused or timeout).
  • WIP — a static override. The service is intentionally not finished. The checker does not probe it.

Checker

The checker runs on Dankclaw as a systemd timer. Every run probes each backend directly, then writes status.json. It probes the backend host:port, not the Caddy site. A Caddy 502 or 401 cannot tell up from down.

flowchart TD
    A[timer fires] --> B[read service config]
    B --> C{for each service}
    C -->|wip| D[mark WIP]
    C -->|probe| E[TCP connect to host:port]
    E -->|connected| F[mark Up]
    E -->|refused / timeout| G[mark Down]
    D --> H[write status.json]
    F --> H
    G --> H

Service classification

User services (root page): SearXNG, ComfyUI, OpenWebUI, Gitea, Calibre-Web, RomM, Copyparty, Plex, Jellyfin.

Admin services (/admin/): Hermes, Grafana, Prometheus, Loki, Caddy, dnsmasq, Gluetun, the LLM fleet, and the low-level backends (mariadb, redis, Postgres, node-exporter, alloy). The backends show status only. They get a link only where a UI is meaningful.

Excluded for now: the *arr stack (Radarr, Sonarr, Lidarr, Readarr, Prowlarr, qBittorrent). It is not started. It is a separate effort, possibly on a different host.

Layout

shared/homepage/
├── index.html        # root page (user services)
├── admin.html        # admin + infrastructure services
├── how.html          # optional architecture page
├── style.css         # terminal TUI theme
├── app.js            # loads status.json, renders the badges
├── services.json     # service config (user + admin)
└── fonts/            # Terminus (woff2) for @font-face

status.json is generated at runtime in /srv/homepage/. It is not committed.

Auth

Caddy wraps the site with HTTP basic auth. The root page uses the shared password. The /admin/ page uses a second, operator-only password. The hashes come from the host .env (git-ignored). Do not commit the hash or the password.

dankclaw.franksdank.cloud {
    @admin path /admin/*
    basicauth {
        dank {env.CADDY_BASICAUTH_HASH}
    }
    basicauth @admin {
        frank {env.CADDY_ADMIN_HASH}
    }
    root * /srv/homepage
    file_server
}

Service entry format

{
  "name": "SearXNG",
  "category": "user",
  "description": "Privacy-respecting metasearch engine.",
  "url": "http://search.franksdank.cloud",
  "docs": "/usage/searxng/",
  "probe": "127.0.0.1:8081",
  "wip": false,
  "showLink": true
}
  • category — user or admin. Selects the page.
  • url — the "Open" link (the Caddy site).
  • docs — the per-service usage page.
  • probe — the backend host:port the checker probes.
  • wip — when true, the badge shows WIP and the checker skips the probe.
  • showLink — when false, the card shows status only (no "Open" link).

See Also