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
+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