die Authentifizierung von server.schooltech.ch funktioniert. Ich komme wie gewünscht nur mit aktivem 
cookie rein. 

# /etc/nginx/conf.d/default.conf
server {
    listen 80 default_server;
    listen [::]:80 default_server;

    # ACME HTTP-01 Challenge (Certbot)
    location ^~ /.well-known/acme-challenge/ {
        root /var/www/certbot;
        default_type "text/plain; charset=utf-8";
    }

    # PortalUI root
    root /usr/share/nginx/html;
    index index.html;

    # === API forwarding for Auth-Service ===
    location /api/ {
        proxy_pass http://appserverauth:3000/api/;
        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;
    }

    # === SPA routing (Portal UI) ===
    location / {
        try_files $uri $uri/ /index.html;
    }
}



Die SubDomains werden in 50-subdomains-userA.conf verwaltet. Und bei diesen Subdomains sollen einige auch nur mit aktivem cookie erreichbar sein.
Aber nicht alle. Deshalb: Eine weitere spalte in der forwarding.conf datei.

#!/bin/sh
# /docker-entrypoint.d/40-connect-proxies.sh
# Generiert pro Zeile in /etc/nginx/forwarding.conf:
#  - HTTPS vHost (Proxy oder local static) NUR wenn Zertifikate existieren
#  - optional 80->443 Redirect-Server (mit ACME-Ausnahme) bei http_behavior=redirect
# Läuft automatisch beim Containerstart (nginx:alpine EntryPoint).
#
#
#  Die Datei: connect-proxies.sh läuft, wenn nginx docker container startet

set -eu

CONF_DIR="/etc/nginx/conf.d"
LIVE_DIR="/etc/letsencrypt/live"
FWD_FILE="/etc/nginx/forwarding.conf"

HTTPS_SUFFIX="-https.generated.conf"
HTTP_REDIRECT_SUFFIX="-http-redirect.generated.conf"
GLOBALS_FILE="$CONF_DIR/_globals.generated.conf"

echo "[connect-proxies] start …"

# 0) Forwarding-Datei vorhanden?
if [ ! -f "$FWD_FILE" ]; then
  echo "[connect-proxies] WARN: $FWD_FILE fehlt – keine Proxies zu generieren."
  exit 0
fi

# 1) Globale HTTP-Kontext-Map + Resolver (idempotent)
# >>> CHANGE: Resolver NICHT hardcoden. Dynamisch aus /etc/resolv.conf ableiten, Fallback 127.0.0.11
RESOLVERS="$(awk '/^nameserver/{print $2}' /etc/resolv.conf | xargs || true)"
if [ -n "${RESOLVERS:-}" ]; then
  RESOLVER_LINE="resolver $RESOLVERS ipv6=off valid=30s;"
else
  RESOLVER_LINE="resolver 127.0.0.11 ipv6=off valid=30s;"
fi

cat > "$GLOBALS_FILE" <<NGINX
# Automatisch generiert – nicht editieren
map \$http_upgrade \$connection_upgrade {
    default upgrade;
    ''      close;
}
$RESOLVER_LINE
NGINX
# <<< END CHANGE

# 2) Alte generierte Confs entfernen
rm -f "$CONF_DIR/"*"$HTTPS_SUFFIX" 2>/dev/null || true
rm -f "$CONF_DIR/"*"$HTTP_REDIRECT_SUFFIX" 2>/dev/null || true

