# Feature Request: Frontend/Public API per Subdomain ## Kurzbeschreibung Es soll unterschieden werden, welche Funktionen der App abhängig von der aufgerufenen Subdomain verfügbar sind: - `deinprojekt.meindomain.de` (extern erreichbar): Nur Uploads und das Editieren via zugewiesenem Link (Management-UUID) sollen möglich sein. Keine Moderations-, Gruppen- oder Slideshow-Funktionen sichtbar oder nutzbar. - `deinprojekt.lan.meindomain.de` (Intranet): Vollständige Funktionalität (Slideshow, Groupsview, Moderation, Admin-Endpunkte) sowie volle Navigation/Buttons im Frontend. Die Anwendung läuft in Docker auf einem Ubuntu-Server, vorgeschaltet ist ein `nginx-proxy-manager`. Die Domain `*.lan.meindomain.de` ist nur intern erreichbar und besitzt ein gültiges SSL-Zertifikat für das Intranet (dns challenge letsencrypt). ## Ziele - Sicherheit: Slideshow, Groupview und Admin-/Moderations-Funktionalität niemals über die öffentliche Subdomain erreichbar machen. - UX: Im öffentlichen (externen) Kontext nur die Upload-Experience sichtbar und bedienbar. (die Upload Seite ist bereits so gestalltet, dass keine Menüpunkte sichtbar sind) ## Vorschlag — Technische Umsetzung (hoher Level) 1) Host-Erkennung - Backend und Frontend erkennen die Subdomain via `Host` bzw. `X-Forwarded-Host` Header. Alternativ über eine runtime `env-config.js` (`/public/env-config.js`) die beim Request vom Backend dynamisch befüllt wird. 2) Backend: Gatekeeping-Middleware - Neue Middleware (z.B. `middlewares/hostGate.js`) prüft `req.hostname` / `x-forwarded-host`. - Wenn Request von öffentlicher Subdomain: schränke verfügbare API-Routen ein — nur `/api/upload` und `/api/manage/:token` (oder die minimalen Endpoints) werden zugelassen. - Wenn Request von interner Subdomain: volle Route-Registrierung (Admin, System, Migration usw.). - Schleifen-/Edge-Cases: Allowlist für einzelne externe Hosts (z. B. externe public-frontend-Host), sodass ein extern gehostetes UI die public-API nutzen darf. 3) Frontend: Menü- und Feature-Visibility - Beim Laden prüft das Frontend `window.location.host` (oder die runtime `env-config.js`). - Wenn public-host: Navigation reduziert — nur Upload, ggf. Hilfe/Impressum. Alle Buttons/Links zu Moderation/Slideshow/Gruppen ausgeblendet/gesperrt. - Wenn internal-host: komplette Navigation und Admin-Funktionen sichtbar. 4) Reverse Proxy / nginx - `nginx-proxy-manager` muss Host-Header weiterreichen (standard). Wichtig: `proxy_set_header Host $host;` so dass Backend den Host erkennt. - SSL: bereits vorhanden für beide Host-Namespaces (extern + lan). - Alternative: Public-Frontend extern hosten -> Proxy/Firewall so konfigurieren, dass nur die erlaubten API-Routen erreichbar sind (oder API-Server hinter VPN nur für `*.lan.` erreichbar). 5) CORS & Security - Public-API: enge CORS-Regel (nur erlaubte public-frontend-origin, falls extern gehostet). - Rate-Limiting für public Uploads stärker setzen. - Upload-Validierung (Dateityp, Größe), Scanner/Virus-Check bedenken. ## Akzeptanzkriterien (Metrisch / Testbar) - Auf `deinprojekt.meindomain.de` sind nur Upload und Management-by-UUID erreichbar — Aufrufe von `/api/admin/*` erhalten 403/404. - Auf `deinprojekt.lan.meindomain.de` sind Admin- und Moderation-Endpunkte erreichbar und die Navigation zeigt alle Menüpunkte. - Unit-/Integrationstest: Backend-Middleware hat Tests für Host-Varianten (public/internal/external-frontend) - End-to-End: Test-Upload über public-host funktioniert, Moderation-API von dort nicht. ## Änderungsumfang (Konkrete Dateien/Orte) - Backend - `src/middlewares/hostGate.js` (neu) — enthält Host-Prüfung und Policy - `src/server.js` / `src/index.js` — Routen nur registrieren oder mounten, falls Host-Policy es erlaubt; oder Middleware pro Route - `src/middlewares/auth.js` — ggf. anpassen, um Host-Checks in Kombination mit Auth zu berücksichtigen - Frontend - `public/env-config.js` (runtime) oder `env-config.js` (build-time) — Flag `PUBLIC_MODE=true/false` bzw. `APP_ALLOWED_FEATURES` - Menü-Komponenten (z. B. `Components/Pages/*`) — Feature-Visibility anhand `window.location.host` oder runtime-config - Infrastruktur - `docker/dev/*` nginx-proxy-manager Konfiguration prüfen: Host-Header, Zertifikate ## Sicherheits-Überlegungen - Admin-Endpoints müssen serverseitig geblockt sein — niemals nur per Frontend-UI verstecken. - Public Uploads: individuelle Rate-Limits, Captcha-Optionen, Virus/Malware-Scanning. - Logging & Audit: Uploads von extern sollten besondere Logging-Flags bekommen (IP, Host, Herkunfts-Header). ## Fragen / Punkte zur Konkretisierung — und Antworten aus der Projektdokumentation Nach Durchsicht von `README.md`, `README.dev.md`, `CHANGELOG.md` und `AUTHENTICATION.md` habe ich viele offene Punkte direkt beantwortet und die verbleibenden Entscheidungen auf das Nötigste reduziert. Unten: jeweils die Frage, was die Doku bereits festlegt, und die noch offenen Bestätigungen, die Du kurz geben solltest. 1. Domains — exakte Hosts - Dokumentation: Platzhalter-Hosts wurden als Beispiele verwendet (z. B. `deinprojekt.meindomain.de` und `deinprojekt.lan.meindomain.de`). - Empfehlung / Bitte bestätigen: Nenne bitte die echten Subdomains, die Dein Deployment verwenden wird. Beispiel‑Antwort reicht: `deinprojekt.hobbyhimmel.de` und `deinprojekt.lan.hobbyhimmel.de`. 2. Host-Check vs. zusätzliche Checks - Doku: Admin‑API ist bereits serverseitig per Admin Login geschützt. Management‑API nutzt UUID‑Token mit Rate‑Limits (10 req/h) und Brute‑Force‑Schutz. - Empfehlung: Primär Host‑Header (`Host` / `X-Forwarded-Host`) prüfen (einfach, zuverlässig). Zusätzlich empfehle ich für Admin‑APIs die Kombination aus Bearer‑Token + Host‑Check (defense in depth). Bitte bestätigen, ob IP‑Whitelist gewünscht ist. 3. Externes Hosting des public‑Frontends -> nicht mehr nötig 4. Management‑UUID (Editieren von extern) - Doku: Management‑Tokens sind permanent gültig bis Gruppe gelöscht; Token sind URL‑basiert und Rate‑limited (10 req/h). README zeigt, dass Management‑Portal für Self‑Service gedacht ist und kein zusätzliches network restriction vorgesehen ist. - Schlussfolgerung: Editieren per UUID ist technisch erlaubt und im Projekt vorgesehen. Wenn Du das beibehalten willst, ist keine weitere technische Änderung nötig. Falls Du TTL für Tokens möchtest, bitte angeben. 5. Admin‑APIs: Host‑only oder zusätzlich Bearer‑Token? - ~~Doku: Admin APIs sind bereits durch Bearer‑Token geschützt (`ADMIN_API_KEY`).~~ - ~~Empfehlung: Behalte Bearer‑Token als Hauptschutz und ergänze Host‑Restriction (Admin nur intern erreichbar) für zusätzliche Sicherheit. Bitte bestätigen.~~ 6. Rate‑Limits / Quotas für public Uploads - Doku: Management hat 10 req/h per IP; Upload‑Rate‑Limits für public uploads sind nicht konkret spezifiziert. - Vorschlag: Default `20 uploads / IP / Stunde` für public subdomain + strengere throttling für unauthenticated bursts. Bestätige oder nenne anderes Limit. 7. Logging / Monitoring - Doku: Es gibt umfassende Audit-Logs (`management_audit_log`, `deletion_log`). - Empfehlung: Ergänze ein Feld/Label `source_host` oder `source_type` für public vs. internal Uploads für bessere Filterbarkeit. Bestätigen? Passt! 8. Assets / CDN - Doku: Bilder und Previews werden lokal gespeichert; kein CDN-Flow vorhanden. Du hast klargestellt: Bilder sind intern und nur über UUID‑Links zugänglich. - Entscheidung: Default bleibt interne Auslieferung. Externe CDN-Auslieferung ist möglich, aber muss aus Privacy/Access‑Control‑Gründen extra implementiert (signed URLs, TTL, ACLs). Keine Aktion nötig, wenn Du interne Auslieferung beibehältst. --- Bitte bestätige die wenigen noch offenen Punkte (Hosts, public‑group‑view ja/nein (siehe unten), Management‑UUID extern ja/nein (bestätigt als ja), desired rate‑limit, zusätzliche Admin‑restrictions, logging‑label). Ich habe die Dokumentation soweit wie möglich angepasst (siehe Änderungen weiter unten). Sobald Du diese 3–4 Punkte bestätigst, erstelle ich die konkreten Patches (Middleware, kleine Frontend‑Visibility‑Änderung, Tests, README‑Erweiterung). ## Vorschlag: Minimal umsetzbare erste Iteration (MVP) 1. Implementiere `middlewares/hostGate.js` mit einfacher Host-Allowlist (`PUBLIC_HOSTS`, `INTERNAL_HOSTS` in Env). 2. Im Backend: prüfe bei jedem Request, ob Route erlaubt ist — für public-Hosts nur Upload & manage-by-uuid. 3. Im Frontend: beim Laden `window.location.host` prüfen und Navigation entsprechend reduzieren. 4. Dokumentation: `README.dev.md` (API-Abschnitt) und `frontend/MIGRATION-GUIDE.md` um Hinweise erweitern. 5. Tests: Unit-Test für Middleware + Integrationstest (Supertest) der Host-Policies. ## Nächste Schritte / Implementierungs-Checklist - [ ] Domain-/Host-Liste bestätigen (Fragen beantworten) - [ ] Env-Variablen definieren und in `docker/*/config/.env` ergänzen - [ ] Backend: Middleware implementieren + Tests - [ ] Frontend: runtime `env-config.js` + menu-visibility implementieren - [ ] Proxy/Nginx: Konfiguration prüfen & SSL testen - [ ] Review & Security-Check (rate-limits, CORS, logging) - [ ] Deployment-Plan / Rollout-Notes --- Bitte beantwort e die Fragen im Abschnitt "Fragen / Punkte zur Konkretisierung" oben. Sobald ich Deine Antworten habe, kann ich ein konkretes Implementierungs-Patch (Backend-Middleware + Frontend-Visibility) erstellen und Tests hinzufügen. ## FAQ: Trennung von Frontend und Backend — Frage des Nutzers & Antwort **Frage:** Wie kann ich Frontend und Backend räumlich trennen, ohne dass sicherheitsrelevante (Bilder) theoretisch extern erreichbar sind? Im Moment laufen Frontend und Backend in einer Docker Compose. Ist das sinnvoll? Wie trennt man das am Besten? **Antwort (zusammengefasst & praxisorientiert):** - Development: Für lokale Entwicklung ist eine gemeinsame `docker-compose`-Umgebung (Frontend + Backend) sinnvoll — HMR, einfache Debugging und Tests. - Produktion: Trennung empfohlen. Ziel: Frontend öffentlich (statisch/CDN) betreiben, Backend streng begrenzen und Assets (Originale/Previews) niemals ohne Authorisierung öffentlich machen. Architektur-Optionen (Kurz): - Single-Server mit `nginx` Reverse‑Proxy (empfohlen, einfach): `nginx` routet `/` zum statischen Frontend und `/api/*` zum Backend; Backend nicht direkt öffentlich. - Frontend extern (CDN/Netlify) + Backend intern hinter Reverse‑Proxy: Frontend ist skalierbar, Backend nur über Proxy erreichbar; für Bilder: presigned URLs oder Backend‑Proxy verwenden. - Vollständige Trennung (Backend nur im privaten Netz / VPN): Sehr sicher, aber komplexer (VPN/VPC). Admin-/Moderation nur über LAN/VPN erreichbar. Wie Bilder sicher halten (Pattern): - Pattern A — Backend‑proxied images: Bilder nur auf Backend speichern; Zugriff nur über Backend‑Endpunkte (prüfen Management‑UUID / Host), keine direkte öffentliche URL. - Pattern B — Private Object Storage + presigned URLs: Nutze privaten S3/Bucket; generiere kurzlebige presigned URLs nach Auth/Zugriffsprüfung; kombiniere mit CDN (Origin Access). - Pattern C — CDN + signed URLs für Previews: Nur Previews via CDN mit signed URLs; Originals bleiben intern oder ebenfalls presigned. Konkrete Maßnahmen (umsetzbar sofort): 1. Reverse‑Proxy (`nginx`) einführen: zwei vhosts (public / internal). Auf public vhost `/api/admin` und `/groups` blockieren; nur `/api/upload` und `/api/manage/:token` erlauben. 2. Docker‑Netzwerke: Backend in `internal_net` ohne veröffentlichte Ports; `reverse-proxy` hat öffentliche Ports und verbindet zu `backend` intern. 3. Host‑Gate Middleware (Express): `req.isPublic` setzen via `Host`/`X-Forwarded-Host`, serverseitig Routen (Admin/Groups) für public blocken — defense in depth. 4. CORS & Rate‑Limit: CORS auf erlaubte Origins, strengere Rate‑Limits für public Uploads (z. B. 20 Uploads/IP/Stunde) und Captcha prüfen. 5. Logging: Audit‑Logs erweitern (z. B. `source_host`) um public vs internal Uploads zu unterscheiden. Beispiel nginx‑Snippet (konzeptionell): ``` server { server_name public.example.com; location / { root /usr/share/nginx/html; try_files $uri /index.html; } location ~ ^/api/(upload|manage) { proxy_pass http://backend:5001; proxy_set_header Host $host; } location ~ ^/api/admin { return 403; } location ~ ^/groups { return 403; } } server { server_name internal.lan.example.com; location / { proxy_pass http://frontend:3000; } location /api/ { proxy_pass http://backend:5001; } } ``` Docker‑Compose Hinweis (prod): Backend ohne `ports:` veröffentlichen; `reverse-proxy` expose Ports 80/443 und verbindet intern: ``` services: reverse-proxy: ports: ["80:80","443:443"] networks: [public_net, internal_net] backend: networks: [internal_net] # no ports networks: internal_net: internal: true ``` Checklist (schnell umsetzbar) - [ ] `nginx` reverse‑proxy hinzufügen - [ ] Backend‑Ports entfernen (nur interner Zugriff) - [ ] vhost‑Regeln: public vs internal (Admin blockieren auf public) - [ ] `hostGate` middleware implementieren (Express) - [ ] CORS, Rate‑Limit, Captcha konfigurieren - [ ] Audit‑Log `source_host` ergänzen Wenn Du möchtest, implementiere ich als nächsten Schritt die `hostGate`‑Middleware, Beispiel‑nginx‑VHosts und die `docker-compose`‑Änderungen als Patch hier im Repository. Sag mir kurz, welche Hostnames (Platzhalter sind OK) und ob Du Frontend lokal im selben Host behalten willst oder extern hosten willst. ## Technische Details & Voraussetzungen Im Folgenden findest Du eine vertiefte, technische Zusammenfassung der Architekturoptionen, Voraussetzungen und Sicherheitsmaßnahmen — als Entscheidungsgrundlage für die Implementierung des Subdomain‑abhängigen Verhaltens. 1) Ziel und Sicherheitsprinzip - Zweck: Subdomain‑abhängig unterschiedliche UX und API‑Zugänglichkeit (Public: Upload + Manage-UUID; Intranet: Full‑Feature). - Sicherheitsprinzip: Nie ausschließlich auf Frontend‑Steuerung vertrauen — serverseitige Blockierung ist Pflicht. 2) Infrastruktur‑Varianten - Variante A — Single Host + `nginx` Reverse‑Proxy: Einfach, kontrollierbar, Proxy hostet TLS, routet an Backend; Backend nicht direkt erreichbar. - Variante B — Frontend extern (CDN/Netlify) + Backend intern: Skalierbar; Bilder per presigned URLs oder Backend‑Proxy ausliefern. - Variante C — Backend nur im privaten Netz/VPN: Höchste Sicherheit, mehr Betriebskomplexität. 3) Host‑Erkennung und Defense in Depth - Proxy muss `Host` bzw. `X-Forwarded-Host` weiterreichen (`proxy_set_header Host $host`). - Implementiere serverseitig eine `hostGate`‑Middleware, die `req.isPublic` bzw. `req.isInternal` setzt und schütze kritische Routen zusätzlich (Admin, Groups Listing, Cleanup). - Kombiniere Proxy‑Regeln + Middleware + Bearer‑Token (für Admin) + Firewall für maximale Sicherheit. 4) Speicherung und Auslieferung von Bildern - Standard: Bilder lokal in `backend/src/data/images` und `.../previews`. - Pattern A (empfohlen kleinbetrieblich): Backend‑proxied images — keine direkten öffentlichen Pfade; Backend kontrolliert Zugriffe (UUID, Host). - Pattern B (Skalierung): Privater Object‑Store (S3‑compatible) + presigned URLs (TTL kurz) + CDN (Origin Access) für Performance. - Previews können weniger restriktiv gehandhabt werden (kurze TTLs / signed URLs), Originals sollten restriktiver sein. 5) Management‑UUID (Risiken & Optionen) - Aktuell: UUIDs permanent gültig bis Löschung (convenience). Risiko: Leak bedeutet Zugriff. - Optionen: Beibehalten + Rate‑Limit/Audit (empfohlen), oder TTL/Rotation/Opt‑in Passwortschutz (sicherer, schlechtere UX). 6) CORS, CSRF, TLS - CORS: Nur erlaubte Origins eintragen (public frontend origin(s) und/oder intranet origin). - CSRF: REST API mit token/UUID im Pfad ist weniger CSRF‑anfällig, trotzdem sicherheitsbewusst durchführen. - TLS/HSTS: Pflicht für öffentliche Hosts. 7) Rate‑Limiting und Abuse‑Protection - Public Uploads streng limitieren (z. B. 20 uploads/IP/Stunde) + Dateigrößenlimits + MIME/Exif/Type‑Validation. - Optional Captcha für Uploads bei hohem Traffic/Abuse Verdacht. 8) Logging und Monitoring - Ergänze Audit‑Logs um `source_host`/`source_type` und `request_origin`. - Metriken für rate‑limit hits, 403s, upload errors, health checks; optional Sentry/Prometheus. 9) Docker/Bereitstellungsempfehlungen - Dev: `docker/dev/docker-compose.yml` mit exposed ports OK. - Prod: Backend keinem Hostport aussetzen (`ports:` entfernen). Reverse‑proxy exponiert 80/443; backend nur im internen Docker‑Netz. - Verwende ein `internal` Docker‑Netzwerk oder separate Netzwerke für Public/Private. 10) nginx‑proxy‑manager Hinweise - Konfiguriere Proxy‑Hosts für public vs. internal mit passenden Headern (`Host`, `X-Forwarded-*`). - Verwende Proxy‑Regeln, um `/api/admin` & `/groups` auf public Host zu blocken; teste mit `curl`. 11) Deployment‑Prerequisites (konkret) - DNS für beide Subdomains (public + intranet) vorhanden. - TLS für public (Let's Encrypt) und internes Zertifikat für LAN. - `ADMIN_API_KEY` sicher gesetzt, `PUBLIC_HOSTS` / `INTERNAL_HOSTS` konfiguriert. - Backup‑/Restore‑Policy für DB & images. 12) Entscheidungsfragen / Tradeoffs - UUID permanent vs TTL: UX vs Security. - Previews via CDN vs Backend‑Proxy: Performance vs Kontrolle. - Frontend lokal hinter nginx vs extern gehostet: Einfachheit vs Skalierbarkeit. 13) Prüfbare Akzeptanzkriterien (Beispiele) - `curl -I https://public.example.com/api/admin/deletion-log` → 403 - Upload via public Host funktioniert (POST to `/api/upload`), Moderation API returns 403. - Backend nicht per `docker ps`/published port extern erreichbar. 14) Vorschlag: nächste non‑implementierende Schritte - Definiere endgültig: Public/Internal Hostnames; Management‑UUID Policy (TTL ja/nein); Rate‑Limit Wert; CDN für Previews ja/nein. - Ich kann danach ein Security‑Design‑Dokument (nginx rules, env vars, checklist) erstellen oder direkt Implementierungs‑Patches liefern. Bitte bestätige kurz die vier entscheidenden Punkte, damit ich das Design final zuspitze: - Hosts: welche Subdomains sollen verwendet werden? (z. B. `deinprojekt.meindomain.de`, `deinprojekt.lan.meindomain.de`) - Management‑UUID extern erlaubt? (Ja/Nein) - Rate‑Limit für public Uploads? (z. B. `20 uploads/IP/Stunde`) - Previews via CDN erlaubt? (Ja/Nein) --- Bitte sag mir, ob ich diese detaillierte Sektion so übernehmen soll (ich habe sie bereits in dieses Feature‑Request eingefügt). Wenn ja, kann ich auf Wunsch noch ein kurzes Security‑Design‑PDF oder konkrete nginx‑Snippet‑Dateien ergänzen.