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

4.7 KiB

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).

# 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:

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