# 3) Zeilen verarbeiten
LINE_NO=0
while IFS= read -r RAW || [ -n "$RAW" ]; do
  LINE_NO=$((LINE_NO+1))
  # trim + CR entfernen
  LINE="$(printf '%s' "$RAW" | tr -d '\r' | sed 's/^[[:space:]]*//; s/[[:space:]]*$//')"
  [ -z "$LINE" ] && continue
  case "$LINE" in \#*) continue;; esac

  # Spalten splitten (mindestens 2 erforderlich)
  set -- $LINE
  SERVER_NAME="${1:-}"
  UPSTREAM_URL="${2:-}"
  HTTP_BEHAVIOR="${3:-redirect}"
  WEBSOCKETS="${4:-false}"
  VERIFY_TLS="${5:-false}"
  CERT_DOMAIN="${6:-$SERVER_NAME}"
  LISTEN_PORT="${7:-443}"

  if [ -z "$SERVER_NAME" ] || [ -z "$UPSTREAM_URL" ]; then
    echo "[connect-proxies] WARN(Line $LINE_NO): unvollständig -> $LINE"
    continue
  fi

  FULLCHAIN="$LIVE_DIR/$CERT_DOMAIN/fullchain.pem"
  PRIVKEY="$LIVE_DIR/$CERT_DOMAIN/privkey.pem"

  HTTPS_OUT="$CONF_DIR/${SERVER_NAME}-p${LISTEN_PORT}${HTTPS_SUFFIX}"
  HTTP_REDIRECT_OUT="$CONF_DIR/${SERVER_NAME}${HTTP_REDIRECT_SUFFIX}"

  # >>> NEW: Upstream normalisieren (Trailing Slash entfernen) + DNS-Check vorbereiten
  SANITIZED_UPSTREAM="${UPSTREAM_URL%/}"
  DNS_OK="true"
  SCHEME=""; HOST=""; PORT=""

  if [ "$SANITIZED_UPSTREAM" != "local" ]; then
    case "$SANITIZED_UPSTREAM" in
      http://*)
        URI="${SANITIZED_UPSTREAM#http://}"; SCHEME="http";  DEFAULT_PORT="80"
        ;;
      https://*)
        URI="${SANITIZED_UPSTREAM#https://}"; SCHEME="https"; DEFAULT_PORT="443"
        ;;
      *)
        echo "[connect-proxies] WARN(Line $LINE_NO): $SERVER_NAME upstream_url ungültig: '$UPSTREAM_URL' – überspringe."
        continue
        ;;
    esac
    HOSTPORT="${URI%%/*}"
    HOST="${HOSTPORT%%:*}"
    PORT="${HOSTPORT#*:}"; [ "$PORT" = "$HOSTPORT" ] && PORT="$DEFAULT_PORT"

    if command -v getent >/dev/null 2>&1; then
      if ! getent hosts "$HOST" >/dev/null 2>&1; then
        DNS_OK="false"
        echo "[connect-proxies] [-] $SERVER_NAME: DNS nicht auflösbar ($HOST) – erzeuge 503-Placeholder statt Proxy."
      fi
    else
      DNS_OK="unknown"
    fi
  fi
  # <<< END NEW

  if [ -f "$FULLCHAIN" ] && [ -f "$PRIVKEY" ]; then
    echo "[connect-proxies] [+] $SERVER_NAME: Zertifikat OK (cert_domain=$CERT_DOMAIN). Erzeuge 443 …"

    # Fall A: local (statisch, kein proxy_pass)
    if [ "$SANITIZED_UPSTREAM" = "local" ]; then
      cat > "$HTTPS_OUT" <<NGINX
# Auto-generated - 443 static site
server {
    listen ${LISTEN_PORT} ssl http2;
    listen [::]:${LISTEN_PORT} ssl http2;
    server_name $SERVER_NAME;

    ssl_certificate     $FULLCHAIN;
    ssl_certificate_key $PRIVKEY;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    root /usr/share/nginx/html;
    index index.html;

    location /api/ {
        proxy_pass http://appserverauth:3000/api/;

        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;
    }

    location / {
        try_files \$uri \$uri/ /index.html;
    }
}
NGINX

    else
      # >>> NEW: Zwei Pfade – DNS_OK=false => Placeholder; sonst Proxy mit Laufzeit-Resolver
      if [ "$DNS_OK" = "false" ]; then
        # 443 Placeholder – keine Proxy-Verbindung, saubere 503
        cat > "$HTTPS_OUT" <<NGINX
# Auto-generated - 443 placeholder (DNS failed)
server {
    listen ${LISTEN_PORT} ssl http2;
    listen [::]:${LISTEN_PORT} ssl http2;
    server_name $SERVER_NAME;

    ssl_certificate     $FULLCHAIN;
    ssl_certificate_key $PRIVKEY;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    location / {
        default_type text/html;
        return 503 "<!doctype html><html><head><meta charset='utf-8'><title>Service temporarily unavailable</title></head><body style='font-family:sans-serif;margin:3rem'><h1>\$server_name nicht erreichbar</h1><p>DNS-Auflösung fehlgeschlagen. Bitte später erneut versuchen.</p></body></html>";
    }
}
NGINX
      else
        # 443 Proxy – DNS ok/unknown: Laufzeit-Auflösung + freundlicher 503 bei Downstreams
        cat > "$HTTPS_OUT" <<NGINX
