Stabiler machen

This commit is contained in:
chk
2026-06-06 18:08:24 +02:00
parent 263e9b4565
commit d83cf32bfa
4 changed files with 34 additions and 6 deletions

View File

@@ -34,8 +34,8 @@ Diensten ist nicht die Domain, sondern **wohin der Upstream zeigt**:
![Architektur-Übersicht](doc/Architektur.svg) ![Architektur-Übersicht](doc/Architektur.svg)
> Diagramm-Quelle: [`doc/Architektur.svg`](doc/Architektur.svg) (daraus lässt > Diagramm-Quelle: [`doc/Architektur.svg`](doc/Architektur.svg) — auch als
> sich bei Bedarf eine PDF/PNG erzeugen). > [`doc/Architektur.png`](doc/Architektur.png) (für Viewer ohne SVG-Support).
**Bausteine (Docker-Container, siehe `docker-compose.yaml`):** **Bausteine (Docker-Container, siehe `docker-compose.yaml`):**
@@ -77,8 +77,8 @@ Ruft man die nackte Domain `server.schooltech.ch` auf, erscheint die
![Portal-Ansicht](doc/Portal.svg) ![Portal-Ansicht](doc/Portal.svg)
*Oben die Navigationsleiste mit Logo und Dienst-Buttons, darunter der gewählte *Oben die Navigationsleiste mit Logo und Dienst-Buttons, darunter der gewählte
Dienst im iFrame. (Quelle: [`doc/Portal.svg`](doc/Portal.svg), auch als Dienst im iFrame. (Quelle: [`doc/Portal.svg`](doc/Portal.svg) auch als
[`doc/Portal.pdf`](doc/Portal.pdf).)* [`doc/Portal.png`](doc/Portal.png) und [`doc/Portal.pdf`](doc/Portal.pdf).)*
1. Seite öffnen → ist man nicht eingeloggt, zeigt der Button **„Login“**. 1. Seite öffnen → ist man nicht eingeloggt, zeigt der Button **„Login“**.
2. Login (User/Passwort) → der Auth-Service setzt ein Session-Cookie für die 2. Login (User/Passwort) → der Auth-Service setzt ein Session-Cookie für die
@@ -205,7 +205,9 @@ Läuft **automatisch beim Containerstart** des nginx-Containers (liegt als
`/docker-entrypoint.d/40-connect-proxies.sh`). Pro `forwarding.conf`-Zeile: `/docker-entrypoint.d/40-connect-proxies.sh`). Pro `forwarding.conf`-Zeile:
1. **Globale Map + Resolver** schreiben (`_globals.generated.conf`) nötig für 1. **Globale Map + Resolver** schreiben (`_globals.generated.conf`) nötig für
WebSockets und für die DNS-Auflösung der Upstreams zur Laufzeit. WebSockets und für die DNS-Auflösung der Upstreams zur Laufzeit. Außerdem ein
**443-Default-Server** (`00-default-server.generated.conf`), der unbekanntes
SNI per `ssl_reject_handshake` abweist (siehe Hinweis unten).
2. **Alte generierte Configs** löschen (`*-https.generated.conf`, 2. **Alte generierte Configs** löschen (`*-https.generated.conf`,
`*-http-redirect.generated.conf`). `*-http-redirect.generated.conf`).
3. Pro Dienst eine vHost-Datei erzeugen mit Fallunterscheidung: 3. Pro Dienst eine vHost-Datei erzeugen mit Fallunterscheidung:
@@ -215,7 +217,8 @@ Läuft **automatisch beim Containerstart** des nginx-Containers (liegt als
optional `proxy_ssl_verify`, optional `auth_request`-Schutz. optional `proxy_ssl_verify`, optional `auth_request`-Schutz.
- **DNS nicht auflösbar** → statt Proxy ein **503-Platzhalter** („Service - **DNS nicht auflösbar** → statt Proxy ein **503-Platzhalter** („Service
nicht erreichbar“), damit nginx trotzdem startet. nicht erreichbar“), damit nginx trotzdem startet.
- **Kein Zertifikat vorhanden** → vHost wird **übersprungen** (keine 443-Conf). - **Kein Zertifikat vorhanden** → vHost wird **übersprungen** (keine 443-Conf);
solche Anfragen fängt der 443-Default-Server ab (siehe Hinweis unten).
- Bei `http_behavior = redirect` zusätzlich ein **80→443-Redirect** (mit - Bei `http_behavior = redirect` zusätzlich ein **80→443-Redirect** (mit
Ausnahme für die ACME-Challenge). Ausnahme für die ACME-Challenge).
4. Abschließend **`nginx -t`** zur Syntaxprüfung. 4. Abschließend **`nginx -t`** zur Syntaxprüfung.
@@ -223,6 +226,14 @@ Läuft **automatisch beim Containerstart** des nginx-Containers (liegt als
So ist das System robust: fehlt ein Zertifikat oder ein Backend, fällt nur der So ist das System robust: fehlt ein Zertifikat oder ein Backend, fällt nur der
betroffene Dienst aus nginx selbst läuft weiter. betroffene Dienst aus nginx selbst läuft weiter.
> **Anti-Leak / Default-Server:** Ohne expliziten Default bedient nginx eine
> Anfrage mit unbekanntem `server_name` mit dem *ersten* 443-Block (alphabetisch
> das war `ai.server.schooltech.ch`). Damit eine Domain ohne passenden vHost
> (z. B. fehlendes Zertifikat) **nicht still** bei einem fremden Dienst landet,
> erzeugt das Skript einen Catch-all `listen 443 ssl default_server;
> ssl_reject_handshake on;` unbekanntes SNI bekommt einen sauberen TLS-Abbruch.
> `server.schooltech.ch` & Co. treffen ihren eigenen vHost weiterhin per SNI-Match.
> **Aktiver Pfad vs. Referenz:** Die vHosts werden zur Laufzeit von > **Aktiver Pfad vs. Referenz:** Die vHosts werden zur Laufzeit von
> `connect-proxies.sh` aus `forwarding.conf` erzeugt. Die statischen Dateien in > `connect-proxies.sh` aus `forwarding.conf` erzeugt. Die statischen Dateien in
> `nginxPages/` sind **nicht** in `docker-compose.yaml` gemountet und dienen nur > `nginxPages/` sind **nicht** in `docker-compose.yaml` gemountet und dienen nur

View File

@@ -40,6 +40,23 @@ map \$http_upgrade \$connection_upgrade {
$RESOLVER_LINE $RESOLVER_LINE
NGINX NGINX
# 1b) Default-Server für 443: weist unbekanntes/leeres SNI sauber ab,
# statt es an den alphabetisch ersten vHost zu "vererben" (Anti-Leak).
# Greift auch dann, wenn einer Domain das Zertifikat fehlt.
DEFAULT_443_FILE="$CONF_DIR/00-default-server.generated.conf"
cat > "$DEFAULT_443_FILE" <<'NGINX'
# Automatisch generiert nicht editieren
# Fängt alle HTTPS-Verbindungen ab, deren SNI auf keinen echten vHost passt,
# und lehnt den TLS-Handshake ab. So landet eine unbekannte/zertifikatslose
# Domain NIE still beim ersten vHost. Braucht per ssl_reject_handshake
# bewusst KEIN eigenes Zertifikat.
server {
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
ssl_reject_handshake on;
}
NGINX
# 2) Alte generierte Confs entfernen # 2) Alte generierte Confs entfernen
rm -f "$CONF_DIR/"*"$HTTPS_SUFFIX" 2>/dev/null || true rm -f "$CONF_DIR/"*"$HTTPS_SUFFIX" 2>/dev/null || true
rm -f "$CONF_DIR/"*"$HTTP_REDIRECT_SUFFIX" 2>/dev/null || true rm -f "$CONF_DIR/"*"$HTTP_REDIRECT_SUFFIX" 2>/dev/null || true

BIN
doc/Architektur.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

BIN
doc/Portal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB