diff --git a/deploy/131-portal-einrichten.sh b/deploy/131-portal-einrichten.sh new file mode 100755 index 00000000..c7281fcc --- /dev/null +++ b/deploy/131-portal-einrichten.sh @@ -0,0 +1,193 @@ +#!/usr/bin/env bash +# Richtet das Portal auf 131 ein (Dienst, nginx 8450, Firewall, CORS am Core, +# Audience "portal", Neubau von Portal und Login). Als root auf 131 ausfuehren: +# scp deploy/131-portal-einrichten.sh root@192.168.1.131:/root/ && ssh root@192.168.1.131 'bash /root/131-portal-einrichten.sh' +# Idempotent; geaenderte Dateien werden vorher nach $BAK gesichert. Geheimnisse +# werden nur zwischen Dateien kopiert und nie ausgegeben. +set -euo pipefail + +HOST=192.168.1.131 +INSTALL=/opt/nexarch-web/portal +ACCOUNT=/opt/nexarch-web/account +SRC=/root/nexarch-code +BAK=/root/portal-einrichten-$(date +%Y%m%d-%H%M%S) +NGINX_SITE=/etc/nginx/sites-available/nexarch-gui +mkdir -p "$BAK" + +say() { printf '\n== %s\n' "$*"; } +fail() { printf 'FEHLER: %s\n' "$*" >&2; exit 1; } + +[ "$(id -u)" = 0 ] || fail "als root ausfuehren" +[ -f "$NGINX_SITE" ] || fail "$NGINX_SITE fehlt" +[ -f /etc/nftables.conf ] || fail "/etc/nftables.conf fehlt" +[ -f /etc/nexarch/policy-api.env ] || fail "/etc/nexarch/policy-api.env fehlt" +[ -d "$INSTALL/web/portal/.next" ] || fail "Portal-Build unter $INSTALL fehlt" +grep -qE 'include\s+/etc/nginx/conf\.d/\*\.conf' /etc/nginx/nginx.conf || fail "nginx.conf bindet conf.d nicht ein" +nginx -t &1 | tail -1 + +say "1/8 Quellstand" +git -C "$SRC" fetch -q origin /dev/null || sed -i -E 's/^(NEXARCH_ACCOUNT_MODULE_AUDIENCES=.*)$/\1,portal/' "$ENVF" +else + echo 'NEXARCH_ACCOUNT_MODULE_AUDIENCES=dms,portal' >> "$ENVF" +fi +grep '^NEXARCH_ACCOUNT_MODULE_AUDIENCES=' "$ENVF" +echo "Hinweis: mit mehr als einer Audience lehnt der Core Anfragen ohne ?module= ab. Auf 131 nutzt bisher kein Frontend eine Sitzung (geprueft), das Portal setzt module=portal." + +say "4/8 nginx: CORS am Core (8443) und Block 8450" +cp -p "$NGINX_SITE" "$BAK/nexarch-gui" +cat > /etc/nginx/conf.d/nexarch-cors-map.conf <<'MAP' +map $http_origin $nexarch_cors_origin { + default ""; + "~^https://192\.168\.1\.131:(8444|8445|8446|8447|8448|8449|8450)$" $http_origin; +} +MAP +cat > /etc/nginx/snippets-nexarch-cors.conf <<'SNIP' +if ($request_method = OPTIONS) { + add_header Access-Control-Allow-Origin $nexarch_cors_origin always; + add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always; + add_header Access-Control-Allow-Headers "Content-Type" always; + add_header Access-Control-Allow-Credentials "true" always; + add_header Content-Length 0; + return 204; +} +add_header Access-Control-Allow-Origin $nexarch_cors_origin always; +add_header Access-Control-Allow-Credentials "true" always; +SNIP +python3 - "$NGINX_SITE" <<'PY' +import re, sys +p = sys.argv[1] +s = open(p).read() +inc = " include /etc/nginx/snippets-nexarch-cors.conf;\n" +for loc in ("/auth/", "/account/"): + pat = " location %s {\n" % loc + first = s.index(pat) # erster Treffer = Block auf 8443 + after = first + len(pat) + if inc not in s[after:after + len(inc) + 1]: + s = s[:after] + inc + s[after:] +if "listen 8450 ssl;" not in s: + s = s.rstrip("\n") + """ + +# NEXARCH Web - Portal +server { + listen 8450 ssl; + http2 on; + server_name _; + ssl_certificate /etc/ssl/archivmail/archivmail.crt; + ssl_certificate_key /etc/ssl/archivmail/archivmail.key; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + + location / { + proxy_pass http://127.0.0.1:3057; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + } +} +""" +open(p, "w").write(s) +PY +if nginx -t &1; then + echo "nginx -t ok (Reload folgt nach der Firewall)" +else + cp -p "$BAK/nexarch-gui" "$NGINX_SITE"; rm -f /etc/nginx/conf.d/nexarch-cors-map.conf /etc/nginx/snippets-nexarch-cors.conf + fail "nginx -t fehlgeschlagen, Aenderung zurueckgenommen" +fi + +say "5/8 Firewall: Port 8450" +cp -p /etc/nftables.conf "$BAK/nftables.conf" +grep -q '8449, 8450' /etc/nftables.conf || sed -i 's/8448, 8449 }/8448, 8449, 8450 }/' /etc/nftables.conf +grep -q '8450' /etc/nftables.conf || fail "8450 konnte nicht in nftables.conf eingetragen werden" +nft -c -f /etc/nftables.conf /etc/systemd/system/nexarch-web-portal.service +systemctl daemon-reload + local base=$1 app=$2; shift 2 + local dir="$base/web/$app" + [ -d "$dir" ] || fail "$dir fehlt" + tar czf "$BAK/$app-next.tgz" -C "$dir" .next + rsync -a --delete --exclude node_modules --exclude .next "$SRC/web/shl/" "$base/web/shl/" + rsync -a --delete --exclude node_modules --exclude .next "$SRC/web/$app/" "$dir/" + chown -R nexarch:nexarch "$base/web/shl" "$dir" + mkdir -p "$base/.home"; chown nexarch:nexarch "$base/.home" + local lock; lock=$(sha256sum "$dir/package-lock.json" | cut -d' ' -f1) + if [ ! -d "$dir/node_modules" ] || [ "$(cat "$dir/node_modules/.nexarch-lock" 2>/dev/null)" != "$lock" ]; then + runuser -u nexarch -- env HOME="$base/.home" NPM_CONFIG_CACHE="$base/.home/.npm" bash -c "cd '$dir' && npm ci --no-audit --no-fund && echo $lock > node_modules/.nexarch-lock" "$BAK/$app-npm.log" 2>&1 \ + || { tail -5 "$BAK/$app-npm.log"; fail "npm ci $app fehlgeschlagen (Log: $BAK/$app-npm.log)"; } + fi + if [ -d "$dir/node_modules/@nexarch/shl" ] && [ ! -L "$dir/node_modules/@nexarch/shl" ]; then + rm -rf "$dir/node_modules/@nexarch/shl"; ln -s ../../../shl "$dir/node_modules/@nexarch/shl" + fi + if [ -e "$base/web/shl/node_modules" ] && [ ! -L "$base/web/shl/node_modules" ]; then + mv "$base/web/shl/node_modules" "$BAK/$app-shl-node_modules" + fi + [ -e "$base/web/shl/node_modules" ] || ln -s "../$app/node_modules" "$base/web/shl/node_modules" + if runuser -u nexarch -- env HOME="$base/.home" NPM_CONFIG_CACHE="$base/.home/.npm" "$@" bash -c "cd '$dir' && npx next build --webpack" "$BAK/$app-build.log" 2>&1; then + echo "Build $app ok" + else + tail -5 "$BAK/$app-build.log" + rm -rf "$dir/.next"; tar xzf "$BAK/$app-next.tgz" -C "$dir" + fail "Build $app fehlgeschlagen, alter Stand zurueckgestellt (Log: $BAK/$app-build.log)" + fi +} + +say "7/8 Neubau Portal und Login aus origin/main" +build_app "$INSTALL" portal NEXT_PUBLIC_CORE_API_BASE=https://$HOST:8443 NEXT_PUBLIC_LOGIN_URL=https://$HOST:8443/ NEXT_PUBLIC_TOKEN_MODULE=portal +if [ -d "$ACCOUNT/web/account" ]; then + build_app "$ACCOUNT" account NEXT_PUBLIC_PORTAL_URL=https://$HOST:8450/ + systemctl restart nexarch-web-account ` und nimmt nginx- und nft-Änderungen bei Prüffehlern zurück. +- CORS: Der Core (8443) liefert auf 131 selbst keine CORS-Header; Frontends auf anderen Ports (8444–8450) brauchen sie für `/auth/module-token`. Das Skript trägt sie in nginx ein (`/etc/nginx/conf.d/nexarch-cors-map.conf`, Ursprünge `https://192.168.1.131:8444–8450`). - Voraussetzung für Anmeldung: `nexarch-account-api` läuft (Passwort der DB-Rolle muss zur DSN in `account-api.env` passen; bei Authentifizierungsfehler beendet sich der Dienst mit Exit 2 und startet nicht neu). ## 204 (Dev/Test, Demo `nexarch-portal-live`)