# Auto-generated - 443 reverse proxy
server {
    listen ${LISTEN_PORT} ssl http2;
    listen [::]:${LISTEN_PORT} ssl http2;
    server_name $SERVER_NAME;

    ssl_certificate     $FULLCHAIN;
    ssl_certificate_key $PRIVKEY;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    # Fehler sauber abfangen und 503 liefern (statt rohe 502/504)
    proxy_intercept_errors on;
    error_page 502 503 504 = @service_down;

    location / {
        # >>> CHANGE: variable proxy_pass -> DNS zur Laufzeit (verhindert nginx -t Crash)
        set \$target $SANITIZED_UPSTREAM;
        proxy_pass \$target;

        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_http_version 1.1;
NGINX

        if [ "$WEBSOCKETS" = "true" ]; then
          cat >> "$HTTPS_OUT" <<'NGINX'
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
NGINX
        else
          cat >> "$HTTPS_OUT" <<'NGINX'
        proxy_set_header Upgrade "";
        proxy_set_header Connection close;
NGINX
        fi

        case "$SANITIZED_UPSTREAM" in
          https://*)
            if [ "$VERIFY_TLS" = "true" ]; then
              cat >> "$HTTPS_OUT" <<'NGINX'
        proxy_ssl_verify on;
        proxy_ssl_server_name on;
NGINX
            else
              cat >> "$HTTPS_OUT" <<'NGINX'
        proxy_ssl_verify off;
        proxy_ssl_server_name on;
NGINX
            fi
          ;;
        esac

        cat >> "$HTTPS_OUT" <<'NGINX'
        client_max_body_size 50m;
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }

    location @service_down {
        default_type text/html;
        return 503 "<!doctype html><html><head><meta charset='utf-8'><title>Service temporarily unavailable</title></head><body style='font-family:sans-serif;margin:3rem'><h1>$server_name nicht erreichbar</h1><p>Der Dienst ist momentan nicht verfügbar. Bitte später erneut versuchen.</p></body></html>";
    }

}
NGINX
      fi
      # <<< END NEW
    fi

    # 80->443 Redirect-Server nur, wenn gewünscht
    if [ "$HTTP_BEHAVIOR" = "redirect" ]; then
      cat > "$HTTP_REDIRECT_OUT" <<NGINX
# Auto-generated – 80->443 redirect for $SERVER_NAME
server {
    listen 80;
    listen [::]:80;
    server_name $SERVER_NAME;

    # ACME-Ausnahme
    location ^~ /.well-known/acme-challenge/ {
        root /var/www/certbot;
        default_type "text/plain; charset=utf-8";
    }

    location / {
        return 301 https://\$host\$request_uri;
    }
}
NGINX
    else
      # Sicherstellen, dass kein alter Redirect liegen bleibt
      rm -f "$HTTP_REDIRECT_OUT" 2>/dev/null || true
    fi

  else
    echo "[connect-proxies] [-] $SERVER_NAME: keine Zertifikate (cert_domain=$CERT_DOMAIN). Entferne evtl. alte Confs."
    rm -f "$HTTPS_OUT" "$HTTP_REDIRECT_OUT" 2>/dev/null || true
  fi

done < "$FWD_FILE"

echo "[connect-proxies] nginx -t …"
nginx -t
echo "[connect-proxies] done."

# server_name                            upstream_url                  http_behavior  websockets  verify_upstream_tls  [cert_domain]

#fluidncRed.server.schooltech.ch http://appServer_TunnelHead:8120 redirect true false

# 444 → 8121 (WS/WSS)
# fluidncRedWs.server.schooltech.ch http://appServer_TunnelHead:8121 redirect true false fluidncRedWs.server.schooltech.ch 444
#server.schooltech.ch                     local            static       false       false
server.schooltech.ch local redirect false false server.schooltech.ch 443
tcPortainer.server.schooltech.ch  http://thinkcentre.local:9000  redirect  true  false
tcGuac.server.schooltech.ch  http://thinkcentre.local:9000  redirect  true  false
 
#inf InformatiWeb  ist per Tunnel angeschlossen. Soll auf 97xx Ports gehen
infPortainer.server.schooltech.ch  http://appServer_TunnelHead:9903  redirect  true  false
infGuac.server.schooltech.ch  http://appServer_TunnelHead:9980  redirect  true  false
 
#RP5 ist "Lokal" der Server
rp5Guac.server.schooltech.ch  http://appServer_guacamole:8080  redirect  true  false
rp5Portainer.server.schooltech.ch  http://portainer:9000  redirect  true  false
 
 
#RP3 ist  Raspi für die Scara-Robots, per Tunnel angeschlossen. Er hat 81xx Ports am TunnelHead
rp3Portainer.server.schooltech.ch  http://appServer_TunnelHead:8100  redirect  true  false
rp3Guac.server.schooltech.ch  http://appServer_TunnelHead:8180  redirect  true  false
fluidncRed.server.schooltech.ch http://appServer_TunnelHead:8120 redirect true false 
fluidncWhite.server.schooltech.ch https://appServer_TunnelHead:8104 redirect true false 

============
Fragen:
1) ist der aufbau einigermassen klar?

2) weisst du, wo die User-Authentifizierung eingebaut wereden könnte?

3) Ist es sinnvoll, das in der forwaring.conf abzuspeichern? 