added new features 3.0

This commit is contained in:
leon
2026-10-10 15:51:30 +02:00
parent 84d8697f23
commit 21e2ccefb2
41 changed files with 978 additions and 226 deletions

View File

@@ -3,7 +3,8 @@
# 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.
# Moduloberflächen liegen auf einem eigenen Host; der Hostname wird beim Start
# aus MODULE_PUBLIC_ORIGIN in diese Konfiguration eingesetzt.
# =============================================================
worker_processes auto;
@@ -43,7 +44,7 @@ http {
}
server {
listen 8080;
listen 8080 default_server;
server_name _;
root /app/public;
@@ -67,7 +68,7 @@ http {
location /api/v1/modules/ {
proxy_pass http://platform_backend;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header Host $http_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;
@@ -79,7 +80,7 @@ http {
location /api/v1/marketplace/modules/ {
proxy_pass http://platform_backend;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header Host $http_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;
@@ -89,48 +90,23 @@ http {
location /api/ {
proxy_pass http://platform_backend;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header Host $http_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(?<calendar_module_path>/.*)?$" {
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.
# Alte Modul-Links auf dem Plattformhost führen über das Einmal-Ticket
# zum getrennten Modulhost. Hier wird kein Modul-JavaScript ausgeliefert.
location ~ "^/(?!api/|assets/|login|profile|admin|403|404)(?<module_slug>[a-z0-9][a-z0-9-]{2,100})(?<module_path>/.*)?$" {
proxy_pass http://platform_backend/api/v1/gateway/$module_slug$module_path;
proxy_pass http://platform_backend/api/v1/auth/module-open/$module_slug;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header Host $http_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_read_timeout 30s;
}
# SPA-Fallback für React Router
@@ -138,4 +114,51 @@ http {
try_files $uri $uri/ /index.html;
}
}
# Dieser Host liefert ausschließlich Modulpfade und den Ticket-Übergang.
# Management-API, Login, Admin-Frontend und Plattform-Cookies sind hier
# nicht erreichbar. Der Name wird beim Containerstart validiert eingesetzt.
server {
listen 8080;
server_name __MODULE_HOSTNAME__;
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'; worker-src 'none'; 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;
# Auf lokalen Macs kann dieser Host zuvor für MPM verwendet worden sein.
# Bekannte Plattform-Einstiege führen zum konfigurierten Plattformhost.
location = / { return 302 __PLATFORM_ORIGIN__/; }
location ~ "^/(login|admin|profile|assets|403|404)(/|$)" {
return 302 __PLATFORM_ORIGIN__$request_uri;
}
location = /__mpm_module_handoff {
access_log off;
proxy_pass http://platform_backend/api/v1/auth/module-handoff$is_args$args;
proxy_http_version 1.1;
proxy_set_header Host $http_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;
}
location ^~ /api/ { return 404; }
location ~ "^/(?<module_slug>[a-z0-9][a-z0-9-]{2,100})(?<module_path>/.*)?$" {
proxy_pass http://platform_backend/api/v1/gateway/$module_slug$module_path$is_args$args;
proxy_http_version 1.1;
proxy_set_header Host $http_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;
proxy_hide_header Service-Worker-Allowed;
}
location / { return 404; }
}
}

View File

@@ -0,0 +1,14 @@
const fs = require('node:fs');
const { loadConfiguration } = require('/app/platform-backend/dist/config/configuration.js');
const configuration = loadConfiguration();
const { hostname } = new URL(configuration.modulePublicOrigin);
const platformOrigin = new URL(configuration.marketplace.publicUrl).origin;
if (!/^[a-z0-9.-]+$/i.test(hostname)) {
throw new Error('Ungültiger Modul-Hostname');
}
const template = fs.readFileSync('/etc/nginx/nginx.conf.template', 'utf8');
fs.writeFileSync(
'/tmp/mpm-nginx.conf',
template.replaceAll('__MODULE_HOSTNAME__', hostname).replaceAll('__PLATFORM_ORIGIN__', platformOrigin),
);

View File

@@ -0,0 +1,4 @@
#!/bin/sh
set -eu
node /usr/local/lib/mpm/render-nginx-config.cjs
exec /usr/sbin/nginx -g 'daemon off;' -c /tmp/mpm-nginx.conf

View File

@@ -30,7 +30,7 @@ stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
[program:nginx]
command=/usr/sbin/nginx -g "daemon off;" -c /etc/nginx/nginx.conf
command=/usr/local/bin/start-mpm-nginx
autorestart=true
startretries=5
stopsignal=QUIT