forwarding

This commit is contained in:
chk
2026-06-07 07:21:30 +02:00
parent 475dfcc446
commit c04e5902ce
3 changed files with 98 additions and 67 deletions

111
README.md
View File

@@ -22,7 +22,7 @@ terminiert TLS (Let's Encrypt) und leitet an den passenden Upstream weiter.
- [Authentifizierung](#authentifizierung)
- [TLS / Let's Encrypt](#tls--lets-encrypt)
- [Container & Betrieb](#container--betrieb)
- [Neuen Dienst hinzufügen](#neuen-dienst-hinzufügen)
- [Eine neue Seite ins Portal aufnehmen](#eine-neue-seite-ins-portal-aufnehmen)
- [Dateiübersicht](#dateiübersicht)
---
@@ -134,7 +134,7 @@ Dienst im iFrame. Bild: [`doc/Portal.png`](doc/Portal.png) · Quellen:
> automatisch aus `forwarding.conf` erzeugt. Ein neuer Dienst in
> `forwarding.conf` taucht also erst dann in der Navigationsleiste auf, wenn er
> auch ins `services`-Array eingetragen wird (siehe
> [Neuen Dienst hinzufügen](#neuen-dienst-hinzufügen)).
> [Eine neue Seite ins Portal aufnehmen](#eine-neue-seite-ins-portal-aufnehmen)).
Aktuell im Portal verlinkte Dienste (`public/app.js`):
@@ -353,24 +353,105 @@ docker logs appServer_PortalUI | grep connect-proxies
---
## Neuen Dienst hinzufügen
## Eine neue Seite ins Portal aufnehmen
1. **Zeile in `forwarding.conf`** ergänzen, z. B.:
Zwei Fragen entscheiden, wie eine Seite angebunden wird: **(1) Wie erreicht der
nginx-Container das Backend?** und **(2) unter welcher Subdomain** soll es laufen?
### Wie das Backend erreichbar ist zwei Wege
- **A) Direkt** das Backend ist vom nginx-Container aus erreichbar:
- **lokaler Container** im Docker-Netz `appRobotNet` → per Container-Name,
z. B. `http://open-webui:8080`.
- **Gerät im LAN** → per **IP**, z. B. `http://192.168.0.210:9183`.
- ⚠️ **Kein `.local`/mDNS!** Namen wie `thinkcentre.local` löst der Container
**nicht** auf (Docker-DNS kann kein mDNS) → der Dienst wird zum 503-Platzhalter.
Immer IP **oder** Tunnel verwenden.
- **B) Über den SSH-Reverse-Tunnel** das Backend steht hinter NAT/Firewall
(Roboter-Pi, ThinkCentre, InformatikWeb) und hat keine Route ins Server-LAN. Es
„meldet sich“ per autossh beim Server an und wird dort auf einem festen Port
erreichbar.
### Hintergrund: der SSH-Reverse-Tunnel
Auf der **Geräteseite** (z. B. im Portainer-Stack des Roboters) läuft ein
autossh-Container `appRobot_Tunnel`, der eine Dauerverbindung zu
`tunnel@server.schooltech.ch -p 2255` (= Container `appServer_TunnelHead`)
aufbaut. Pro Dienst eine Zeile:
```
-R 0.0.0.0:<HubPort>:<container>:<port>
```
Bedeutung: „Öffne am TunnelHead den Port `<HubPort>` und leite ihn an
`<container>:<port>` auf der Geräteseite weiter.“ Damit wird `<container>:<port>`
(Geräteseite) für nginx als **`appServer_TunnelHead:<HubPort>`** erreichbar und
`forwarding.conf` proxyt genau dorthin.
**Aktuelle Tunnel-Belegung** (aus dem autossh-Command des `appRobot_Tunnel`-Stacks):
| HubPort | → Geräteseite | Portal-Subdomain |
|---|---|---|
| 9703 | `portainer:9000` | `tcPortainer` |
| 9710 | `appRobot_Control:10010` | `tcControl` |
| 9712 | `appRobot_Simulation:1003` | `tcSimulation` |
| 9725 | `appRobot_AccessBase:443` | `robotBase` |
| 9726 | `appRobot_AccessEllbow:443` | `robotEllbow` |
| 9727 | `appRobot_AccessHand:443` | `robotHand` |
| 9743 | `AppRobotWebcam:8444` | `robotVideo` |
| 9744 | `appRobot_CodeServer:8443` | `robotVSCode` |
| 9780 | `appRobot_guacamole:8080` | `tcGuac` |
| 9793 | `appRobot_Homing:2093` | `robotHoming` |
| 9798 | `appRobot_Driver:2098` | `robotDriver` |
> Konvention der HubPorts: **81xx → RP3/SCARA**, **97xx → ThinkCentre/Roboter**,
> **99xx → InformatikWeb**. Das `0.0.0.0:` setzt voraus, dass am TunnelHead-sshd
> `GatewayPorts clientspecified` aktiv ist (ist es).
### Rezept A: neue Seite **über den Tunnel**
1. **Tunnel öffnen** geräteseitig im autossh-Command eine `-R`-Zeile ergänzen
(freien HubPort wählen), z. B.:
```
meinDienst.server.schooltech.ch http://appServer_TunnelHead:9999 redirect true false
-R 0.0.0.0:9750:appRobot_NeuerDienst:8080 \
```
2. **DNS:** sicherstellen, dass die Subdomain auf den Server zeigt
(Wildcard `*.server.schooltech.ch` oder A-Record).
3. **Zertifikat** holen Domain in `letsEncrypt.sh` aufnehmen und Skript laufen
lassen (sonst überspringt `connect-proxies.sh` den vHost).
4. **nginx neu starten:** `docker restart appServer_PortalUI`.
5. **Optional im Portal sichtbar machen:** Eintrag im `services`-Array in
`public/app.js` ergänzen:
Stack neu deployen (Portainer). Der Dienst ist nun `appServer_TunnelHead:9750`.
2. **`forwarding.conf`** (Server) Zeile ergänzen; das Schema muss zu dem passen,
was das Backend spricht:
```
neuerdienst.server.schooltech.ch http://appServer_TunnelHead:9750 redirect true false
```
3. **Zertifikat** Domain in `letsEncrypt.sh` aufnehmen (**mit `--cert-name`!**)
und ausführen; ohne Zertifikat überspringt `connect-proxies.sh` den vHost.
4. **nginx neu starten:** `docker restart appServer_PortalUI`, dann im Log prüfen:
`[+] … Zertifikat OK … Erzeuge 443`.
5. **Optional im Portal-Menü zeigen:** Eintrag im `services`-Array in
`public/app.js`:
```js
{ id: "mein", name: "Mein Dienst", url: "https://meinDienst.server.schooltech.ch/" }
{ id: "neu", name: "Neuer Dienst", url: "https://neuerdienst.server.schooltech.ch/" }
```
6. **Optional Login erzwingen:** in `forwarding.conf` als 8. Spalte
`… server.schooltech.ch 443 true` setzen.
6. **Optional Login erzwingen:** in `forwarding.conf` 8. Spalte `… 443 true`.
### Rezept B: neue Seite **direkt** (lokaler Container / LAN-IP)
Wie A, nur **Schritt 1 entfällt**. Der Upstream in `forwarding.conf` zeigt direkt
auf den Container-Namen oder die LAN-IP (niemals `.local`):
```
neuerdienst.server.schooltech.ch http://192.168.0.50:8080 redirect true false
```
(Rest identisch: Zertifikat → Restart → optional `app.js`/Auth.)
### Eine Seite entfernen
1. Zeile in `forwarding.conf` löschen (oder mit `#` auskommentieren) und ggf. den
`app.js`-Eintrag entfernen → `docker restart appServer_PortalUI`.
2. Falls über Tunnel: die `-R`-Zeile aus dem `appRobot_Tunnel`-Stack entfernen und
neu deployen.
3. Optional Zertifikat aufräumen: `certbot delete --cert-name <domain>`.
> **Spalten-Kurzreferenz** der `forwarding.conf`:
> `server_name upstream_url http_behavior websockets verify_upstream_tls [cert_domain] [listen_port] [auth_required]`
> — Details siehe [`forwarding.conf` das Herzstück](#forwardingconf--das-herzstück).
---