Files
audi-app/homeassistant/REVERSE_PROXY.md
T
Paul Nothaft f8b877d555 Phase 10-13: PWA fertig, blockierte Phasen vorbereitet
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.
2026-08-11 11:27:20 +02:00

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