# 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) - [Eine neue Seite ins Portal aufnehmen](#eine-neue-seite-ins-portal-aufnehmen) - [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**: Architektur-Übersicht: Internet → nginx Reverse-Proxy (appServer_PortalUI) → Subdomains, gruppiert nach Upstream-Ziel > Bild: [`doc/Architektur.png`](doc/Architektur.png) · Vektor-Quelle: > [`doc/Architektur.svg`](doc/Architektur.svg) (für PDF/beliebige Skalierung).
Dieselbe Übersicht als ASCII-Text ```text Internet (HTTPS :443 / HTTP :80) │ ┌────────────────────────────────────────────────┐ │ nginx Reverse-Proxy (Container: appServer_PortalUI) │ ein vHost pro Subdomain *.server.schooltech.ch │ TLS-Terminierung (Let's Encrypt) · 80→443 Redirect └────────────────────────────────────────────────┘ │ ┌───────────────┬───────────┼──────────────┬────────────────────┐ ▼ ▼ ▼ ▼ server. rp5*. nextcloud. inf*/rp3*/tc*/robot*/fluidnc* schooltech.ch schooltech. schooltech. .server.schooltech.ch Portal-UI lokale Gerät im LAN über SSH-Tunnel-Hub (diese App) Container (direkte IP) appServer_TunnelHead │ │ │ │ ▼ ▼ ▼ ▼ public/ appServer_ 192.168.0.210 appServer_TunnelHead (SSH-Reverse-Tunnels) index.html guacamole / ├─ 99xx InformatikWeb (inf*) + Auth-API portainer ├─ 81xx RP3/SCARA (rp3*, fluidnc*) └─ 97xx ThinkCentre (tc*, robot*) ```
**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 **`