Add Dawarich stack

This commit is contained in:
2026-06-21 22:32:41 +02:00
parent 1de6ffc5ac
commit 725e3b0125
20 changed files with 1322 additions and 1 deletions
+2 -1
View File
@@ -6,7 +6,8 @@
!**/stack.env.example !**/stack.env.example
# Secrets and certificate material # Secrets and certificate material
**/secrets/ **/secrets/*
!**/secrets/*.example
**/letsencrypt/ **/letsencrypt/
**/acme.json **/acme.json
**/*.key **/*.key
+13
View File
@@ -0,0 +1,13 @@
COMPOSE_PROJECT_NAME=dawarich
TZ=Europe/Berlin
DAWARICH_HOST=dawarich.kaleschke.info
APPLICATION_HOSTS=dawarich.kaleschke.info
POSTGRES_USER=dawarich
POSTGRES_DB=dawarich_production
GRAFANA_DB_USER=dawarich_grafana_ro
METRICS_USERNAME=prometheus
BACKGROUND_PROCESSING_CONCURRENCY=5
RAILS_MAX_THREADS=10
+152
View File
@@ -0,0 +1,152 @@
# Dawarich Stack
Produktionsvorlage fuer Dawarich im KalliLab-Homelab mit GitOps ueber Gitea und Komodo.
## Gepruefter Stand
- Dawarich Release: `1.8.1` (GitHub latest am 2026-06-11)
- Docker Image: `freikin/dawarich:1.8.1`
- Hinweis: `freika/dawarich` existiert auf Docker Hub nicht; das offizielle Image aus dem Upstream-Compose ist `freikin/dawarich`.
- Dawarich Tracking-Endpoint fuer OwnTracks: `/api/v1/owntracks/points?api_key=<api-key>`
- Dawarich Prometheus ab 1.7.7: `dawarich_app:3000/metrics`; Port `9394` ist intern fuer Sidekiq-Metriken.
Quellen:
- https://github.com/Freika/dawarich/releases/tag/1.8.1
- https://dawarich.app/docs/getting-started/track-your-location/
- https://dawarich.app/docs/self-hosting/monitoring/prometheus/
## Dateien
```text
apps/dawarich/
|-- docker-compose.yml
|-- .env.example
|-- prometheus-scrape.snippet.yml
|-- homeassistant-dawarich.example.yaml
|-- grafana/
| |-- datasource-dawarich.yml
| `-- dashboard-dawarich.json
|-- postgres/initdb/20-grafana-readonly.sh
`-- secrets/*.txt.example
```
## Setup-Reihenfolge
1. Stack-Verzeichnis nach Komodo/Gitea uebernehmen: `apps/dawarich`.
2. `.env.example` als nicht versionierte Stack-`.env` oder Komodo Stack Environment anlegen.
3. Secret-Dateien auf dem Unraid-Host erstellen:
```bash
install -d -m 700 /mnt/user/appdata/secrets
openssl rand -base64 48 > /mnt/user/appdata/secrets/dawarich_postgres_password.txt
openssl rand -base64 48 | tr -dc 'A-Za-z0-9._~-' | head -c 48 > /mnt/user/appdata/secrets/dawarich_redis_password.txt
openssl rand -hex 64 > /mnt/user/appdata/secrets/dawarich_secret_key_base.txt
openssl rand -base64 48 > /mnt/user/appdata/secrets/dawarich_metrics_password.txt
openssl rand -base64 48 > /mnt/user/appdata/secrets/dawarich_grafana_ro_password.txt
chmod 600 /mnt/user/appdata/secrets/dawarich_*.txt
```
4. Bind-Volume-Zielpfade vor dem ersten Deploy anlegen:
```bash
install -d -m 750 \
/mnt/user/appdata/dawarich/postgres17 \
/mnt/user/appdata/dawarich/redis \
/mnt/user/appdata/dawarich/shared \
/mnt/user/appdata/dawarich/public \
/mnt/user/appdata/dawarich/watched \
/mnt/user/appdata/dawarich/storage
```
5. In Komodo als Compose-Stack deployen. `frontend_net` und `backend_net` muessen bereits existieren.
6. Ersten Login in Dawarich durchfuehren und den API-Key im Account-Bereich erzeugen.
7. Home Assistant `homeassistant-dawarich.example.yaml` in das Smart-Home-Fachrepo uebernehmen und `device_tracker.your_phone` ersetzen.
## Traefik und Authelia
Die UI liegt auf `https://dawarich.kaleschke.info` und nutzt `authelia@file,secure-headers@file`.
Die Tracking-API-Routen fuer OwnTracks, Overland und Traccar sind separat und priorisiert ohne Authelia geroutet, weil diese Clients per Dawarich-API-Key authentifizieren und keine Browser-ForwardAuth-Challenge verarbeiten koennen.
## Prometheus
`prometheus-scrape.snippet.yml` ist die dienstnahe Referenz. Produktiv ist der Job bereits in `monitoring/prometheus/prometheus.yml` eingetragen.
Der Monitoring-Stack ist dafuer bereits vorbereitet:
- `prometheus` haengt an `backend_net`, damit `dawarich_app` erreichbar ist.
- `/mnt/user/appdata/secrets/dawarich_metrics_password.txt` ist als Docker Secret eingebunden.
Nicht `dawarich_app:9394` scrapen: das ist nach aktueller Dawarich-Doku veraltet. Der Web-Service aggregiert App- und Sidekiq-Metriken unter `dawarich_app:3000/metrics`.
## Grafana
Der Read-only-User `dawarich_grafana_ro` wird beim ersten DB-Init durch `postgres/initdb/20-grafana-readonly.sh` angelegt.
Bei einer bereits initialisierten DB das Script einmal manuell im DB-Container ausfuehren:
```bash
docker exec dawarich_db /docker-entrypoint-initdb.d/20-grafana-readonly.sh
```
Die produktive Provisionierung ist bereits in den vorhandenen Monitoring-Stack integriert:
- Datasource: `monitoring/grafana/provisioning/datasources/dawarich.yml`
- Dashboard: `monitoring/grafana/dashboards/dawarich.json`
- Grafana haengt an `backend_net`, damit `dawarich_db:5432` erreichbar ist.
- `DAWARICH_GRAFANA_RO_PASSWORD` wird beim Grafana-Start aus `/mnt/user/appdata/secrets/dawarich_grafana_ro_password.txt` exportiert.
## Home Assistant
Dawarich akzeptiert OwnTracks-kompatible Location-Punkte per:
```text
https://dawarich.kaleschke.info/api/v1/owntracks/points?api_key=<dawarich-api-key>
```
`homeassistant-dawarich.example.yaml` enthaelt:
- `rest_command.dawarich_push_owntracks`
- Automation fuer `device_tracker`-State-Changes
- API-Key aus HA `secrets.yaml` als `dawarich_api_key`
Alternativ existiert eine HACS-Integration `dawarich-home-assistant`; die YAML-Variante hier bleibt absichtlich transparent und GitOps-lesbar.
## Backup mit Borg
Borg-relevante Daten liegen unter:
```text
/mnt/user/appdata/dawarich/postgres17
/mnt/user/appdata/dawarich/redis
/mnt/user/appdata/dawarich/shared
/mnt/user/appdata/dawarich/public
/mnt/user/appdata/dawarich/watched
/mnt/user/appdata/dawarich/storage
/mnt/user/appdata/secrets/dawarich_*.txt
```
Primaerer Restore-Weg fuer die DB sollte ein logischer Dump plus Appdaten sein. Raw-Postgres-Verzeichnisse sind nur fuer gleiches Major/PostGIS-Image und sauberen Shutdown geeignet.
Empfohlener Dump vor Borg:
```bash
docker exec dawarich_db pg_dump -U dawarich -d dawarich_production -Fc > /mnt/user/backups/borg/dumps/latest/dawarich.dump
```
## Updates
- Kein `latest` verwenden.
- Vor jedem Update Release Notes lesen, besonders bei Dawarich und PostGIS.
- Dawarich App und Sidekiq muessen immer dasselbe Image-Tag nutzen.
- PostGIS-Major-/Minor-Wechsel getrennt planen und vorher Dump plus Restore-Probe erstellen.
- Image-Digests nach Review bewusst aktualisieren.
## Rollback
1. Komodo Stack stoppen.
2. Vorherigen Git-Commit mit altem Image-Tag/Digest deployen.
3. Falls nur App-Code gewechselt wurde: Stack starten und Healthchecks pruefen.
4. Falls DB-Migrationen gelaufen sind: DB aus `dawarich.dump` in einen frischen PostGIS-17-Container restoren; kein blindes Zurueckkopieren eines Live-Postgres-Verzeichnisses.
5. Dawarich UI, `/api/v1/health`, Prometheus-Scrape und HA-Push testen.
+271
View File
@@ -0,0 +1,271 @@
name: dawarich
x-dawarich-image: &dawarich_image freikin/dawarich:1.8.1@sha256:7c70f2169e848ed77ae1cec01dd10ec4a73a70a785d4e4d248db1735c0bc25ed
services:
dawarich_db:
image: postgis/postgis:17-3.5-alpine@sha256:fc07e7a034e013d50ada575673b798ca6277e000b8364e39e217f612d94bd9a5
container_name: dawarich_db
restart: unless-stopped
shm_size: 1G
environment:
TZ: ${TZ}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_PASSWORD_FILE: /run/secrets/dawarich_postgres_password
GRAFANA_DB_USER: ${GRAFANA_DB_USER}
PGDATA: /var/lib/postgresql/data
volumes:
- dawarich_db_data:/var/lib/postgresql/data
- dawarich_shared:/var/shared
- ./postgres/initdb:/docker-entrypoint-initdb.d:ro
networks:
- backend_net
secrets:
- dawarich_postgres_password
- dawarich_grafana_ro_password
expose:
- "5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U \"$${POSTGRES_USER}\" -d \"$${POSTGRES_DB}\""]
interval: 10s
timeout: 10s
retries: 5
start_period: 30s
security_opt:
- no-new-privileges:true
dawarich_redis:
image: redis:7-alpine@sha256:6ab0b6e7381779332f97b8ca76193e45b0756f38d4c0dcda72dbb3c32061ab99
container_name: dawarich_redis
restart: unless-stopped
command:
- /bin/sh
- -lc
- |
exec redis-server \
--save 900 1 \
--save 300 10 \
--appendonly no \
--requirepass "$$(cat /run/secrets/dawarich_redis_password)"
volumes:
- dawarich_redis_data:/data
networks:
- backend_net
secrets:
- dawarich_redis_password
expose:
- "6379"
healthcheck:
test: ["CMD-SHELL", "redis-cli -a \"$$(cat /run/secrets/dawarich_redis_password)\" --raw incr ping >/dev/null"]
interval: 10s
timeout: 10s
retries: 5
start_period: 30s
security_opt:
- no-new-privileges:true
dawarich_app:
image: *dawarich_image
container_name: dawarich_app
restart: unless-stopped
stdin_open: true
tty: true
entrypoint:
- /bin/sh
- -lc
command:
- |
export DATABASE_PASSWORD="$$(cat /run/secrets/dawarich_postgres_password)"
export REDIS_URL="redis://:$$(cat /run/secrets/dawarich_redis_password)@dawarich_redis:6379/0"
export SECRET_KEY_BASE="$$(cat /run/secrets/dawarich_secret_key_base)"
export METRICS_PASSWORD="$$(cat /run/secrets/dawarich_metrics_password)"
exec web-entrypoint.sh bin/rails server -p 3000 -b ::
environment:
TZ: ${TZ}
RAILS_ENV: production
DATABASE_HOST: dawarich_db
DATABASE_PORT: "5432"
DATABASE_USERNAME: ${POSTGRES_USER}
DATABASE_NAME: ${POSTGRES_DB}
APPLICATION_HOSTS: ${APPLICATION_HOSTS}
APPLICATION_PROTOCOL: https
TIME_ZONE: ${TZ}
SELF_HOSTED: "true"
STORE_GEODATA: "true"
RAILS_LOG_TO_STDOUT: "true"
PROMETHEUS_EXPORTER_ENABLED: "true"
METRICS_USERNAME: ${METRICS_USERNAME}
SIDEKIQ_METRICS_URL: http://dawarich_sidekiq:9394/metrics
BACKGROUND_PROCESSING_CONCURRENCY: ${BACKGROUND_PROCESSING_CONCURRENCY}
RAILS_MAX_THREADS: ${RAILS_MAX_THREADS}
volumes:
- dawarich_public:/var/app/public
- dawarich_watched:/var/app/tmp/imports/watched
- dawarich_storage:/var/app/storage
- dawarich_db_data:/dawarich_db_data:ro
networks:
- frontend_net
- backend_net
secrets:
- dawarich_postgres_password
- dawarich_redis_password
- dawarich_secret_key_base
- dawarich_metrics_password
expose:
- "3000"
healthcheck:
test: ["CMD-SHELL", "wget -qO - http://127.0.0.1:3000/api/v1/health | grep -q '\"status\"[[:space:]]*:[[:space:]]*\"ok\"'"]
interval: 10s
timeout: 10s
retries: 30
start_period: 30s
depends_on:
dawarich_db:
condition: service_healthy
dawarich_redis:
condition: service_healthy
security_opt:
- no-new-privileges:true
labels:
- traefik.enable=true
- traefik.docker.network=frontend_net
# Public API-key endpoints for mobile apps and Home Assistant pushes.
- traefik.http.routers.dawarich-api.rule=Host(`${DAWARICH_HOST}`) && (Path(`/api/v1/owntracks/points`) || Path(`/api/v1/overland/batches`) || Path(`/api/v1/traccar/points`))
- traefik.http.routers.dawarich-api.entrypoints=websecure
- traefik.http.routers.dawarich-api.tls=true
- traefik.http.routers.dawarich-api.tls.certresolver=le
- traefik.http.routers.dawarich-api.priority=100
- traefik.http.routers.dawarich-api.middlewares=secure-headers@file
- traefik.http.routers.dawarich-api.service=dawarich
# UI and all other routes require Authelia ForwardAuth.
- traefik.http.routers.dawarich.rule=Host(`${DAWARICH_HOST}`)
- traefik.http.routers.dawarich.entrypoints=websecure
- traefik.http.routers.dawarich.tls=true
- traefik.http.routers.dawarich.tls.certresolver=le
- traefik.http.routers.dawarich.priority=10
- traefik.http.routers.dawarich.middlewares=authelia@file,secure-headers@file
- traefik.http.routers.dawarich.service=dawarich
- traefik.http.services.dawarich.loadbalancer.server.port=3000
dawarich_sidekiq:
image: *dawarich_image
container_name: dawarich_sidekiq
restart: unless-stopped
stdin_open: true
tty: true
entrypoint:
- /bin/sh
- -lc
command:
- |
export DATABASE_PASSWORD="$$(cat /run/secrets/dawarich_postgres_password)"
export REDIS_URL="redis://:$$(cat /run/secrets/dawarich_redis_password)@dawarich_redis:6379/0"
export SECRET_KEY_BASE="$$(cat /run/secrets/dawarich_secret_key_base)"
export METRICS_PASSWORD="$$(cat /run/secrets/dawarich_metrics_password)"
exec sidekiq-entrypoint.sh sidekiq
environment:
TZ: ${TZ}
RAILS_ENV: production
DATABASE_HOST: dawarich_db
DATABASE_PORT: "5432"
DATABASE_USERNAME: ${POSTGRES_USER}
DATABASE_NAME: ${POSTGRES_DB}
APPLICATION_HOSTS: ${APPLICATION_HOSTS}
APPLICATION_PROTOCOL: https
TIME_ZONE: ${TZ}
SELF_HOSTED: "true"
STORE_GEODATA: "true"
RAILS_LOG_TO_STDOUT: "true"
PROMETHEUS_EXPORTER_ENABLED: "true"
PROMETHEUS_EXPORTER_PORT: "9394"
METRICS_USERNAME: ${METRICS_USERNAME}
BACKGROUND_PROCESSING_CONCURRENCY: ${BACKGROUND_PROCESSING_CONCURRENCY}
RAILS_MAX_THREADS: ${RAILS_MAX_THREADS}
volumes:
- dawarich_public:/var/app/public
- dawarich_watched:/var/app/tmp/imports/watched
- dawarich_storage:/var/app/storage
networks:
- frontend_net
- backend_net
secrets:
- dawarich_postgres_password
- dawarich_redis_password
- dawarich_secret_key_base
- dawarich_metrics_password
expose:
- "9394"
healthcheck:
test: ["CMD-SHELL", "pgrep -f sidekiq >/dev/null"]
interval: 10s
timeout: 10s
retries: 30
start_period: 30s
depends_on:
dawarich_db:
condition: service_healthy
dawarich_redis:
condition: service_healthy
dawarich_app:
condition: service_healthy
security_opt:
- no-new-privileges:true
networks:
frontend_net:
external: true
backend_net:
external: true
volumes:
dawarich_db_data:
driver: local
driver_opts:
type: none
o: bind
device: /mnt/user/appdata/dawarich/postgres17
dawarich_redis_data:
driver: local
driver_opts:
type: none
o: bind
device: /mnt/user/appdata/dawarich/redis
dawarich_shared:
driver: local
driver_opts:
type: none
o: bind
device: /mnt/user/appdata/dawarich/shared
dawarich_public:
driver: local
driver_opts:
type: none
o: bind
device: /mnt/user/appdata/dawarich/public
dawarich_watched:
driver: local
driver_opts:
type: none
o: bind
device: /mnt/user/appdata/dawarich/watched
dawarich_storage:
driver: local
driver_opts:
type: none
o: bind
device: /mnt/user/appdata/dawarich/storage
secrets:
dawarich_postgres_password:
file: /mnt/user/appdata/secrets/dawarich_postgres_password.txt
dawarich_redis_password:
file: /mnt/user/appdata/secrets/dawarich_redis_password.txt
dawarich_secret_key_base:
file: /mnt/user/appdata/secrets/dawarich_secret_key_base.txt
dawarich_metrics_password:
file: /mnt/user/appdata/secrets/dawarich_metrics_password.txt
dawarich_grafana_ro_password:
file: /mnt/user/appdata/secrets/dawarich_grafana_ro_password.txt
@@ -0,0 +1,355 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "grafana",
"uid": "-- Grafana --"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"editable": false,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": null,
"links": [],
"panels": [
{
"datasource": {
"type": "postgres",
"uid": "dawarich-postgres"
},
"fieldConfig": {
"defaults": {
"custom": {
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
},
"unit": "none"
},
"overrides": []
},
"gridPos": {
"h": 16,
"w": 16,
"x": 0,
"y": 0
},
"id": 1,
"options": {
"basemap": {
"config": {},
"name": "Layer 0",
"type": "default"
},
"controls": {
"mouseWheelZoom": true,
"showAttribution": true,
"showDebug": false,
"showMeasure": false,
"showScale": true,
"showZoom": true
},
"layers": [
{
"config": {
"showLegend": true,
"style": {
"color": {
"fixed": "dark-green"
},
"opacity": 0.55,
"rotation": {
"fixed": 0,
"max": 360,
"min": -360,
"mode": "mod"
},
"size": {
"fixed": 4,
"max": 15,
"min": 2
},
"symbol": {
"fixed": "img/icons/marker/circle.svg",
"mode": "fixed"
},
"textConfig": {
"fontSize": 12,
"offsetX": 0,
"offsetY": 0,
"textAlign": "center",
"textBaseline": "middle"
}
}
},
"location": {
"latitude": "latitude",
"longitude": "longitude",
"mode": "coords"
},
"name": "Location points",
"tooltip": true,
"type": "markers"
}
],
"tooltip": {
"mode": "details"
},
"view": {
"allLayers": true,
"id": "fit",
"lat": 51,
"lon": 10,
"zoom": 5
}
},
"pluginVersion": "13.0.2",
"targets": [
{
"datasource": {
"type": "postgres",
"uid": "dawarich-postgres"
},
"editorMode": "code",
"format": "table",
"rawQuery": true,
"rawSql": "SELECT\n to_timestamp(timestamp) AS \"time\",\n ST_Y(lonlat::geometry) AS latitude,\n ST_X(lonlat::geometry) AS longitude,\n accuracy,\n tracker_id\nFROM points\nWHERE $__unixEpochFilter(timestamp)\n AND lonlat IS NOT NULL\nORDER BY timestamp DESC\nLIMIT 20000;",
"refId": "A"
}
],
"title": "Location Points",
"type": "geomap"
},
{
"datasource": {
"type": "postgres",
"uid": "dawarich-postgres"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "bars",
"fillOpacity": 70,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
},
"unit": "km"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 8,
"x": 16,
"y": 0
},
"id": 2,
"options": {
"legend": {
"calcs": [
"sum"
],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"hideZeros": false,
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "13.0.2",
"targets": [
{
"datasource": {
"type": "postgres",
"uid": "dawarich-postgres"
},
"editorMode": "code",
"format": "time_series",
"rawQuery": true,
"rawSql": "SELECT\n make_date(year, month, 1)::timestamp AS \"time\",\n round((distance::numeric / 1000.0), 2) AS \"km\"\nFROM stats\nWHERE make_date(year, month, 1)::timestamp BETWEEN $__timeFrom() AND $__timeTo()\nORDER BY 1;",
"refId": "A"
}
],
"title": "Kilometers per Month",
"type": "timeseries"
},
{
"datasource": {
"type": "postgres",
"uid": "dawarich-postgres"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "bars",
"fillOpacity": 70,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
},
"unit": "short"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 8,
"x": 16,
"y": 8
},
"id": 3,
"options": {
"legend": {
"calcs": [
"sum"
],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"hideZeros": false,
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "13.0.2",
"targets": [
{
"datasource": {
"type": "postgres",
"uid": "dawarich-postgres"
},
"editorMode": "code",
"format": "time_series",
"rawQuery": true,
"rawSql": "SELECT\n date_trunc('day', to_timestamp(timestamp)) AS \"time\",\n count(*) AS \"points\"\nFROM points\nWHERE $__unixEpochFilter(timestamp)\nGROUP BY 1\nORDER BY 1;",
"refId": "A"
}
],
"title": "Points per Day",
"type": "timeseries"
}
],
"preload": false,
"refresh": "5m",
"schemaVersion": 41,
"tags": [
"dawarich",
"location"
],
"templating": {
"list": []
},
"time": {
"from": "now-30d",
"to": "now"
},
"timepicker": {},
"timezone": "browser",
"title": "Dawarich",
"uid": "dawarich",
"version": 1,
"weekStart": ""
}
@@ -0,0 +1,17 @@
apiVersion: 1
datasources:
- name: Dawarich PostgreSQL
uid: dawarich-postgres
type: postgres
access: proxy
url: dawarich_db:5432
database: dawarich_production
user: dawarich_grafana_ro
editable: false
jsonData:
sslmode: disable
postgresVersion: 1700
timescaledb: false
secureJsonData:
password: $DAWARICH_GRAFANA_RO_PASSWORD
@@ -0,0 +1,47 @@
# Add `dawarich_api_key` to Home Assistant `secrets.yaml`.
# The endpoint is the current OwnTracks-compatible Dawarich endpoint:
# https://<host>/api/v1/owntracks/points?api_key=<api-key>
rest_command:
dawarich_push_owntracks:
url: "https://dawarich.kaleschke.info/api/v1/owntracks/points?api_key={{ api_key }}"
method: POST
content_type: "application/json"
payload: >-
{
"_type": "location",
"lat": {{ latitude }},
"lon": {{ longitude }},
"tst": {{ timestamp }},
"acc": {{ accuracy | default(0) }},
"alt": {{ altitude | default(0) }},
"batt": {{ battery | default(0) }},
"tid": "{{ tracker_id[:2] }}"
}
automation:
- id: dawarich_push_device_tracker_location
alias: Dawarich - push device tracker location
mode: queued
max: 20
trigger:
- platform: state
entity_id:
- device_tracker.your_phone
condition:
- condition: template
value_template: >-
{{ trigger.to_state is not none
and state_attr(trigger.entity_id, 'latitude') is number
and state_attr(trigger.entity_id, 'longitude') is number }}
action:
- service: rest_command.dawarich_push_owntracks
data:
api_key: !secret dawarich_api_key
tracker_id: "{{ trigger.entity_id.split('.')[1] }}"
latitude: "{{ state_attr(trigger.entity_id, 'latitude') }}"
longitude: "{{ state_attr(trigger.entity_id, 'longitude') }}"
accuracy: "{{ state_attr(trigger.entity_id, 'gps_accuracy') | default(0, true) }}"
altitude: "{{ state_attr(trigger.entity_id, 'altitude') | default(0, true) }}"
battery: "{{ state_attr(trigger.entity_id, 'battery_level') | default(0, true) }}"
timestamp: "{{ as_timestamp(trigger.to_state.last_updated) | int }}"
@@ -0,0 +1,35 @@
#!/bin/sh
set -eu
GRAFANA_USER="${GRAFANA_DB_USER:-dawarich_grafana_ro}"
GRAFANA_PASSWORD="$(cat /run/secrets/dawarich_grafana_ro_password)"
sql_ident() {
printf '"%s"' "$(printf '%s' "$1" | sed 's/"/""/g')"
}
sql_literal() {
printf "'%s'" "$(printf '%s' "$1" | sed "s/'/''/g")"
}
DB_IDENT="$(sql_ident "$POSTGRES_DB")"
USER_IDENT="$(sql_ident "$GRAFANA_USER")"
USER_LITERAL="$(sql_literal "$GRAFANA_USER")"
PASSWORD_LITERAL="$(sql_literal "$GRAFANA_PASSWORD")"
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<EOSQL
DO \$\$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_catalog.pg_roles WHERE rolname = ${USER_LITERAL}) THEN
EXECUTE 'CREATE ROLE ${USER_IDENT} LOGIN PASSWORD ${PASSWORD_LITERAL}';
ELSE
EXECUTE 'ALTER ROLE ${USER_IDENT} WITH LOGIN PASSWORD ${PASSWORD_LITERAL}';
END IF;
END
\$\$;
GRANT CONNECT ON DATABASE ${DB_IDENT} TO ${USER_IDENT};
GRANT USAGE ON SCHEMA public TO ${USER_IDENT};
GRANT SELECT ON ALL TABLES IN SCHEMA public TO ${USER_IDENT};
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO ${USER_IDENT};
EOSQL
@@ -0,0 +1,18 @@
# Dawarich 1.8.1 serves the Prometheus endpoint on the web service at
# /metrics. Port 9394 is the internal Sidekiq metrics endpoint consumed by
# dawarich_app via SIDEKIQ_METRICS_URL.
#
# Prerequisites in monitoring/docker-compose.yml:
# - attach service `prometheus` to external `backend_net`
# - mount Docker secret/file `/mnt/user/appdata/secrets/dawarich_metrics_password.txt`
# into the Prometheus container at `/run/secrets/dawarich_metrics_password`
- job_name: dawarich
metrics_path: /metrics
scheme: http
basic_auth:
username: prometheus
password_file: /run/secrets/dawarich_metrics_password
static_configs:
- targets:
- dawarich_app:3000
@@ -0,0 +1 @@
replace-with-a-long-random-grafana-readonly-password
@@ -0,0 +1 @@
replace-with-a-long-random-metrics-password
@@ -0,0 +1 @@
replace-with-a-long-random-postgres-password
@@ -0,0 +1 @@
replace-with-a-long-random-url-safe-redis-password
@@ -0,0 +1 @@
replace-with-output-of-openssl-rand-hex-64
+10
View File
@@ -60,6 +60,11 @@ Dieses Dokument listet sensible Daten, deren Ablageorte und die vorgesehene Einb
| Monitoring Grafana -> InfluxDB | Datasource Token | `/mnt/user/appdata/secrets/monitoring_grafana_influxdb_token.txt` -> Docker Secret `/run/secrets/monitoring_grafana_influxdb_token` | aktiv | | Monitoring Grafana -> InfluxDB | Datasource Token | `/mnt/user/appdata/secrets/monitoring_grafana_influxdb_token.txt` -> Docker Secret `/run/secrets/monitoring_grafana_influxdb_token` | aktiv |
| Grafana OIDC (Authelia) | Client Secret | `/mnt/user/appdata/secrets/grafana_oidc_client_secret` (Klartext, chmod 600) -> Docker Secret `/run/secrets/grafana_oidc_client_secret` -> `GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET__FILE`. Zugehoeriger pbkdf2-Hash liegt im Authelia-Host-Config-Client `grafana` (kein Wert im Repo) | aktiv (2026-06-06) | | Grafana OIDC (Authelia) | Client Secret | `/mnt/user/appdata/secrets/grafana_oidc_client_secret` (Klartext, chmod 600) -> Docker Secret `/run/secrets/grafana_oidc_client_secret` -> `GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET__FILE`. Zugehoeriger pbkdf2-Hash liegt im Authelia-Host-Config-Client `grafana` (kein Wert im Repo) | aktiv (2026-06-06) |
| Mealie OIDC (Authelia) | Client Secret | Stack-ENV `${MEALIE_OIDC_CLIENT_SECRET}` in `/mnt/user/services/stacks/mealie/apps/mealie/.env` (Komodo-Stack-ENV); pbkdf2-Hash im Authelia-Host-Config-Client `mealie` (kein Wert im Repo) | aktiv (2026-06-06) | | Mealie OIDC (Authelia) | Client Secret | Stack-ENV `${MEALIE_OIDC_CLIENT_SECRET}` in `/mnt/user/services/stacks/mealie/apps/mealie/.env` (Komodo-Stack-ENV); pbkdf2-Hash im Authelia-Host-Config-Client `mealie` (kein Wert im Repo) | aktiv (2026-06-06) |
| Dawarich | DB Password | `/mnt/user/appdata/secrets/dawarich_postgres_password.txt` -> Docker Secret `/run/secrets/dawarich_postgres_password`; Postgres nutzt `POSTGRES_PASSWORD_FILE`, App/Sidekiq lesen per Entrypoint-Export | geplant |
| Dawarich | Redis Password | `/mnt/user/appdata/secrets/dawarich_redis_password.txt` -> Docker Secret `/run/secrets/dawarich_redis_password`; Redis `--requirepass`, App/Sidekiq `REDIS_URL` | geplant |
| Dawarich | Rails `SECRET_KEY_BASE` | `/mnt/user/appdata/secrets/dawarich_secret_key_base.txt` -> Docker Secret `/run/secrets/dawarich_secret_key_base` | geplant |
| Dawarich Metrics | Basic-Auth Password | `/mnt/user/appdata/secrets/dawarich_metrics_password.txt` -> Docker Secret `/run/secrets/dawarich_metrics_password`; Prometheus `password_file` | geplant |
| Grafana -> Dawarich | Read-only DB Password | `/mnt/user/appdata/secrets/dawarich_grafana_ro_password.txt` -> Docker Secret `/run/secrets/dawarich_grafana_ro_password`; Grafana-Env `DAWARICH_GRAFANA_RO_PASSWORD` | geplant |
| Renovate Bot | Gitea Service-Account PAT | `/mnt/user/appdata/secrets/renovate_token.txt` -> Host-Datei (chmod 600), gelesen von `ops/renovate/run-renovate.sh` und an Renovate-Container als `RENOVATE_TOKEN` weitergegeben | aktiv nach Operator-Setup (siehe `docs/RENOVATE.md`) | | Renovate Bot | Gitea Service-Account PAT | `/mnt/user/appdata/secrets/renovate_token.txt` -> Host-Datei (chmod 600), gelesen von `ops/renovate/run-renovate.sh` und an Renovate-Container als `RENOVATE_TOKEN` weitergegeben | aktiv nach Operator-Setup (siehe `docs/RENOVATE.md`) |
| n8n | Encryption Key fuer interne Credential-Verschluesselung | `/mnt/user/appdata/secrets/n8n_encryption_key.txt` (chmod 600) -> Komodo Stack ENV `${N8N_ENCRYPTION_KEY}`; kein `_FILE`-Support im Upstream-Image | aktiv | | n8n | Encryption Key fuer interne Credential-Verschluesselung | `/mnt/user/appdata/secrets/n8n_encryption_key.txt` (chmod 600) -> Komodo Stack ENV `${N8N_ENCRYPTION_KEY}`; kein `_FILE`-Support im Upstream-Image | aktiv |
| n8n | GMX IMAP Login (Mail-Trigger Workflow) | n8n Credentials Store (Typ `imap`), nur in `/mnt/user/appdata/n8n/data` mit `N8N_ENCRYPTION_KEY` verschluesselt | aktiv | | n8n | GMX IMAP Login (Mail-Trigger Workflow) | n8n Credentials Store (Typ `imap`), nur in `/mnt/user/appdata/n8n/data` mit `N8N_ENCRYPTION_KEY` verschluesselt | aktiv |
@@ -108,6 +113,11 @@ Dieses Dokument listet sensible Daten, deren Ablageorte und die vorgesehene Einb
|-- ha_token_codex |-- ha_token_codex
|-- filebrowser_admin_password.txt |-- filebrowser_admin_password.txt
|-- homelab_smtp_password.txt |-- homelab_smtp_password.txt
|-- dawarich_postgres_password.txt
|-- dawarich_redis_password.txt
|-- dawarich_secret_key_base.txt
|-- dawarich_metrics_password.txt
|-- dawarich_grafana_ro_password.txt
`-- vaultwarden_admin_token.txt `-- vaultwarden_admin_token.txt
``` ```
+3
View File
@@ -43,6 +43,9 @@ Secret-Werte sind nicht enthalten. Es werden nur Secret-Namen, Env-Key-Namen und
| `immich_machine_learning` | Immich ML | `apps/immich/docker-compose.yml` | intern | `immich_default`, `immich_egress` | `model-cache` | rebuildbar | nein | keine Traefik-Route; `immich_egress` (nicht-internal) nur fuer Modell-Download zu huggingface, sonst scheitert Smart Search/Gesichtserkennung an DNS | | `immich_machine_learning` | Immich ML | `apps/immich/docker-compose.yml` | intern | `immich_default`, `immich_egress` | `model-cache` | rebuildbar | nein | keine Traefik-Route; `immich_egress` (nicht-internal) nur fuer Modell-Download zu huggingface, sonst scheitert Smart Search/Gesichtserkennung an DNS |
| `mealie` | Rezeptverwaltung | `apps/mealie/docker-compose.yml` | `https://mealie.kaleschke.info` | `mealie-postgres`, Traefik | `/mnt/user/appdata/mealie/data` | Tier 2, Borg + `mealie.dump` | ja | App + DB in internem Netz getrennt | | `mealie` | Rezeptverwaltung | `apps/mealie/docker-compose.yml` | `https://mealie.kaleschke.info` | `mealie-postgres`, Traefik | `/mnt/user/appdata/mealie/data` | Tier 2, Borg + `mealie.dump` | ja | App + DB in internem Netz getrennt |
| `mealie-postgres` | Mealie-Datenbank | `apps/mealie/docker-compose.yml` | intern | `mealie_internal` | `/mnt/user/appdata/mealie/postgres18`, archivierter Rollback-Altstand `/mnt/user/appdata/_archive/pg18-immich-rollback-volumes-20260602/mealie-postgres17`, `mealie_postgres_password.txt` | Dump `mealie.dump` | nein | interne DB; PostgreSQL 18 | | `mealie-postgres` | Mealie-Datenbank | `apps/mealie/docker-compose.yml` | intern | `mealie_internal` | `/mnt/user/appdata/mealie/postgres18`, archivierter Rollback-Altstand `/mnt/user/appdata/_archive/pg18-immich-rollback-volumes-20260602/mealie-postgres17`, `mealie_postgres_password.txt` | Dump `mealie.dump` | nein | interne DB; PostgreSQL 18 |
| `dawarich_app` | Standort-Historie / Google-Timeline-Ersatz | `apps/dawarich/docker-compose.yml` | `https://dawarich.kaleschke.info` | eigene PostGIS-DB, eigene Redis, Traefik + Authelia, optional Home Assistant Push | `/mnt/user/appdata/dawarich/{postgres17,redis,shared,public,watched,storage}`, `dawarich_*.txt` Secrets | Tier 2, Borg + `dawarich.dump` | ja + Authelia | UI hinter Authelia; API-Key-Tracking-Endpunkte fuer OwnTracks/Overland/Traccar ohne ForwardAuth priorisiert. App und Sidekiq nutzen `freikin/dawarich:1.8.1`; Prometheus-Scrape nach aktueller Dawarich-Doku ueber `dawarich_app:3000/metrics`, Sidekiq-Metriken intern ueber `:9394`. |
| `dawarich_db` | Dawarich PostGIS-Datenbank | `apps/dawarich/docker-compose.yml` | intern | `backend_net` | `/mnt/user/appdata/dawarich/postgres17`, `dawarich_postgres_password.txt`, `dawarich_grafana_ro_password.txt` | Dump `dawarich.dump`; raw DB nur bei gleichem PG/PostGIS und sauberem Shutdown | nein | PostGIS 17-3.5 Alpine; Grafana-Read-only-User `dawarich_grafana_ro` per Init-Script |
| `dawarich_redis` | Dawarich Cache/Queue-Backend | `apps/dawarich/docker-compose.yml` | intern | `backend_net` | `/mnt/user/appdata/dawarich/redis`, `dawarich_redis_password.txt` | Teil von Dawarich-Restore, aber aus DB/Appdaten rekonstruierbar | nein | Redis 7 Alpine, keine Host-Ports |
| `mail-archiver` | Mail-Archivierung | `apps/mail-archiver/docker-compose.yml` | `https://mail.kaleschke.info` | PostgreSQL 18, Internet/IMAP, Traefik, Authelia | `/mnt/user/appdata/mailarchiver/data-protection-keys` | Tier 2, `postgresql17-mailarchiver.dump` | ja + Authelia | Hybrid-Dienst: `frontend_net` fuer Internet, `backend_net` fuer DB; App-eigene Auth bleibt zusaetzliche Schutzschicht; Dump-Dateiname behaelt den historischen Cluster-Namen | | `mail-archiver` | Mail-Archivierung | `apps/mail-archiver/docker-compose.yml` | `https://mail.kaleschke.info` | PostgreSQL 18, Internet/IMAP, Traefik, Authelia | `/mnt/user/appdata/mailarchiver/data-protection-keys` | Tier 2, `postgresql17-mailarchiver.dump` | ja + Authelia | Hybrid-Dienst: `frontend_net` fuer Internet, `backend_net` fuer DB; App-eigene Auth bleibt zusaetzliche Schutzschicht; Dump-Dateiname behaelt den historischen Cluster-Namen |
| `nextcloud` | Datei-/Cloud-Dienst | `apps/nextcloud/docker-compose.yml` | `https://cloud.kaleschke.info` | eigene PostgreSQL, eigene Redis, Traefik | `/mnt/user/appdata/nextcloud/html`, `/mnt/user/documents/nextcloud-data` | Tier 2, `nextcloud.dump` + Share | ja | native App-Auth ohne zentrale ForwardAuth; WebDAV/CardDAV beachten | | `nextcloud` | Datei-/Cloud-Dienst | `apps/nextcloud/docker-compose.yml` | `https://cloud.kaleschke.info` | eigene PostgreSQL, eigene Redis, Traefik | `/mnt/user/appdata/nextcloud/html`, `/mnt/user/documents/nextcloud-data` | Tier 2, `nextcloud.dump` + Share | ja | native App-Auth ohne zentrale ForwardAuth; WebDAV/CardDAV beachten |
| `nextcloud-postgres` | Nextcloud-Datenbank | `apps/nextcloud/docker-compose.yml` | intern | `nextcloud_internal` | `/mnt/user/appdata/nextcloud/postgres18`, archivierter Rollback-Altstand `/mnt/user/appdata/_archive/pg18-immich-rollback-volumes-20260602/nextcloud-postgres17`, `nextcloud_postgres_password.txt` | `nextcloud.dump`, raw DB nicht primaerer Restore-Weg | nein | interne DB; PostgreSQL 18 | | `nextcloud-postgres` | Nextcloud-Datenbank | `apps/nextcloud/docker-compose.yml` | intern | `nextcloud_internal` | `/mnt/user/appdata/nextcloud/postgres18`, archivierter Rollback-Altstand `/mnt/user/appdata/_archive/pg18-immich-rollback-volumes-20260602/nextcloud-postgres17`, `nextcloud_postgres_password.txt` | `nextcloud.dump`, raw DB nicht primaerer Restore-Weg | nein | interne DB; PostgreSQL 18 |
+12
View File
@@ -17,8 +17,11 @@ services:
- prometheus_data:/prometheus - prometheus_data:/prometheus
networks: networks:
- monitoring_net - monitoring_net
- backend_net
expose: expose:
- "9090" - "9090"
secrets:
- dawarich_metrics_password
security_opt: security_opt:
- no-new-privileges:true - no-new-privileges:true
depends_on: depends_on:
@@ -165,6 +168,7 @@ services:
- -c - -c
- | - |
export GRAFANA_INFLUXDB_TOKEN="$$(cat /run/secrets/monitoring_grafana_influxdb_token)" export GRAFANA_INFLUXDB_TOKEN="$$(cat /run/secrets/monitoring_grafana_influxdb_token)"
export DAWARICH_GRAFANA_RO_PASSWORD="$$(cat /run/secrets/dawarich_grafana_ro_password)"
exec /run.sh exec /run.sh
volumes: volumes:
- grafana_data:/var/lib/grafana - grafana_data:/var/lib/grafana
@@ -173,10 +177,12 @@ services:
networks: networks:
- monitoring_net - monitoring_net
- frontend_net - frontend_net
- backend_net
secrets: secrets:
- monitoring_grafana_admin_password - monitoring_grafana_admin_password
- monitoring_grafana_influxdb_token - monitoring_grafana_influxdb_token
- grafana_oidc_client_secret - grafana_oidc_client_secret
- dawarich_grafana_ro_password
expose: expose:
- "3000" - "3000"
security_opt: security_opt:
@@ -390,6 +396,8 @@ networks:
driver: bridge driver: bridge
frontend_net: frontend_net:
external: true external: true
backend_net:
external: true
dns_net: dns_net:
external: true external: true
@@ -409,3 +417,7 @@ secrets:
file: /mnt/user/appdata/secrets/grafana_oidc_client_secret file: /mnt/user/appdata/secrets/grafana_oidc_client_secret
influxdb3_admin_token: influxdb3_admin_token:
file: /mnt/user/appdata/secrets/influxdb3_admin_token.json file: /mnt/user/appdata/secrets/influxdb3_admin_token.json
dawarich_metrics_password:
file: /mnt/user/appdata/secrets/dawarich_metrics_password.txt
dawarich_grafana_ro_password:
file: /mnt/user/appdata/secrets/dawarich_grafana_ro_password.txt
+355
View File
@@ -0,0 +1,355 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "grafana",
"uid": "-- Grafana --"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"editable": false,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": null,
"links": [],
"panels": [
{
"datasource": {
"type": "postgres",
"uid": "dawarich-postgres"
},
"fieldConfig": {
"defaults": {
"custom": {
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
},
"unit": "none"
},
"overrides": []
},
"gridPos": {
"h": 16,
"w": 16,
"x": 0,
"y": 0
},
"id": 1,
"options": {
"basemap": {
"config": {},
"name": "Layer 0",
"type": "default"
},
"controls": {
"mouseWheelZoom": true,
"showAttribution": true,
"showDebug": false,
"showMeasure": false,
"showScale": true,
"showZoom": true
},
"layers": [
{
"config": {
"showLegend": true,
"style": {
"color": {
"fixed": "dark-green"
},
"opacity": 0.55,
"rotation": {
"fixed": 0,
"max": 360,
"min": -360,
"mode": "mod"
},
"size": {
"fixed": 4,
"max": 15,
"min": 2
},
"symbol": {
"fixed": "img/icons/marker/circle.svg",
"mode": "fixed"
},
"textConfig": {
"fontSize": 12,
"offsetX": 0,
"offsetY": 0,
"textAlign": "center",
"textBaseline": "middle"
}
}
},
"location": {
"latitude": "latitude",
"longitude": "longitude",
"mode": "coords"
},
"name": "Location points",
"tooltip": true,
"type": "markers"
}
],
"tooltip": {
"mode": "details"
},
"view": {
"allLayers": true,
"id": "fit",
"lat": 51,
"lon": 10,
"zoom": 5
}
},
"pluginVersion": "13.0.2",
"targets": [
{
"datasource": {
"type": "postgres",
"uid": "dawarich-postgres"
},
"editorMode": "code",
"format": "table",
"rawQuery": true,
"rawSql": "SELECT\n to_timestamp(timestamp) AS \"time\",\n ST_Y(lonlat::geometry) AS latitude,\n ST_X(lonlat::geometry) AS longitude,\n accuracy,\n tracker_id\nFROM points\nWHERE $__unixEpochFilter(timestamp)\n AND lonlat IS NOT NULL\nORDER BY timestamp DESC\nLIMIT 20000;",
"refId": "A"
}
],
"title": "Location Points",
"type": "geomap"
},
{
"datasource": {
"type": "postgres",
"uid": "dawarich-postgres"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "bars",
"fillOpacity": 70,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
},
"unit": "km"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 8,
"x": 16,
"y": 0
},
"id": 2,
"options": {
"legend": {
"calcs": [
"sum"
],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"hideZeros": false,
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "13.0.2",
"targets": [
{
"datasource": {
"type": "postgres",
"uid": "dawarich-postgres"
},
"editorMode": "code",
"format": "time_series",
"rawQuery": true,
"rawSql": "SELECT\n make_date(year, month, 1)::timestamp AS \"time\",\n round((distance::numeric / 1000.0), 2) AS \"km\"\nFROM stats\nWHERE make_date(year, month, 1)::timestamp BETWEEN $__timeFrom() AND $__timeTo()\nORDER BY 1;",
"refId": "A"
}
],
"title": "Kilometers per Month",
"type": "timeseries"
},
{
"datasource": {
"type": "postgres",
"uid": "dawarich-postgres"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "bars",
"fillOpacity": 70,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
},
"unit": "short"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 8,
"x": 16,
"y": 8
},
"id": 3,
"options": {
"legend": {
"calcs": [
"sum"
],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"hideZeros": false,
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "13.0.2",
"targets": [
{
"datasource": {
"type": "postgres",
"uid": "dawarich-postgres"
},
"editorMode": "code",
"format": "time_series",
"rawQuery": true,
"rawSql": "SELECT\n date_trunc('day', to_timestamp(timestamp)) AS \"time\",\n count(*) AS \"points\"\nFROM points\nWHERE $__unixEpochFilter(timestamp)\nGROUP BY 1\nORDER BY 1;",
"refId": "A"
}
],
"title": "Points per Day",
"type": "timeseries"
}
],
"preload": false,
"refresh": "5m",
"schemaVersion": 41,
"tags": [
"dawarich",
"location"
],
"templating": {
"list": []
},
"time": {
"from": "now-30d",
"to": "now"
},
"timepicker": {},
"timezone": "browser",
"title": "Dawarich",
"uid": "dawarich",
"version": 1,
"weekStart": ""
}
@@ -0,0 +1,17 @@
apiVersion: 1
datasources:
- name: Dawarich PostgreSQL
uid: dawarich-postgres
type: postgres
access: proxy
url: dawarich_db:5432
database: dawarich_production
user: dawarich_grafana_ro
editable: false
jsonData:
sslmode: disable
postgresVersion: 1700
timescaledb: false
secureJsonData:
password: $DAWARICH_GRAFANA_RO_PASSWORD
+10
View File
@@ -36,6 +36,16 @@ scrape_configs:
- targets: - targets:
- traefik:8082 - traefik:8082
- job_name: dawarich
metrics_path: /metrics
basic_auth:
username: prometheus
password_file: /run/secrets/dawarich_metrics_password
static_configs:
# Dawarich >= 1.7.7 serves aggregated web + Sidekiq metrics here.
- targets:
- dawarich_app:3000
- job_name: blackbox-http - job_name: blackbox-http
metrics_path: /probe metrics_path: /probe
params: params: