# appServer Portal UI
Übersichts-Webserver für **`server.schooltech.ch`**. Er fasst eine Reihe von
Web-Diensten (Roboter-Steuerungen, Guacamole-Remotedesktops, Portainer,
VS Code, Nextcloud …) unter **einer Domain** zusammen und macht sie über
sprechende Subdomains erreichbar.
Alle Dienste laufen als Subdomain von `.server.schooltech.ch` – egal ob sie
auf dem Server selbst, auf einem Gerät im LAN oder hinter einem SSH-Tunnel
stehen. Ein nginx-Reverse-Proxy nimmt jede Subdomain auf 443 entgegen,
terminiert TLS (Let's Encrypt) und leitet an den passenden Upstream weiter.
---
## Inhalt
- [Architektur-Übersicht](#architektur-übersicht)
- [Die Portal-Seite (`server.schooltech.ch`)](#die-portal-seite-serverschooltechch)
- [Die Dienste / Subdomains](#die-dienste--subdomains)
- [`forwarding.conf` – das Herzstück](#forwardingconf--das-herzstück)
- [`connect-proxies.sh` – Konfig-Generator](#connect-proxiessh--konfig-generator)
- [Authentifizierung](#authentifizierung)
- [TLS / Let's Encrypt](#tls--lets-encrypt)
- [Container & Betrieb](#container--betrieb)
- [Neuen Dienst hinzufügen](#neuen-dienst-hinzufügen)
- [Dateiübersicht](#dateiübersicht)
---
## Architektur-Übersicht
Alles hängt unter `*.server.schooltech.ch`. Der Unterschied zwischen den
Diensten ist nicht die Domain, sondern **wohin der Upstream zeigt**:
> Bild: [`doc/Architektur.png`](doc/Architektur.png) · Vektor-Quelle:
> [`doc/Architektur.svg`](doc/Architektur.svg) (für PDF/beliebige Skalierung).
**Bausteine (Docker-Container, siehe `docker-compose.yaml`):**
| Container | Image | Rolle |
|---|---|---|
| `appServer_PortalUI` | `nginx:alpine` | Reverse-Proxy + Auslieferung der Portal-Seite (Ports 80/443) |
| `AppServerAuth` | `node:24-alpine` | Login-/Session-Service (`auth/auth.js`, Port 3000 intern) |
| `appServer_TunnelHead` | `linuxserver/openssh-server` | SSH-Hub: entfernte Geräte bauen Reverse-Tunnel hierher auf |
| `appServer_guacamole` | `abesnier/guacamole` | Lokaler Guacamole-Remotedesktop |
| `appServer_LetsEncryptFetcher` | `certbot/certbot` | Holt/erneuert die TLS-Zertifikate |
Alle Container hängen im Docker-Netzwerk **`appRobotNet`** und sprechen sich
per Container-Namen an (z. B. `appserverauth:3000`).
---
## Die Portal-Seite (`server.schooltech.ch`)
Ruft man die nackte Domain `server.schooltech.ch` auf, erscheint die
**Portal-Oberfläche** – eine schlanke Single-Page-App aus `public/`:
- **`public/index.html`** – Grundgerüst: oben eine **Navigationsleiste**
(`` mit Logo *„schooltech“*, der Service-Navigation `#services`
und einem Login/Logout-Button), darunter ein **`