--- type: reference description: "Grafana visualizes the metrics that Prometheus collects from every service." tags: - infrastructure - grafana timestamp: 2026-09-11 --- # Grafana Grafana visualizes the metrics that Prometheus collects from every service. It runs on Dankclaw and is reachable at `grafana.franksdank.cloud` (via Caddy, behind the Anubis challenge + embedded-outpost gate; login happens inside Grafana via the Authentik OAuth2 button). **Host:** Dankclaw — **Hostname:** `grafana.franksdank.cloud` — **Port:** 3002 (internal) — **Docs:** https://grafana.com/docs ## Facts | Item | Value | |------|-------| | Image | `docker.io/grafana/grafana:latest` | | Published | `127.0.0.1:3002` → 3000, loopback only (see [[Observability]] → Exposure) | | Unit | `dankclaw/observability/quadlet/grafana.container` → `grafana.service` | | Data | `/opt/grafana/data` — `grafana.db`: accounts, sessions, anything created in the UI | | Provisioning mount | `/opt/grafana/provisioning` (read-only) — **empty as of 2026-09-11** | | Datasource | **none configured** — see the state note in [[Observability]] | ## Configuration Everything comes from the Quadlet unit. The Authentik OAuth2 client secret is the only credential, and systemd expands it from a per-service env file: ``` [Service] EnvironmentFile=/home/dank/Containers/grafana/env # systemd-side only [Container] Environment=GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET=${GRAFANA_OAUTH_CLIENT_SECRET} ``` `seed_grafana_env` in `scripts/deploy-remote.sh` seeds that file from `dankclaw/.env` with a single-variable filter and fails the deploy when the value is missing. The container receives the one expanded value, never the file. ## Datasource None is configured. Grafana cannot query anything yet; pointing it at `http://prometheus:9090` and `http://loki:3100` (by container name, on the `dankclaw_default` network) is outstanding work — see the state note in [[Observability]]. ## Healthcheck Grafana responds on `/api/health` with 200 and `"database":"ok"`. ## Gotchas - Change the default admin credentials at first boot (env or UI). - Dashboards provisioned as YAML survive container recreation; UI-created ones live in the data volume — back it up. - **Auth = OAuth2 relying-party, not auth_proxy.** The embedded outpost carries no provider token (`token=None`), so no identity header ever reaches Grafana; RP mode is topology-independent. The full verified contract (provider pk 9, client_id `grafana-21ca190cde75d60f`, global authorize/token/userinfo paths, Basic client auth, form-encoded token body, and the fork's userinfo-claims bug that leaves identity at the `sub` hash only) is in [[Authentik]] → "OAuth2 relying-party quirks". Consequences for Grafana: users auto-upsert as Viewer with `login = `; no email/groups/role claims reach Grafana until the evaluator bug is fixed — do not write role mappings that depend on those claims. The local admin account stays the only Admin. - **Never point this unit's `EnvironmentFile` at the repo-root `.env`.** That file is a gluetun env file and it carries `HOME=/root`; systemd imports it for the service, podman then looks for its configuration under `/root`, cannot read it, and the unit dies at start with `stat /root/.config: permission denied`. The unit reads `/home/dank/Containers/grafana/env`, which the deployer seeds with exactly one variable. ## See Also - [[Dankclaw Stack]] - [[Prometheus]] — the datasource - [[Observability]] — the whole stack