# ============================================================= # MPM – Reverse Proxy (Nginx) # Master has restricted capabilities; workers run as unprivileged user app. # - / -> Management-Frontend (SPA, statische Dateien) # - /api/ -> Management-Backend (127.0.0.1:3000) # Ab Phase 4 werden hier dynamisch Modul-Routen (/slug) ergänzt. # ============================================================= worker_processes auto; user app; pid /tmp/nginx.pid; error_log /dev/stderr warn; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; access_log /dev/stdout; server_tokens off; sendfile on; tcp_nopush on; # Upload-Grenze (z. B. für Modul-ZIP-Pakete ab Phase 3) client_max_body_size 10m; gzip on; gzip_types text/plain text/css application/javascript application/json image/svg+xml; gzip_min_length 1024; client_body_temp_path /tmp/nginx/client_body; proxy_temp_path /tmp/nginx/proxy; fastcgi_temp_path /tmp/nginx/fastcgi; uwsgi_temp_path /tmp/nginx/uwsgi; scgi_temp_path /tmp/nginx/scgi; upstream platform_backend { server 127.0.0.1:3000; } server { listen 8080; server_name _; root /app/public; index index.html; # Sicherheits-Header add_header X-Content-Type-Options "nosniff" always; add_header X-Frame-Options "DENY" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'" always; # Gehashte Frontend-Assets: lange cachen location /assets/ { expires 1y; try_files $uri =404; } # Management-API ans Backend proxien # Modulstarts können durch Docker-Builds deutlich länger als 30 Sekunden dauern. # Der Client muss auf die Lifecycle-Antwort warten können. location /api/v1/modules/ { proxy_pass http://platform_backend; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_read_timeout 600s; } # Marketplace-Updates klonen Branches, bauen Images und starten Compose-Stacks. # Diese Lifecycle-Antworten können länger als das normale API-Limit dauern. location /api/v1/marketplace/modules/ { proxy_pass http://platform_backend; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_read_timeout 600s; } location /api/ { proxy_pass http://platform_backend; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_read_timeout 30s; } # Next.js benötigt Inline-Skripte für die React-Hydrierung. Die globale # Plattform-CSP ohne 'unsafe-inline' würde trotz geladener JS-Dateien # alle Client-Handler des Kalendertools blockieren. location ~ "^/kalendartool(?/.*)?$" { proxy_pass http://platform_backend/api/v1/gateway/kalendartool$calendar_module_path; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_read_timeout 60s; proxy_hide_header Content-Security-Policy; # add_header überschreibt hier die globale Header-Liste; die übrigen # Sicherheits-Header deshalb erneut setzen. add_header X-Content-Type-Options "nosniff" always; add_header X-Frame-Options "DENY" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'" always; } # Modul-Routing (Phase 4): /slug/* wird intern an den # Modul-Gateway des Backends übergeben (/api/v1/gateway/slug/*). # Der Gateway prüft Session, Modul-Status und Berechtigung, # bevor der Request an den Modul-Prozess proxied wird. # WICHTIG: Plattform-Pfade (api, assets, login, …) sind ausgeschlossen, # damit nur echte Modul-Slugs (3–100 Zeichen) weitergeleitet werden. location ~ "^/(?!api/|assets/|login|profile|admin|403|404)(?[a-z0-9][a-z0-9-]{2,100})(?/.*)?$" { proxy_pass http://platform_backend/api/v1/gateway/$module_slug$module_path; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_read_timeout 60s; } # SPA-Fallback für React Router location / { try_files $uri $uri/ /index.html; } } }