Files
serverAppConfigs/serverAppConfigs-docs/Infrastructure/Observability.md
T
Frank 701ab14f60 docs(observability): record the quadlet cutover, the exposure posture, and the unconfigured state
Rewrites the [[Observability]] umbrella page and the five component pages for
what is actually deployed: rootless Quadlet units instead of compose services,
the loopback-only publish posture (node-exporter's LAN binding explained), the
loki healthcheck living in its image because the image has no shell, and the
Home=/root trap that killed the first grafana start.

Adds the note that matters most to a reader: the stack is installed, healthy
and UNCONFIGURED. Grafana reports zero datasources and zero dashboards with an
empty provisioning directory; Prometheus has no rule files and no Alertmanager;
Loki is configured but has no reader; node-exporter runs its default
collectors. Alloy is the only configured piece. Metrics and logs are collected
and retained, and nothing is visualized or alerted on.

AGENTS.md's boot-persistence gap note is replaced by the resolution.
2026-09-11 16:10:27 -07:00

6.4 KiB


type: reference title: Observability on Dankclaw description: The Dankclaw observability stack — Prometheus, Grafana, Loki, Alloy and node-exporter: what runs, how it is deployed, how it is exposed, and what is still unconfigured. tags: [observability, prometheus, grafana, loki, alloy, node-exporter, quadlet, dankclaw] timestamp: 2026-09-11

Observability

The observability stack runs on Dankclaw: Prometheus for metrics, Loki for logs, Alloy as the shipper, Grafana for dashboards and node-exporter for host metrics. This is a small homelab — no Kubernetes.

Stack

graph LR
    S[Services] -->|/metrics| P[Prometheus]
    H[Host] -->|":9100"| P
    S -->|logs| A[Alloy]
    J[journald] --> A
    A --> L[Loki]
    P --> G[Grafana]
    L --> G
Component Role Image Published
Prometheus metrics collection prom/prometheus 127.0.0.1:9090
Grafana dashboards grafana/grafana 127.0.0.1:3002
Loki log storage & query franksdank/loki (local build) 127.0.0.1:3100
Alloy log shipping franksdank/alloy (local build) 127.0.0.1:12345
Node-Exporter host metrics prom/node-exporter 192.168.0.143:9100, host netns

Current state: installed, healthy, and UNCONFIGURED

Recorded 2026-09-11, on the day the stack moved to Quadlet units. Everything in the table above is deployed, healthy and boot-persistent. Almost nothing is wired up beyond the default install:

  • Grafana has zero datasources and zero dashboards. grafana.db reports 0 rows in data_source and 0 in dashboard; /opt/grafana/provisioning/ is empty, and the only account is the local admin. Nothing in the UI can query Prometheus or Loki yet. Datasources, dashboards, and provisioning-as-code are all outstanding work.
  • Prometheus has no alerting at all. /opt/prometheus/config/ contains prometheus.yml and nothing else — no rule files, no recording rules — and there is no Alertmanager anywhere in the stack. It scrapes and retains; it never notifies anyone.
  • Loki is configured but has no reader. Storage is filesystem with 30-day retention, auth_enabled: false, and the push path works; nothing queries it except manual Explore once Grafana is wired up.
  • node-exporter runs its default collector set — no collector tuning, no textfile collector for custom metrics.
  • Alloy is the one configured piece. It ships the host journal and podman container logs to Loki with job labels, and that pipeline is live.

The honest summary: metrics and logs are being collected and retained, and nothing is being visualized, correlated or alerted on. Any claim of "observability" beyond raw collection is aspirational until Grafana has datasources and there is at least one alerting path.

Deployment

All five are rootless Quadlet units on Dankclaw. The units live in dankclaw/observability/quadlet/<name>.container and install to ~/.config/containers/systemd/, generating <name>.service.

They left dankclaw/compose.yaml on 2026-09-11, after a reboot proved that compose-only containers do not come back on their own — the same gap that had already taken Caddy and Pi-hole down at earlier reboots.

./scripts/deploy.sh dankclaw --service loki        # or prometheus|grafana|alloy|node-exporter

deploy_observability in scripts/deploy-remote.sh installs the unit, restarts it and waits on its endpoint. Ordering lives in the units themselves (Grafana wants Prometheus, Alloy wants Loki), and SERVICE_ORDER in the planner puts each dependency first.

Every unit carries a healthcheck, so a wedged process reads unhealthy in podman ps rather than merely Up. See Loki for the one unit that cannot declare it inline.

Exposure

The rule is the same as for every other service: the only off-host path is a guarded vhost (<name>.franksdank.cloud → Anubis → Authentik embedded outpost). Two consequences are easy to get wrong:

  • Prometheus, Grafana, Loki and Alloy publish on 127.0.0.1 only. Caddy reaches them by container name over the dankclaw_default network, and the host-side homepage status timer probes loopback. Publishing on 0.0.0.0 — what the compose services did — put an unauthenticated metrics API (with the lifecycle endpoint enabled), dashboard, log store and log-ingest endpoint on every host interface, which is a bypass around the guard chain.
  • node-exporter is the one deliberate LAN listener. Prometheus runs in a container and cannot reach the host's loopback, so the unit binds exactly two addresses: 127.0.0.1:9100 for the homepage status probe and 192.168.0.143:9100 for Prometheus. It authenticates nothing, so it never gets a vhost.

Scrape surface

shared/prometheus/prometheus.yml is the source of truth (installed to /opt/prometheus/config/ on every deploy). It scrapes:

Job Target Notes
prometheus localhost:9090 itself
node-dankclaw, node-dankserver 192.168.0.143:9100, 192.168.0.235:9100 one node-exporter per host
gitea 192.168.0.143:3000 published LAN port (Gitea is on an isolated network)
grafana, loki grafana:3000, loki:3100 container names on dankclaw_default
comfyui comfyui:8188 UI probe, no native exporter
services 192.168.0.143:8081, :3005 SearXNG, OpenWebUI up/down probes

For services without a native exporter, use the Prometheus blackbox exporter in probe mode to assert up/down and HTTP latency. The homepage status timer probes the same endpoints from the host.

Log aggregation choice

Loki + Alloy is the lightweight Grafana-native option for a two-server homelab:

  • Alloy reads container logs from the host (journald socket + container log files) and pushes them to Loki. It replaces Promtail, which reached end-of-life on 2026-03-02.
  • Loki stores compressed logs with labels; queries run in Grafana's Explore.
  • No Elasticsearch memory cost, no Kubernetes required.

Alternatives considered and rejected: ELK (too heavy), Promtail (EOL), VictoriaLogs (newer, less documentation), plain journald (no centralized query).

See Also