f8b877d555
PWA laeuft: Manifest, Symbole in allen noetigen Groessen und die iOS-Angaben, die Apple statt des Manifests auswertet. Das Startsymbol ist bewusst neutral - die Vier Ringe auf einem Homescreen waeren nach aussen sichtbar und fielen nicht mehr unter die private Nutzung. Vorbereitet, aber nicht ausgefuehrt: Capacitor-Konfiguration, ein Ablage-Adapter fuer Schluesselbund und Keystore (greift defensiv auf die Laufzeit zu, damit die App ohne das Plugin unveraendert weiterlaeuft), die Pfad-Freigabeliste fuer den Reverse Proxy und das Geruest der FMM003-Zuordnungstabelle. Die QR-Seite fuer die Einrichtung war zunaechst ein Fehlgriff: Ich hatte den QR-Erzeuger selbst geschrieben. Der Vergleich gegen eine erprobte Implementierung zeigte 1239 abweichende Module von 3249 - der Code waere unlesbar gewesen. Jetzt liegt eine bewaehrte Bibliothek (MIT, 57 KB) neben der Seite im eigenen Home Assistant. Das erfuellt die eigentliche Anforderung genauso: kein Netzzugriff, der Token verlaesst das eigene Netz nicht. Geprueft ueber einen Umlauf - 233 Zeichen hinein, identisch wieder heraus.
127 lines
4.7 KiB
Markdown
127 lines
4.7 KiB
Markdown
# Reverse-Proxy: Pfad-Freigabeliste für DataMetric360
|
|
|
|
**Vorbereitung, noch nicht in Betrieb.** Gehört zu Phase 12 des
|
|
`../UMSETZUNGSPLAN.md`; die Entscheidung dahinter steht in
|
|
`../COMPANION_APP_ARCHITECTURE.md` §4.
|
|
|
|
Ziel: Die App erreicht Home Assistant von unterwegs, **ohne dass Home Assistant
|
|
selbst im Internet steht**. Dazu ein Cloudflare-Tunnel (baut nur nach außen auf,
|
|
kein Port am Router) auf einen Reverse Proxy, der ausschließlich die unten
|
|
aufgeführten Pfade durchlässt.
|
|
|
|
## Was die App wirklich braucht
|
|
|
|
Aus dem tatsächlichen Code der Datenschicht (`companion-app/src/api/`)
|
|
abgeleitet, nicht geschätzt:
|
|
|
|
| Methode | Pfad | Wofür |
|
|
|---|---|---|
|
|
| `GET` | `/api/` | Verbindungsprüfung bei der Ersteinrichtung |
|
|
| `GET` | `/api/states/pyscript.audi_dashboard_*` | Profil, Fahrten, Tankvorgänge, Status, Batterieverlauf, Belegergebnis, Updatestatus |
|
|
| `GET` | `/api/states/pyscript.reifen_*` | Reifensatz-Kilometerstände |
|
|
| `POST` | `/api/services/pyscript/audi_dashboard_*` | alle schreibenden Vorgänge |
|
|
| `GET` (Upgrade) | `/api/websocket` | Live-Aktualisierung |
|
|
|
|
Alles andere wird geblockt, insbesondere `/auth/*`, `/lovelace*`, `/config*`,
|
|
`/api/config`, `/api/history*`, `/developer-tools*` und die Oberfläche selbst.
|
|
|
|
## Ehrliche Einschränkung
|
|
|
|
**Der WebSocket lässt sich nicht pfadgenau beschneiden.** Nach `auth_ok` kann
|
|
über `/api/websocket` grundsätzlich jeder Zustand gelesen werden, nicht nur die
|
|
`pyscript.*`-Entitäten. Die Freigabeliste ist an dieser Stelle also grobkörniger
|
|
als beim REST-Zugriff.
|
|
|
|
Was bleibt: Ohne gültigen Token kommt gar keine Verbindung zustande, und ein
|
|
verlorenes Gerät wird durch Zurückziehen genau seines Tokens ausgesperrt. Das
|
|
ist die im Architekturdokument bewusst akzeptierte Abwägung — sie sollte nur
|
|
nicht in Vergessenheit geraten.
|
|
|
|
Wer sie nicht eingehen will, hat eine Alternative: den WebSocket weglassen und
|
|
die App auf regelmäßiges Abfragen umstellen. Kostet Akku und Datenvolumen,
|
|
verkleinert die Angriffsfläche aber auf die exakt aufgeführten REST-Pfade.
|
|
|
|
## Nginx Proxy Manager
|
|
|
|
Im Add-on unter *Hosts → Proxy Hosts → Edit → Advanced* eintragen. Ziel ist der
|
|
interne Name der Home-Assistant-Instanz (im Supervisor-Netz `homeassistant:8123`).
|
|
|
|
```nginx
|
|
# Reihenfolge zählt: die erlaubenden Blöcke stehen vor dem pauschalen Verbot.
|
|
|
|
location = /api/ {
|
|
proxy_pass http://homeassistant:8123;
|
|
include conf.d/include/proxy.conf;
|
|
}
|
|
|
|
location ~ ^/api/states/pyscript\.(audi_dashboard_[a-z_]+|reifen_[a-z_]+)$ {
|
|
limit_except GET { deny all; }
|
|
proxy_pass http://homeassistant:8123;
|
|
include conf.d/include/proxy.conf;
|
|
}
|
|
|
|
location ~ ^/api/services/pyscript/audi_dashboard_[a-z_]+$ {
|
|
limit_except POST { deny all; }
|
|
proxy_pass http://homeassistant:8123;
|
|
include conf.d/include/proxy.conf;
|
|
}
|
|
|
|
location = /api/websocket {
|
|
proxy_pass http://homeassistant:8123;
|
|
proxy_http_version 1.1;
|
|
proxy_set_header Upgrade $http_upgrade;
|
|
proxy_set_header Connection "upgrade";
|
|
proxy_read_timeout 3600s;
|
|
include conf.d/include/proxy.conf;
|
|
}
|
|
|
|
# Die Fotos der Fahrzeuge, die die App anzeigt. Nur Lesen, nur Bilder.
|
|
location ~ ^/local/bilder/[a-z0-9_-]+\.(webp|png|jpg|svg)$ {
|
|
limit_except GET { deny all; }
|
|
proxy_pass http://homeassistant:8123;
|
|
include conf.d/include/proxy.conf;
|
|
}
|
|
|
|
# Alles Übrige: nicht durchlassen.
|
|
location / {
|
|
return 404;
|
|
}
|
|
```
|
|
|
|
Wird die App selbst unter derselben Adresse ausgeliefert, braucht sie einen
|
|
eigenen Block auf ihr Verzeichnis — sauberer ist ein getrennter Hostname
|
|
(`datametric360.app` für die App, `api.datametric360.app` für die
|
|
Schnittstelle), dann bleibt diese Liste unverändert.
|
|
|
|
## Nach der Einrichtung prüfen
|
|
|
|
Von einem Netz ohne VPN, etwa über Mobilfunk:
|
|
|
|
```bash
|
|
API=https://api.datametric360.app
|
|
T=<Zugriffstoken>
|
|
|
|
# muss gehen
|
|
curl -s -o /dev/null -w '%{http_code}\n' -H "Authorization: Bearer $T" "$API/api/"
|
|
curl -s -o /dev/null -w '%{http_code}\n' -H "Authorization: Bearer $T" \
|
|
"$API/api/states/pyscript.audi_dashboard_profil"
|
|
|
|
# muss 404 oder 403 liefern
|
|
curl -s -o /dev/null -w '%{http_code}\n' "$API/auth/authorize"
|
|
curl -s -o /dev/null -w '%{http_code}\n' -H "Authorization: Bearer $T" "$API/api/config"
|
|
curl -s -o /dev/null -w '%{http_code}\n' -H "Authorization: Bearer $T" \
|
|
"$API/api/states/sensor.audi_rs_4_avant_mileage"
|
|
|
|
# ohne Token: 401, nicht 200
|
|
curl -s -o /dev/null -w '%{http_code}\n' "$API/api/states/pyscript.audi_dashboard_profil"
|
|
```
|
|
|
|
Zusätzlich: Port 8123 darf von außen **gar nicht** antworten.
|
|
|
|
## Offen bis zur Einrichtung
|
|
|
|
- Nameserver von `datametric360.app` auf Cloudflare umstellen („Full setup")
|
|
- Entscheidung Nginx Proxy Manager gegen Traefik (die Liste oben ist für NPM
|
|
geschrieben und für Traefik sinngemäß zu übertragen)
|
|
- Endgültige Hostnamen festlegen und hier eintragen
|