Discovery zeigte: YunoHost reicht den Usernamen nicht als Header durch, sondern im signierten Cookie "yunohost.portal" (JWT, Claim "user"). Die Forward-Auth liest jetzt die Identitaet aus Header ODER Cookie - nur von der Proxy-Quell-IP akzeptiert. HS256-Signaturpruefung optional via TRUSTED_AUTH_JWT_SECRET (stdlib hmac, kein Dep). - config: trusted_auth_cookie / _cookie_claim / _jwt_secret - nginx-Vorlage + deploy/README: keine Identitaets-Header-Zeile mehr noetig; SSO-Schutz der Subdomain ist Pflicht (sonst Spoofing) - Tests: Cookie-Extraktion, Signaturpruefung, Proxy-IP-Trust Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3.2 KiB
Remote-Betrieb über YunoHost (va.linix.de)
Web-UI + Mikrofon vom Handy/Browser, abgesichert per HTTPS und YunoHost-SSO.
Topologie: https://va.linix.de → nginx@YunoHost (TLS, SSO) → über LAN →
http://<GPU-Box>:8003 (Gateway). Der interne LAN-Hop ist unverschlüsselt
(vertrautes LAN, wie bei Ollama).
Warum HTTPS Pflicht ist: Browser geben das Mikrofon (
getUserMedia) nur in einem „secure context" frei – also HTTPS oderhttp://localhost. Über einfacheshttp://vom Handy gibt es kein Mikrofon.
1. Gateway auf der GPU-Box
deploy/voice-assistant.env.example → /etc/voice-assistant/voice-assistant.env anpassen:
HOST= LAN-IP der GPU-Box (nicht0.0.0.0),PORT=8003AUTH_ENABLED=trueTRUSTED_AUTH_HEADER(nach Discovery, s. u.),TRUSTED_PROXY_IPS= LAN-IP von linix.deADMIN_USERS=atoor,dieterschlueter,dschlueter,SSO_LOGOUT_URL=…
Kein
--forwarded-allow-ipssetzen: Das Identitäts-Vertrauen prüft die direkte Quell-IP (= der Proxy). Würde uvicorn den Client ausX-Forwarded-Forüberschreiben, schlüge der Proxy-IP-Check fehl.
2. Drei Sicherheits-Pflichten
- Bind: Gateway nur an die LAN-IP (Schritt 1).
- Firewall: Port 8003 der GPU-Box nur von der linix.de-IP erlauben, z. B.:
sudo ufw allow from <linix.de_LAN_IP> to any port 8003 proto tcp sudo ufw deny 8003 - Header überschreiben: nginx setzt den Identitäts-Header selbst; Client-Eingaben werden verworfen (siehe nginx-Conf). App-seitig zusätzlich der Proxy-IP-Check.
3. nginx auf YunoHost
deploy/va.linix.de.nginx.conf als Vorlage → auf dem YunoHost-Server unter
/etc/nginx/conf.d/va.linix.de.d/assistant.conf ablegen, GPU_BOX_LAN_IP
eintragen, die map $http_upgrade … einmalig im http{}-Kontext anlegen, dann
nginx -t && systemctl reload nginx. Subdomain va.linix.de in YunoHost
anlegen (Let's Encrypt) und per SSO schützen (nur erlaubte Tester/Gruppe).
4. Identität: YunoHost liefert sie im Cookie (nicht als Header)
Discovery (/api/admin/request-headers?key=<ADMIN_API_KEY> hinter dem SSO) zeigt:
YunoHost reicht den Usernamen nicht als eigenen Header durch, sondern im JWT-Cookie
yunohost.portal (Claim user). Das Gateway liest diesen Cookie direkt — daher:
# .env auf der GPU-Box:
TRUSTED_AUTH_COOKIE=yunohost.portal
TRUSTED_AUTH_COOKIE_CLAIM=user
TRUSTED_PROXY_IPS=<LAN-IP des YunoHost-Servers>
# optional (Härtung): HS256-Secret des Portals -> Signaturpruefung
# TRUSTED_AUTH_JWT_SECRET=...
In der nginx-Conf ist keine proxy_set_header-Identitätszeile nötig — Cookies
werden ohnehin durchgereicht.
Sicherheit: Ohne
TRUSTED_AUTH_JWT_SECRETwird die Cookie-Payload ungeprüft gelesen. Das ist nur sicher, weil (a) nur die Proxy-Quell-IP akzeptiert wird und (b) die Subdomain per SSO geschützt sein muss (dann lässt YunoHost nur validierte Cookies durch). Für Härtung das Portal-HS256-Secret inTRUSTED_AUTH_JWT_SECRETsetzen → die Signatur wird dann selbst geprüft.
5. Test
https://va.linix.de/lädt die UI, links „Angemeldet als ".- Text-Chat funktioniert; Mikrofon-Button nimmt auf und spielt die Antwort ab.
- Admins (
ADMIN_USERS) sehen den Admin-Bereich (Nutzerliste).