Skip to content
Snippets Groups Projects
Select Git revision
  • 2df2a68b99d70a77fae96d7b2a1ef8b3d2073556
  • 2025ss default
  • 2024ss
  • 2023ss
  • 2022ss
  • 2021ss
  • 2020ss
  • 2019ss
  • 2018ss
9 results

add-01.c

Blame
  • online-werkzeuge-admin.tex 44.97 KiB
    % online-werkzeuge-admin.pdf - Instructions For Administrating Online Tools
    % Copyright (C) 2020  Peter Gerwinski <https://www.peter.gerwinski.de>
    %
    % This document is free software: you can redistribute it and/or
    % modify it either under the terms of the Creative Commons
    % Attribution-ShareAlike 3.0 License, or under the terms of the
    % GNU General Public License as published by the Free Software
    % Foundation, either version 3 of the License, or (at your option)
    % any later version.
    %
    % This document is distributed in the hope that it will be useful,
    % but WITHOUT ANY WARRANTY; without even the implied warranty of
    % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    % GNU General Public License for more details.
    %
    % You should have received a copy of the GNU General Public License
    % along with this document.  If not, see <http://www.gnu.org/licenses/>.
    %
    % You should have received a copy of the Creative Commons
    % Attribution-ShareAlike 3.0 Unported License along with this
    % document.  If not, see <http://creativecommons.org/licenses/>.
    
    \documentclass[12pt,a4paper]{article}
    
    \usepackage{pgscript}
    \setcounter{secnumdepth}{0}
    
    \newcommand{\sep}{~$\cdot$~}
    \newcommand{\mylicense}{CC-by-sa (Version 3.0) oder GNU GPL (Version 3 oder höher)}
    
    \lstset{basicstyle=\color{blendedblue},
            language=bash,
            captionpos=b,
            gobble=4,
            xleftmargin=1em,
            columns=fullflexible,
            moredelim=**[is][\color{darkred}]{¡}{¿}}
    \lstdefinestyle{terminal}{basicstyle=\small\ttfamily\color{darkgreen},
                              language={},
                              columns=fixed,
                              moredelim=**[is][\color{darkred}]{¡}{¿},
                              moredelim=**[is][\color{blendedblue}]{°}{¿},
                              moredelim=**[is][\sffamily\it\lstset{columns=fullflexible}]{²}{¿}}
    \lstdefinestyle{cmd}{basicstyle=\small\ttfamily\color{darkred},
                         language={},
                         columns=fixed,
                         moredelim=**[is][\color{darkgreen}]{¡}{¿},
                         moredelim=**[is][\color{blendedblue}]{°}{¿},
                         moredelim=**[is][\sffamily\it\lstset{columns=fullflexible}]{²}{¿}}
    
    \newcommand{\shorttextarrow}{{\boldmath $\rightarrow$}}
    
    \begin{document}
    
      \makebox(0,0.005)[tl]{\includegraphics[scale=0.72]{logo-hochschule-bochum-cvh-text-v2.pdf}}\hfill
      \makebox(0,0)[tr]{\includegraphics[scale=0.5]{logo-hochschule-bochum.pdf}}
      \par\bigskip\bigskip
      \begin{center}
        \Large
        Anleitung
        \par\smallskip
        \Huge\textbf{Aufsetzen von Online-Werkzeugen}
        \par\medskip
        \Large
        für Lehrveranstaltungen und Konferenzen
      \end{center}
    
      \section{Übersicht}
    
      Im ersten Teil dieser Anleitung (\gitfile{ow}{}{online-werkzeuge.pdf})
      wurden die Werkzeuge \newterm{Mumble}, \newterm{noVNC\/}
      und \newterm{OpenMeetings\/} aus Sicht der Teilnehmenden vorgestellt,
      im zweiten Teil (\gitfile{ow}{}{online-werkzeuge-extra.pdf}) dann
      \newterm{TightVNC\/} und \newterm{PuTTY\/} aus Sicht der Vortragenden.
    
      Dieser dritte Teil der Anleitung soll IT-Verantwortliche dabei unterstützen,
      die von uns eingesetzten Online-Werkzeuge auch bei sich aufzusetzen.
      \strong{Diese Anleitung ist keine Einführung
      und keine Schritt-für-Schritt-Installationsanleitung.}
      Wir setzen vielmehr voraus, daß Sie \strong{mit der Administration
      Ihres GNU/Linux-Servers vertraut} sind und in der Lage,
      online in englischer Sprache vorliegende Installationsanleitungen umzusetzen.
    
      Diese Anleitung bezieht sich auf Debian GNU/Linux, Version 10 (Buster).
      Wenn Sie mit einer anderen Distribution arbeiten,
      ersetzen Sie nötigenfalls z.\,B.\ \lstinline[style=cmd]{apt}
      durch Ihren Paket-Manager, z.\,B.\ \lstinline[style=cmd]{yum}.
    
      \section{Warum gerade diese Online-Werkzeuge?}
    
      Die Medien sind voll von Berichten über Online-Werkzeuge,
      die den Menschen helfen, einander auch bei physikalischem Abstand nahe zu bleiben.
      Nicht ganz so häufig sind die Analysen dieser Werkzeuge
      unter Gesichtspunkten wie Datenschutz und Privatsphäre.
      Nur am Rande wird gelegentlich erwähnt,
      daß Personen, die auf Datenschutz und Privatsphäre Wert legen,
      ja stattdessen GNU/Linux und freie Software (Open Source) verwenden könnten.
    
      Genau darum geht es hier.
    
      Alle in den ersten beiden Anleitungen beschriebenen Werkzeuge -- \term{Mumble},
      \term{OpenMeetings}, \term{TightVNC}, \term{noVNC\/} und \term{PuTTY\/} --
      \emph{sind} freie Software. Insbesondere haben Sie das Recht,
      die Software bis hin zur Quelltextebene zu analysieren und sicherzustellen,
      daß sie wirklich nur das tut, wofür sie gedacht ist, und keine Hintertür enthält.
      Wenn Sie diese Werkzeuge für Ihre Organisation
      auf einem Server Ihrer Organisation in Ihrer Eigenschaft als Admin
      Ihrer Organisation installieren, ist dies die bestmögliche Garantie
      für Datenschutz und Privatsphäre, die es bei Online-Kommunikationswerkzeugen
      überhaupt geben kann.
    
      Wenn man vorschlägt, diese Werkzeuge zu benutzen, hört man häufig:
      "`Ja, aber die kommerziellen Werkzeuge sind doch viel einfacher in der Benutzung,
      haben mehr Möglichkeiten und sind stabiler."'
      Dieser Argumentation haben wir folgendes entgegenzusetzen:
      \begin{itemize}
        \item
          Auch freie Software kann kommerziell sein.
          Wenn Sie jemanden dafür bezahlen, Ihnen die Software schlüsselfertig
          zu installieren, Sie darin zu schulen und Ihnen Telefon-Support zu leisten,
          erhalten Sie in der Regel sogar besseren Service als bei proprietären
          (nicht-freien, "`Closed Source"') Produkten.
          Diese Dienstleistung hat dann zwar sicherlich auch
          einen angemessenen Preis in Euro, aber zumindest
          bezahlen Sie nicht mit Ihren privaten Daten und/oder Firmengeheimnissen.
        \item
          Wir haben einige proprietäre Online-Kommunikationswerkzeuge ausprobiert
          und können das oft behauptete Plus an Funktionsumfang und Stabilität
          \emph{unter gleichen Bedingungen\/} nicht bestätigen.
          (So darf man zum Beispiel ein Web-Interface
          nur mit einem anderen Web-Interface vergleichen,
          nicht jedoch mit einer installierten Software.)
          Ob etwas korrekt funktioniert oder nicht und ob es viel oder wenig kann,
          hängt von vielen Faktoren ab, aber nicht unmittelbar von der Lizenz.
        \item
          Ein Werkzeug, das Sie ausspioniert, weiß naturgemäß mehr über Sie
          als eins, das Ihre informationelle Selbstbestimmung respektiert.
          Ein SSH-Tunnel, den Sie selbst konfigurieren müssen, ist besser
          als eine Anwendung, die ungefragt "`nach Hause telefoniert"'.
          Der einmalig etwas höhere Aufwand bei der Installation ist nun mal
          der Preis für mehr Datenschutz und Privatsphäre.
          Die Situation ist vergleichbar mit dem Sicherheitsgurt im PKW:
          Ohne Gurt mag es komfortabler sein, aber mit Gurt ist es sicherer.
      \end{itemize}
      Für weitere Details siehe den Artikel
      \emph{Nachhaltige Online-Werkzeuge für Home Office und Lehre}
      in der Datei \gitfile{ow}{}{online-werkzeuge-nachhaltig.pdf}.
    
      \bigbreak
    
      Neben den in diesen Anleitungen vorgeschlagenen freien Werkzeugen
      können wir im Kontext der Online-Kommunikation noch die folgenden empfehlen:
      \begin{itemize}
        \item
          \newterm{BigBlueButton\/} ist ein Online-Konferenz-Werkzeug
          mit einem ähnlichem Funktionsumfang wie \term{OpenMeetings}.
          In unseren Tests war es hinsichtlich Audio-Übertragung und
          Desktop-Sharing stabiler als \term{OpenMeetings\/};
          es erreicht hingegen nicht die Klangqualität von \term{Mumble}.
        \item
          \newterm{NextCloud\/} ist ein bewährtes Werkzeug für den Austausch von Dateien
          und hat auch eine Funktion für Online-Konferenzen.
        \item
          \newterm{Jitsi Meet\/} ist ein sehr einfach zu bedienendes Werkzeug
          für Online-Konferenzen, an denen man auch per Telefon teilnehmen kann.
          In unseren Tests erreichte es nicht die Klangqualität von \term{Mumble}
          und war auch "`nur"' bis zu ca.\ 10 Teilnehmenden stabil.
          Je nach Einsatzzweck kann es jedoch sehr nützlich sein.
        \item
          \newterm{OBS\/} ist eine Software für Live-Filmaufnahmen und Live-Streaming.
        \item
          \newterm{kdenlive} ist eine Software zum Bearbeiten von Filmen
          (Schnitte, Übergänge etc.).
        \item
          \newterm{VLC\/} kann Filme und Kamerabilder nicht nur wiedergeben,
          sondern auch streamen. In Kombination mit \newterm{Icecast\/}
          wird daraus eine Online-Sendestation.
        \item
          \newterm{GitLab\/} ist ein Web-Interface für \newterm{Git}.
        \item
          Für den öffentlichen Online-Chat ist \newterm{IRC\/}
          nach wie vor eine interessante Option.
          Es gibt dafür auch zahlreiche Web-Interfaces.
      \end{itemize}
      \dots\ und natürlich kennen Sie \newterm{SSH}, \newterm{GNU Screen}
      und \newterm{ytalk} für die Online-Kommunikation zwischen Experten.
    
      \section{Let's Encrypt}
    
      Für sichere Verbindungen mittels TLS
      benötigen die Online-Dienste X.509-Zertifikate.
      Wir zeigen hier, wie man mit Hilfe von \newterm{Let's Encrypt}
      sichere Zertifikate erhält.
    
      \term{Let's Encrypt\/} stellt ein Zertifikat dann aus,
      wenn man nachweisen kann, die Kontrolle über eine Domain zu haben.
      Wir benutzen für diesen Nachweis die DNS-Methode.
      Dabei stellt \term{Let's Encrypt\/} eine DNS-Anfrage an unseren Server,
      die wir mit einem unmittelbar zuvor von \term{Let's Encrypt\/}
      erhaltenen Zufalls-String beantworten müssen.
      Dies wird durch eine spezielle Sotware automatisiert,
      den \term{Let's Encrypt\/}-Client (\file{certbot}).
    
      In unserem Beispiel läuft der DNS-Server auf einem Rechner \file{comm-0},
      der \term{Let's Encrypt\/}-Client hingegen auf einem anderen Rechner \file{main-1},
      auf dem das Zertifikat tatsächlich benötigt wird.
    
      Die Installation erfolgt mittels:
      \begin{lstlisting}[style=terminal]
        root@main-1:~# ¡apt install certbot¿
      \end{lstlisting}
      Die Konfiguration erfolgt in der Datei \file{/etc/letsencrypt/cli.ini}:
      \begin{lstlisting}[style=terminal]
        root@main-1:~# ¡cat /etc/letsencrypt/cli.ini¿
        # Because we are using logrotate for greater flexibility,
        # disable the internal certbot logrotation.
        max-log-backups = 0
    
        email = ¡$SOME_E_MAIL_ADDRESS¿
    
        authenticator = manual
        preferred-challenges = dns
        domains = ¡$HOST1¿, ¡$HOST2¿
    
        expand = True
        manual-public-ip-logging-ok = True
        preferred-challenges = dns
        manual-auth-hook = /usr/local/sbin/letsencrypt_dns_update
        post-hook = /usr/local/sbin/letsencrypt-install-new-keys
      \end{lstlisting}
      Hierbei steht
      \begin{itemize}
        \item
          \lstinline[style=cmd]{$SOME_E_MAIL_ADDRESS} für eine E-Mail-Adresse,
          an die bei Bedarf relevante Mitteilungen vom \term{Let's Encrypt\/}-Projekt
          gesendet werden sollen (z.B. ablaufende Zertifikate, die nicht erneuert wurden),
        \item
          \lstinline[style=cmd]{$HOST1} und \lstinline[style=cmd]{$HOST2}
          für die Namen beliebiger Rechner,
          für die jeweils ein Zertifikat beantragt werden soll, und
        \item
          \lstinline[style=cmd]{$DOMAIN} für die Internet-Domain,
          in der sich die Rechner \file{main-1} und \file{comm-0} befinden.
      \end{itemize}
      \strong{Hinweis: Wenn Sie diese Code-Beispiele für sich kopieren wollen,
      verwenden Sie dazu besser nicht diese PDF-Datei, sondern den zugehörigen
      \LaTeX-Quelltext (Datei
      \href{https://gitlab.cvh-server.de/pgerwinski/ow/-/raw/master/online-werkzeuge-admin.text}%
           {\file{online-werkzeuge-admin.tex}}).}
      Dadurch vermeiden Sie Probleme mit der Zeichen-Co\-dier\-ung,
      die in einer PDF-Datei teilweise anders ist als in einer reinen Textdatei.
    
      Zum Aktualisieren des DNS-Records für die Teilnahme an \term{Let's Encrypt}
      werden die Programme \file{dnssec-keygen} (einmalig für die Schlüsselerzeugung)
      und \file{nsupdate} (jedesmal) benötigt.
      Die Installation dieser Programme erfolgt mittels
      \lstinline[style=cmd]{apt install bind9utils}
      bzw.\ \lstinline[style=cmd]{apt install dnsutils}.
      
      Wir erstellen zunächst im Verzeichnis \file{/etc/bind/keys}
      mit \file{dnssec-keygen} ein Schlüsselpaar:
      \begin{lstlisting}[style=terminal]
        root@main-1:/etc/bind/keys# ¡dnssec-keygen -a hmac-sha512 -n host \
                                      -b 512 main-1.$DOMAIN¿
      \end{lstlisting}
      (Auch hier muß \lstinline[style=cmd]{$DOMAIN} durch
      die von Ihnen verwendete Internet-Domain ersetzt werden.)
    
      \file{dnssec-keygen} erzeugt zwei Dateien:
      \begin{lstlisting}[style=terminal]
        root@main-1:/etc/bind/keys# ¡ls¿
        Kmain-1.¡$DOMAIN¿.+¡$aaa¿+¡$iiiii¿.key
        Kmain-1.¡$DOMAIN¿.+¡$aaa¿+¡$iiiii¿.private
      \end{lstlisting}
      Diese Dateinamen werden wir im folgenden mit \lstinline[style=terminal]{¡$KEY¿.key}
      bzw.\ \lstinline[style=terminal]{¡$KEY¿.private} abkürzen.
      (\lstinline[style=cmd]{$aaa} und \lstinline[style=cmd]{$iiiii}
      stehen für Ziffernfolgen.)
    
      Wir müssen nun dafür sorgen, daß der auf \file{main-1} erzeugte Schlüssel
      von \file{comm-0} auch akzeptiert wird.
      Hierzu tragen wir auf \file{comm-0} in die Datei \file{/etc/bind/named.conf.local}
      folgendes ein:
      \begin{lstlisting}[style=terminal]
        zone "_acme-challenge.mumble.¡$DOMAIN¿" {
                type master;
                file "/etc/bind/dynamic/db._acme-challenge.mumble.¡$DOMAIN¿";
    
                # look for dnssec keys here:
                key-directory "/etc/bind";
    
                allow-update { key main-1.¡$DOMAIN¿; };
        };
    
        include "/etc/bind/keys/key.main-1.¡$DOMAIN¿";
      \end{lstlisting}
      Inhalt der Include-Datei
      \file{/etc/bind/keys/key.main-1.\$DOMAIN}:
      \begin{lstlisting}[style=terminal]
        key main-1.¡$DOMAIN¿. {
                algorithm HMAC-SHA512;
                secret "¡$PRIVATE_KEY¿";
        };
      \end{lstlisting}
      Hierbei steht \lstinline[style=cmd]{$PRIVATE_KEY}
      für den in der Datei \file{/etc/bind/keys/\$KEY.private}
      auf dem Rechner \file{main-1} enthaltenen privaten Schlüssel,
      d.\,h.\ alles, was dort hinter \lstinline[style=terminal]{Key:} steht.
      (Der private Schlüssel ist Base64-kodiert und endet daher typischerweise
      mit mehreren Gleichheitszeichen.)
    
    %  Nach dem Erstellen des Schlüssels in \file{/etc/bind} (Kommando s.\,u.)
    %  und der Konfiguration des Rechners \file{comm-0} kann das Update erfolgen.
    
      Danach kann mit Hilfe des folgenden Shell-Skripts
      das für \term{Let's Encrypt\/} notwendige dynamische DNS-Update ausgelöst werden:
      \begin{lstlisting}[style=terminal]
        root@main-1:~# ¡cat /usr/local/sbin/letsencrypt_dns_update¿
        #!/bin/bash
        # Generate key using:
        # dnssec-keygen -a hmac-sha512 -b 512 -n host ¡main-1.$DOMAIN¿
    
        if [ -z "$CERTBOT_DOMAIN" ] || [ -z "$CERTBOT_VALIDATION" ]
        then
        echo "EMPTY DOMAIN OR VALIDATION"
        exit -1
        fi
    
        HOST="_acme-challenge"
    
        /usr/bin/nsupdate -k \
          /etc/bind/keys/¡$KEY¿.private << EOM
        server comm-0.¡$DOMAIN¿
        zone ${HOST}.${CERTBOT_DOMAIN}
        update delete ${HOST}.${CERTBOT_DOMAIN} TXT
        update add ${HOST}.${CERTBOT_DOMAIN} 300 TXT "${CERTBOT_VALIDATION}"
        send
        EOM
        echo ""
      \end{lstlisting}
      Wenn der eigene DNS-Server nicht der primäre Server für die Domain ist,
      wird das dynamische Update nicht sofort wirksam,
      sondern erst nach einem AXFR-Zonentransfer. Dadurch entstehen Verzögerungen,
      die die Authentifikation bei \term{Let's Encrypt} gefährden.
    
      Um dies zu vermeiden, müssen wir den entsprechenden DNS-Eintrag
      auf den sonst für \lstinline[style=cmd]{$DOMAIN} benutzten Servern
      auf unseren eigenen Server delegieren.
      Dies geschieht auf dem DNS-Server \file{comm-0}
      in der Datei \file{/var/lib/bind/db.\$DOMAIN}:
      \begin{lstlisting}[style=terminal]
        _acme-challenge.mumble  IN NS dns-0
      \end{lstlisting}
      (\file{dns-0} steht für dieselbe IP-Adresse wie \file{comm-0}.)
    
      Wenn wir unsere Rechner mit speziellen Namen für die angebotenen Dienste
      ansprechen möchten (z.\,B.\ \file{mumble.\$DOMAIN} anstelle von
      \file{main-0.\$DOMAIN}), geschieht dies in derselben Datei
      durch einen \lstinline[style=terminal]{CNAME}-Eintrag:
      \begin{lstlisting}[style=terminal]
        mumble                  IN CNAME        main-0
      \end{lstlisting}
      Aus Sicherheitsgründen wollen wir den UDP-Port 53 nicht allgemein
      beantworten, sondern uns eigentlich auf die Server von \term{Let's Encrypt}
      beschränken. Leider scheinen deren Anfragen von sehr vielen verschiedenen
      Servern bei Amazon zu kommen, so daß die offensichtliche Lösung mittels
      \file{iptables} nicht anwendbar ist.
    
      Als Umgehungslösung wird daher aktuell beim Durchführen der Zertifikatsanfrage
      auf \file{main-1} (durch \lstinline[style=cmd]{certbot certonly})
      kurzzeitig auf dem Firewall-Rechner mittels
      \begin{lstlisting}[style=cmd]
        iptables -I INPUT -p udp --dport 53 -j ACCEPT
      \end{lstlisting}
      die Abfrage von \file{bind} von außen erlaubt.
    
      \section{Mumble}
    
      Der Rechner, auf dem der \term{Mumble\/}-Server läuft,\\
      ist in diesem Beispiel ebenfalls \file{main-1.\$DOMAIN}.
    
      Die Installation erfolgt mittels:
      \lstinline[style=cmd]{apt install mumble-server}
    
      \term{Mumble\/} besetzt (standardmäßig) den Port 64738.\\
      Diesen müssen wir auf der Firewall freigeben.
    
      Der \term{Mumble\/}-Servers ist vorkonfiguriert (Datei: \file{/etc/mumble-server.ini}).
      Sofern Sie keine speziellen Anforderungen haben
      (z.\,B.\ mehrere Instanzen von \term{Mumble\/} auf derselben Hardware),
      können Sie diese Konfiguration direkt übernehmen.
    
      \subsection{Server-Zertifikat}
    
      Standardmäßig läuft \term{Mumble\/} mit einem selbst-signierten Zertifikat.
      Dies führt zu einem Verlust an Sicherheit und zu Warnmeldungen beim ersten Verbinden.
      Um optimale Sicherheit zu gewährleisten,
      installieren wir stattdessen das mit \term{Let's Encrypt} erzeugte Zertifikat (siehe oben)
      zusammen mit dem Schlüssel für \term{Mumble}.
      Dies geschieht mit Hilfe eines Shell-Skripts
      \file{/usr/local/sbin/letsencrypt-install-new-keys}:
      \begin{lstlisting}[style=terminal]
        #!/bin/sh
    
        install -m 644 -o root -g mumble-server \
          /etc/letsencrypt/live/mumble.¡DOMAIN¿/fullchain.pem \
          /var/lib/mumble-server/cert.pem
        install -m 640 -o root -g mumble-server \
          /etc/letsencrypt/live/mumble.¡DOMAIN¿/privkey.pem \
          /var/lib/mumble-server/privkey.pem
    
        systemctl force-reload mumble-server
      \end{lstlisting}
      (Wir verwenden hier den Server-Namen \file{mumble}
      als \lstinline[style=terminal]{CNAME} für \file{main-1}.\\
      \lstinline[style=cmd]{$DOMAIN} steht wieder für die
      Internet-Domain des Servers.)
    
      \subsection{Benutzerverwaltung}
    
      Die Benutzerverwaltung in \term{Mumble\/} erfolgt
      komplett innerhalb der Client-Software.
    
      Zu Beginn existiert lediglich der Benutzer-Zugang \file{SuperUser}.
      Neue Benutzer*innen können sich direkt mit dem \term{Mumble\/}-Server verbinden
      und dann mittels des Menüpunktes "`Self"'\,\shorttextarrow\,"`Register"'
      ihr beim Starten des \term{Mumble\/}-Clients erzeugtes
      (oder von einem anderen Rechner importiertes)
      Zertifikat mit dem aktuell verwendeten Benutzernamen verknüpfen.
    
      Mit dem \term{Mumble\/}-Client kann der \file{SuperUser}-Zugang dann genutzt werden,
      um die entsprechenden registrierten Personen
      in eine neu erstellte privilegierte Gruppe (z.\,B.\ "`Lehrende"')
      aufzunemen und diesen Rechte zu geben, die es ihnen z.\,B.\ ermöglichen,
      störende Teilnehmer*innen eines Gesprächs ggf.\ stummzuschalten
      oder auszuschließen.
    
      \section{OpenMeetings}
    
      Da die Installationsanleitungen für \term{OpenMeetings\/}
      von der Installation auf einem Ubuntu-System ausgehen
      und wir von anderen Software-Paketen her wissen,
      daß für Ubuntu vorgesehene Software u.\,U.\ nur problematisch
      auf einem Debian GNU/Linux zum Laufen zu bringen ist,
      installieren wir \term{OpenMeetings\/} in einer eigens dafür erzeugten
      virtuellen Maschine (VM), in unserem Fall auf Basis von \newterm{Xen}.
    
      Die Erzeugung der virtuellen Maschine geschieht auf dem äußeren System
      mittels:
      \begin{lstlisting}[style=terminal]
        xen-create-image --size=15Gb --swap=4096Mb --memory=4096Mb \
          --maxmem=4096Mb --dist=bionic --ip=¡$IP¿ --no-pygrub \
          --hostname=ubuntu-0.¡$DOMAIN¿ --mirror=¡$UBUNTU_MIRROR¿
      \end{lstlisting}
      (\lstinline[style=cmd]{$UBUNTU_MIRROR} steht für die URL des
      \file{packages}-Verzeichnisses eines Ubuntu-Spiegels;
      \lstinline[style=cmd]{$IP} steht für die interne IP-Adresse der VM.)
    
      Die hier beschriebene Installation folgt weitgehend der Anleitung
      \begin{quote}
        \vspace{-\bigskipamount}
        \href{https://cwiki.apache.org/confluence/display/OPENMEETINGS/Tutorials+for+installing+OpenMeetings+and+Tools?preview=/27838216/140774282/Installation%20OpenMeetings%205.0.0-M3%20on%20Ubuntu%2018.04%20LTS.pdf}%
             {\nolinkurl{https://cwiki.apache.org/confluence/display/OPENMEETINGS/Tutorials+for+}\\
              \nolinkurl{installing+OpenMeetings+and+Tools?preview=/27838216/140774282/Installation}\hspace*{-1em}\\
              \nolinkurl{\%20OpenMeetings\%205.0.0-M3\%20on\%20Ubuntu\%2018.04\%20LTS.pdf}}
        \vspace{-\bigskipamount}
      \end{quote}
      mit dem Unterschied, daß \file{ffmpeg} nicht selbst kompiliert,
      sondern aus den Paketquellen installiert wird.
    
      \subsection{Kurento Media Server}
    
      Der \newterm{Kurento-Media-Server\/} ist für die Verarbeitung von Medienströmen
      (Audio-, Video- und Screensharing-Streams) notwendig und wird von
      \term{OpenMeetings} verwendet. Damit Medienströme weitergeleitet werden können,
      obwohl sich sowohl \term{OpenMeetings} als auch i.\,d.\,R.\ die Teilnehmenden hinter
      einem NAT befinden, wird dieser so konfiguriert, daß er Zugriff auf
      einen TURN-Server besitzt.
    
      Dies geschieht durch Ergänzen der Zeile
      \begin{lstlisting}[style=terminal]
        turnURL=kurento:¡$TURN_PASSWORT¿@¡$IP¿:3478
      \end{lstlisting}
      in der Konfigurationsdatei \file{/etc/kurento/modules/kurento/WebRtcEndpoint.conf.ini}
      auf dem Rechner, auf dem \term{OpenMeetings\/} läuft (hier: VM mit Ubuntu).
      \lstinline[style=cmd]{$IP} steht hier für die von außen erreichbare IP-Adresse des TURN-Servers.
    
      \subsection{Coturn}
    
      Der für die Verwendung des \term{Kurento Media Server\/} hinter einem NAT
      notwendige \newterm{TURN-Server\/} wird außerhalb einer VM direkt auf \file{dom0}
      (siehe \url{https://en.wikipedia.org/wiki/Xen}) mittels
      \lstinline[style=cmd]{apt install coturn} installiert.
      Die verwendete Konfiguration befindet sich dort in der Datei
      \file{/etc/turnserver.conf}:
      \begin{lstlisting}[style=terminal]
        listening-port=3478
        tls-listening-port=5349
        fingerprint
        lt-cred-mech
        user=kurento:¡$TURN_PASSWORT¿
        realm=root-0.¡$DOMAIN¿
        total-quota=100
        stale-nonce
        cert=/etc/ssl/le/fullchain.pem
        pkey=/etc/ssl/le/privkey.pem
        cipher-list="ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:
                  DH+AES:ECDH+3DES:DH+3DES:RSA+AES:RSA+3DES:!ADH:!AECDH:!MD5"
        no-loopback-peers
        no-multicast-peers
        verbose
      \end{lstlisting}
      (Der Wert von \lstinline[style=terminal]{cipher-list} ist ein durchgehender String
      und darf in der Datei nicht umbrochen werden.
      Dies geschieht hier nur notgedrungen aus Platzgründen.
      \lstinline[style=cmd]{$TURN_PASSWORT} steht für das gewählte Passwort.)
    
      \subsection{Raumkonfiguration}
    
      Das Anlegen von Räumen und Benutzerkonten in \term{OpenMeetings}
      erfolgt über die Web-Oberfläche.
    
      Da wir keine einfache Möglichkeit gefunden haben,
      die Lehrenden jeweils automatisch zu Moderatoren ernennen zu lassen,
      werden diese jeweils über das hier wiedergegebene Shell-Skript
      \file{/usr/local/sbin/give\_rights\_to\_all\_lecture\_rooms}
      zu Moderatoren jeden Raumes ernannt:
      \begin{lstlisting}[style=terminal]
        #!/bin/sh
        (for user in ¡2 5 6 7 8 12 30 31 32 33 34 35¿; do
           for room in ¡$(seq 21 32)¿; do
             echo "insert into room_moderator" \
                  "(roomId, user_id) values ($room, $user);"
           done
         done) | mysql --database=open503 -B
      \end{lstlisting}
      Die Zahlen sind die Benutzer- bzw.\ Raum-IDs
      in der SQL-Datenbank von \term{OpenMeetings\/}
      und müssen Ihrer Installation entsprechend angepaßt werden.
    
      Nach Anwendung ist in der Ubuntu-VM einmalig
      \lstinline[style=cmd]{/etc/init.d/tomcat3 restart} auszuführen.
    
      \section{NoVNC}
    
      Wir installieren zunächst \term{noVNC\/} mittels
      \lstinline[style=cmd]{apt install novnc}.
    
      \subsection{systemd}
    
      Um mehrere Räume bereitstellen zu können,
      wird ein entsprechendes Skript für \file{systemd} geschrieben.
      Mit dieser Methode läuft \term{noVNC\/} dauerhaft im Hintergrund.
      (Alternativ wäre auch eine Aktivierung
      beim Kontaktaufbau zum entsprechenden TCP-Socket denkbar.)
    
      Das \file{systemd}-Skript wird auf dem Rechner \file{main-0},
      auf dem \term{noVNC\/} läuft,
      in der Datei \file{/etc/systemd/system/novnc@.service} abgelegt:
      \begin{lstlisting}[style=terminal]
        [Unit]
        Description = start noVNC service %i
        After=syslog.target network.target
    
        [Service]
        Type=simple
        User=novnc
        ExecStart = /usr/local/sbin/hsbo_novnc %i
    
        [Install]
        WantedBy=multi-user.target
      \end{lstlisting}
      Das \file{systemd}-Skript ruft ein Shell-Skript \file{hsbo\_novnc} auf,
      das sich im Verzeichnis \file{/usr/local/sbin/hsbo\_novnc} befindet
      und das eigentliche Launch-Skript von \term{noVNC\/} aufruft:
      \begin{lstlisting}
        #!/bin/bash
    
        i=$1; shift
        exec /usr/share/novnc/utils/launch.sh --listen $((6080 + $i)) \
             --vnc localhost:$((5900 + $i)) $*
      \end{lstlisting}
      In unserem Beispiel starten wir 13 Instanzen von \term{noVNC},
      durchnumeriert von 0 bis 12.
      Die Nummern sind gleichzeitig die Nummern der VNC-Server,
      auf die \term{noVNC\/} als VNC-Client zugreift.
    
      Mit dem Shell-Befehl
      \begin{lstlisting}[style=cmd]
        for i in $(seq 0 12); do \
          systemctl start novnc@$i; \
          systemctl enable novnc@$i; \
        done
      \end{lstlisting}
      starten wir diese 13 Instanzen und aktivieren sie dauerhaft,
      so daß sie nach einem Reboot wieder zur Verfügung stehen.
    
      \subsection{Apache}
    
      \term{noVNC\/} soll hinter einem Apache-Proxy bleiben.
      Zur Kommunikation werden WSS (secure Websockets) benötigt.
      Daher müssen mittels \lstinline[style=cmd]{a2enmod proxy_wstunnel proxy_http}
      die entsprechenden Module aktiviert werden.
    
      Die entsprechende Apache-Konfiguration erfolgt in der Konfigurationsdatei\\
      \file{/etc/apache2/sites-enabled/novnc.\$DOMAIN.conf}:
      \begin{lstlisting}[style=terminal]
        <VirtualHost _default_:80>
          ServerAdmin webmaster@¡$DOMAIN¿
          ServerName novnc.¡$DOMAIN¿
          ServerAlias www.novnc.¡$DOMAIN¿
    
          Redirect / https://novnc.¡$DOMAIN¿/
    
          ErrorLog ${APACHE_LOG_DIR}/novnc.¡$DOMAIN¿-error.log
          LogLevel warn
          CustomLog ${APACHE_LOG_DIR}/novnc.¡$DOMAIN¿-access.log combined
        </VirtualHost>
    
        <VirtualHost _default_:443 _default_:8443>
          ServerAdmin webmaster@¡$DOMAIN¿
          ServerName novnc.¡$DOMAIN¿
          ServerAlias www.novnc.¡$DOMAIN¿
    
          ProxyPass /websockify ws://localhost:6080/websockify
          ProxyPassReverse /websockify ws://localhost:6080/websockify
    
          ProxyPass /websock/0/ ws://localhost:6080/websockify
          ProxyPassReverse /websock/0/ ws://localhost:6080/websockify
    
          ProxyPass /websock/1/ ws://localhost:6081/websockify
          ProxyPassReverse /websock/1/ ws://localhost:6081/websockify
      \end{lstlisting}
      [\,\dots]
      \begin{lstlisting}[style=terminal]
          ProxyPass /websock/12/ ws://localhost:6092/websockify
          ProxyPassReverse /websock/12/ ws://localhost:6092/websockify
    
          ProxyPass / http://localhost:6080/
          ProxyPassReverse / http://localhost:6080/
    
          ErrorLog ${APACHE_LOG_DIR}/novnc.¡$DOMAIN¿-error.log
          LogLevel warn
          CustomLog ${APACHE_LOG_DIR}/novnc.¡$DOMAIN¿-access.log combined
          SSLEngine on
        </VirtualHost>
      \end{lstlisting}
      Dadurch wird sichergestellt, daß grundsätzlich alle Verbindungen
      verschlüsselt werden.
    
      Auf die einzelnen VNC-Kanäle kann jetzt über URLs der Form
      \begin{lstlisting}
        ¡¿https://novnc.¡$DOMAIN¿/vnc.html?host=novnc.¡$DOMAIN¿&port=443
          &path=websock/¡$CHANNEL¿/&reconnect=1&resize=scale
      \end{lstlisting}
      zugegriffen werden.
      (\lstinline[style=cmd]{$CHANNEL} steht für die Nummer des VNC-Kanals.
      Der Umbruch in der URL geschieht hier nur aus Platzgründen
      und darf natürlich nicht in dieser Form übernommen werden.)
    
      Die Optionen \lstinline{&reconnect=1&resize=scale}
      bewirken eine Vorkonfiguration des \term{noVNC\/}-Clients,
      so daß er sich bei Verbindungsabbruch automatisch wiederverbindet
      und das VNC-Bild auf die Größe des Browser-Fensters skaliert.
      Diese Konfiguration läßt sich während der Benutzung von \term{noVNC\/}
      ändern (Icon: Zahnrad-Symbol).
    
      \subsection{Lokale VNC-Server und Skalierung}
    
      Jeder Zugriff auf \term{noVNC\/} von außen
      baut eine VNC-Verbindung zum angeschlossenen VNC-Server auf.
      Um die Netzwerkverbindungen der Vortragenden nicht zu überlasten,
      leiten wir \term{noVNC\/} nicht direkt dorthin weiter,
      sondern zunächst auf einen lokal laufenden VNC-Server.
    
      Als lokalen VNC-Server verwenden wir \file{tigervncserver}.
      (Mit \file{tightvncserver} kam es bei Zugriffen durch Browser,
      in denen fehlerhafte Plug-Ins installiert waren, zu Abstürzen,
      die dazu führten, daß alle bereits angemeldeten Teilnehmenden
      aus dem System geworfen wurden.)
    
      Um auch die Netzwerkverbindungen der Betrachtenden nicht zu überlasten,
      bieten wir jeden VNC-Kanal (hier: von 1 bis 6) auf einem parallelen Kanal
      (hier: von 7 bis 12) auch in herunterskalierter Form an.
      Dies geschieht, indem wir in dem lokal laufenden VNC-Server einen
      \file{x11vnc}-Server starten, der das Bild in herunterskalierter Form exportiert.
      Ein im Vollbildmodus laufender VNC-Viewer zeigt das herunterskalierte Bild
      dann im Parallel-Kanal an. Hierfür verwenden wir \file{xtightvncviewer}.
      (Bei Verwendung von \file{xtigervncviewer} gab es Schwierigkeiten mit der Übergabe
      des Passworts für den Lesezugriff.)
    
      Dies hat den Nebeneffekt, daß sich Teilnehmende bereits anmelden können,
      bevor die Vortragenden ihre Bildschirme per VNC exportiert haben.
      Um sie im VNC-Kanal willkommen zu heißen,
      zeigen wir ihnen mittels \file{xpdf} im Vollbildmodus eine Startseite.
    
      Es müssen also wie folgt Programme installiert werden:
      \begin{lstlisting}[style=cmd]
        apt install tigervnc-standalone-server x11vnc xtightvncviewer xpdf
      \end{lstlisting}
    
      Das unten wiedergegebene Shell-Skript \file{vnc}
      startet mit dem Parameter \lstinline[style=cmd]{start}
      für alle eingetragenen Kanäle (hier: 1 bis 6) jeweils zwei \file{tigervncserver}:
      einen für die Betrachtung in voller Auflösung (hier: 1920$\times$1080)
      und einen für die Betrachtung in herunterskalierter Auflösung (hier: 960$\times$540).
    
      Danach startet das Skript für jeden VNC-Kanal ein \file{xpdf},
      das die Startseite (hier: \file{\$HOME/vnc-testbild.pdf})
      im lokalen \file{tigervncserver} des nicht skalierten Kanals anzeigt.
      Die angezeigte Seite der PDF-Datei entspricht dabei der Nummer des lokalen VNC-Servers.
    
      Außerdem startet das Skript dort einen einen \file{x11vnc}-Server,
      der das Bild herunterskaliert und auf einem eindeutig gewählten Port lokal freigibt,
      von wo aus ein weiterer \file{xtightvncviewer} es im \file{tigervncserver}
      des skalierten Kanals anzeigt.
      \begin{lstlisting}[style=terminal]
        #!/bin/sh
    
        channels=$(seq 6)
        vncserver="tigervncserver"
        vncserveroptshires="-depth 32 -geometry 1920x1080"
        vncserveroptslores="-depth 32 -geometry 960x540"
        # add "-localhost no" to make it listen on all IPs
        testfile="$HOME/vnc-testbild.pdf"
        action=help
    
        while [ -n "$1" ]; do
          case "$1" in
            "-c") channels="$2"; shift 2;;
            "-s") vncserver="$2"; shift 2;;
            "-o") vncserveroptshires="$2"; shift 2;;
            "-t") testfile="$2"; shift 2;;
            start|stop|status|help) action="$1"; shift;;
            *)    echo "$0: unknown option $1" 1>&2; exit 1;;
          esac
        done
    
        case "$action" in
    
          start)
    
            "$vncserver" :0 $vncserveroptshires
    
            for x in $channels; do
              y=$((x + 6))
              HOME=$HOME/vnc$x "$vncserver" :$x $vncserveroptshires
              HOME=$HOME/vnc$y "$vncserver" :$y $vncserveroptslores
            done
    
            sleep 1
    
            for x in $channels; do
              (HOME=$HOME/vnc$x DISPLAY=:$x \
               xpdf -fullscreen "$testfile" $x &)
              z=$((x + 9500))
              (DISPLAY=:$x HOME=~/vnc$x/.vnc \
               x11vnc -localhost -scale 1/2 -rfbport $z &)
            done
    
            sleep 10
    
            for x in $channels; do
              y=$((x + 6))
              z=$((x + 9500))
              (DISPLAY=:$y xtightvncviewer -passwd $HOME/vnc$y/.vnc/passwd \
               -depth 16 -geometry 960x540+0+0 :$z &)
            done
    
            ;;
    
          stop)
    
            "$vncserver" -kill :0
    
            for x in $channels; do
              y=$((x + 6))
              HOME=$HOME/vnc$x "$vncserver" -kill :$x
              HOME=$HOME/vnc$y "$vncserver" -kill :$y
            done
    
            ;;
    
          status)
    
            ps aux | grep -o "X.*vnc.*:[0-9][0-9]*"
    
            ;;
    
          help)
    
            echo Usage: $0 'start|stop|status|help [-c "<channels>"]' \
                 '[-s <server>] [-o <options>] [-t <testfile>]'
    
            ;;
    
        esac
      \end{lstlisting}
      Mit dem Parameter \lstinline[style=cmd]{stop} beendet das Shell-Skript
      alle lokalen VNC-Server, wodurch sich auch die lokalen VNC-Viewer
      und die lokalen \file{x11vnc}-Server automatisch beenden.
      (Weitere zulässige Parameter und deren Wirkung
      können Sie dem Shell-Skript selbst entnehmen.)
    
      Das Skript setzt voraus, daß die Unterverzeichnisse
      \file{vnc1} bis \file{vnc12} existieren und schreibbar sind,
      so daß die lokalen VNC-Server dort ihre Konfiguration ablegen können.
      Diese Konfigurationen müssen getrennt werden, um unterschiedliche Passwörter
      für den Zugriff von außen vergeben zu können.
      Diese Passwörter können Sie mit
      \begin{lstlisting}[style=cmd]
        HOME=$(pwd)/vnc$NR vncpasswd
      \end{lstlisting}
      eingeben bzw.\ ändern.
      (\lstinline[style=cmd]{$NR} steht für die Nummer des lokalen VNC-Servers,
      gleichbedeutend mit der Nummer des VNC-Kanals,
      ggf.\ um ein Offset erhöht (hier: 6) für die Version mit reduzierter Auflösung.)
      Es ist sinnvoll, für den Kanal in voller bzw.\ in reduzierter Auflösung
      jeweils das gleiche Passwort zu vergeben.
      (Symbolische Links zwischen den Konfigurarions-Verzeichnissen
      führen zu Konflikten zwischen den lokalen VNC-Servern
      und können nicht daher verwendet werden.
      Kopieren der Verzeichnisse ist hingegen unproblematisch.)
    
      Momentan starten wir das Skript \file{vnc} manuell in einer \file{screen}-Sitzung
      auf \file{main-1}. Ein automatischer Start beim Reboot des Servers
      ist natürlich ebenfalls möglich.
    
      \subsection{Anbindung an die SSH-Tunnel der Vortragenden}
    
      Bisher haben wir "`nur"' dafür gesorgt, daß Teilnehmende von außen
      auf lokale VNC-Server auf unserem Server \file{main-1} zugreifen können.
      Nun gilt es, die lokalen VNC-Server über die Startseite hinaus
      mit Inhalten zu füllen. Typischerweise sind dies die von den Vortragenden
      per VNC exportierten Bildschirminhalte. (Natürlich ist es auch möglich,
      lokale X-Clients in den lokalen VNC-Servern laufen zu lassen
      und auf diese Weise beliebige andere Inhalte anzubieten.
      Tatsächlich geschieht dies bereits in Gestalt der Startseiten.)
    
      Das hier wiedergegebene Shell-Skript \file{autoview}
      lauscht mittels \file{nmap} auf den für die SSH-Tunnel der Lehrenen
      vorgesehenen TCP-Ports. (\file{nmap} kann mit
      \lstinline[style=cmd]{apt install nmap} installiert werden.)
      Sobald der Port offen ist, startet es einen lokalen \file{xtightvncviewer}
      und übergibt über eine Pipe das von dem*der Vortragenden festgelegte
      Passwort für den Lesezugriff. (Dieses braucht nicht
      dasselbe Passwort zu sein, das für den Lesezugriff von außen verwendet wird.)
      \begin{lstlisting}[style=terminal]
        #!/bin/sh
    
        vncviewer="xtightvncviewer"
        vncopts="-viewonly -depth 32 -compresslevel 9 -quality 9 \
                 -geometry 1920x1080+0+0"
    
        log="$0.log"
        date_format="%Y-%m-%d %H:%M:%S"
    
        while true; do
          ports=$(nmap localhost -p 5913-5918 \
                  | grep "open" | cut -d '/' -f 1)
          if [ -z "$ports" ]; then
            echo "no VNC sessions offered"
            echo $(date +"$date_format"): "no VNC sessions offered" >> "$log"
          else
            for port in $ports; do
              incoming_channel=$(echo "$port" | cut -b 3-4)
              case $incoming_channel in
                13) channel=1; password="XXXXXXXX" ;;
                17) channel=2; password="XXXXXXXX" ;;
                16) channel=3; password="XXXXXXXX" ;;
                14) channel=4; password="XXXXXXXX" ;;
                15) channel=5; password="XXXXXXXX" ;;
                *)  channel=6; password="XXXXXXXX" ;;
              esac
              echo -n "$incoming_channel --> $channel: "
              echo -n $(date +"$date_format"): \
                   "$incoming_channel --> $channel: " >> "$log"
              process=$(ps aux \
                          | grep "$vncviewer.*:$incoming_channel" \
                          | grep -v "grep")
              if [ -n "$process" ]; then
                echo "vncviewer is running"
                echo "vncviewer is running" >> "$log"
              else
                echo -n "start of vncviewer ..."
                echo "start of vncviewer ..." >> "$log"
                channel_directory="$HOME/vnc$channel"
                (echo "$password" \
                   | DISPLAY=:"$channel" HOME="$channel_directory" \
                   "$vncviewer" :"$incoming_channel" -autopass $vncopts \
                     >> "$log" 2>&1) &
                sleep 1
                echo " initiated"
                echo $(date +"$date_format"): "initiated" >> "$log"
              fi
            done
          fi
          sleep 10
        done
      \end{lstlisting}
      Die Passwörter für den Lesezugriff auf die VNC-Bildschirme der Vortragenden
      sind in dem Shell-Skript zusammen mit den jeweils zugeordneten Port-Nummern
      für die SSH-Tunnel im Klartext abgelegt.
      (In diesem Beispiel lauten die Portnummern für die SSH-Tunnel \file{5913}
      bis \file{5918} und sind nicht fortlaufend mit den VNC-Kanälen.
      Dies hat sich bei der Einführung des Systems so ergeben,
      ließe sich aber auf beliebige Port-Nummern ändern.)
    
      Auch das Skript \file{autoview} starten wir z.\,Zt.\ manuell
      in einer \file{screen}-Sitzung auf \file{main-1}.
      Auch hier wäre natürlich ein automatischer Start beim Reboot des Servers
      ebenfalls möglich.
    
      \subsection{Konfiguration der SSH-Tunnel für die Vortragenden}
    
      Auf dem Server haben wir für alle Vortragenden gemeinsam
      das Benutzerkonto \file{ssh-tunnel} angelegt.
      Dieses hat keinen Shell-Zugriff; in der Datei \file{/etc/passwd}
      steht entsprechend ein \lstinline[style=terminal]{x} für das Passwort
      und \lstinline[style=terminal]{/bin/false} für die Shell.
    
      Die öffentlichen Schlüssel, die uns die Vortragenden zusenden,
      hinterlegen wir in \file{/home/ssh-tunnel/.ssh/authorized\_keys}
      und beschränken dabei den Zugriff auf den Aufbau des jeweils
      zugeordneten SSH-Tunnels.
      \begin{lstlisting}[style=terminal]
        permitlisten="localhost:¡5915¿",no-pty,no-x11-forwarding,no-agent-
          forwarding ¡ssh-rsa AAAAB3NzaC1yc2EAA[...]X== user@host¿
      \end{lstlisting}
      (Auch hier erfolgt der Umbruch nur aus Platzgründen;
      in der Datei muß alles in einer einzigen Zeile stehen.)
      In diesem Beispiel lautet die Port-Nummer für den SSH-Tunnel \lstinline[style=cmd]{5915},
      und die zweite Zeile stellt (stark verkürzt) den öffentlichen SSH-Schlüssel
      des*der Vortragenden dar.
    
      Während Sie die Vortragenden dabei unterstützen, ihre SSH-Tunnel zu konfigurieren,
      können Sie mit 
      \begin{lstlisting}[style=cmd]
        lsof | grep ssh-tunnel | grep "591[0-9]"
      \end{lstlisting}
      prüfen, ob der SSH-Tunnel besteht.
      (\lstinline[style=cmd]{ssh-tunnel} ist das in diesem Beispiel verwendete
      gemeinsame Benutzerkonto für die SSH-Tunnel, und \lstinline[style=cmd]{591[0-9]}
      ist ein regulärer Ausdruck für die den Vortragenden zugewiesenen Port-Nummern.)
    
      Wenn das \file{autoview}-Skript läuft (siehe oben),
      sollte spätestens 10 Sekunden nach Aufbau des SSH-Tunnels
      und Start des VNC-Servers durch den*die Vortragende*n
      der VNC-Bildschirm auf dem entsprechenden Kanal zu sehen sein.
    
      \subsection{VNC ohne SSH-Tunnel}
    
      In der bisher beschriebenen Konfiguration stellt grundsätzlich
      der VNC-Viewer eine Verbindung zu einem VNC-Server her,
      der einen Bildschirminhalt exportiert.
      VNC läßt aber auch Verbindungen in der umgekehrten Richtung zu:
      Ein VNC-Viewer lauscht auf einem Port,
      und ein VNC-Server exportiert sein Bild dorthin.
      (In TightVNC für MS-Windows heißt der entsprechende Menüpunkt
      "`Attach Listening Viewer\dots"'; bei \file{x11vnc}
      heißt die Kommandozeilen-Option \lstinline[style=cmd]{-connect}.)
    
      Um dies zu ermöglichen, genügt es, auf den Kanälen, für die dies beabsichtigt ist,
      einen \file{xtightvncviewer} lauschen zu lassen:
      \begin{lstlisting}[style=cmd]
        for x in 5 6; do
          (HOME=$HOME/vnc$x DISPLAY=:$x xtightvncviewer \
            -depth 24 -geometry 1920x1080+0+0 -listen &); \
        done
      \end{lstlisting}
      (In diesem Beispiel geschieht dies für die Kanäle
      \lstinline[style=cmd]{5} und \lstinline[style=cmd]{6}.)
    
      Die Angabe des Home-Verzeichnisses ist notwendig,
      damit sich \lstinline[style=cmd]{xtightvncviewer} auch ohne Passwort-Abfrage
      mit dem lokalen VNC-Server verbinden kann.
      (Stattdessen könnte man auch \lstinline[style=cmd]{xtightvncviewer}
      mit der Option \lstinline[style=cmd]{-autopass} starten
      und das Passwort durch eine Pipe übergeben.)
    
      Die Angabe der \lstinline[style=cmd]{DISPLAY}-Variablen teilt dem VNC-Viewer mit,
      auf welchem der lokalen VNC-Server das Bild zu sehen sein soll.
      (Der lokale VNC-Server tritt hier nicht als VNC-Server auf, sondern als X-Server.)
    
      Auch dieses Programm lassen wir z.\,Zt.\ der Einfachheit halber
      in einer \file{screen}-Sitzung laufen.
      Ein automatischer Start wäre natürlich auch hier möglich.
    
      \bigbreak
    
      \strong{Warnung:} Im Gegensatz zu allen anderen in dieser Anleitung
      beschriebenen Kommunikationsformen zwischen dem Server und allen,
      die ihn benutzen, ist diese Methode, ein VNC-Bild zu übertragen,
      \strong{unverschlüsselt}.
    
      Sie sollte daher nur in Fällen zur Anwendung kommen,
      in denen (a) der Aufwand, SSH-Tunnel für die Vortragenden einzurichten,
      zu hoch wäre, (b) es nicht auf Vertraulichkeit ankommt
      und (c) nötigenfalls andere Methoden existieren, Authentizität zu gewährleisten.
      (Beispiel: Während einer Übung wollen Studierende zur Diskussion ihrer Lösungen
      ihre eigenen Bildschirminhalte veröffentlichen.)
    
      \subsection{Websockify}
    
      Der im folgenden beschriebene Schritt ist möglicherweise nicht notwendig.
    
      Während unserer ersten Lasttests traten Instabilitäten auf.
      Diese waren begleitet von Fehlermeldungen des Programms \file{websockify},
      die sich auf einen lange bekannten Fehler in diesem Programm zurückführen ließen,
      und sich auch durch ein Upgrade von der Python-2- auf die Python-3-Version
      nicht beseitigen ließen.
    
      Wir haben daraufhin die Python-Version von \file{websockify}
      durch eine Node-JS-Version ersetzt. Diese kann man unter
      \url{https://raw.githubusercontent.com/novnc/websockify-js/master/websockify/websockify.js}
      herunterladen.
    
      Die Instabilitäten wurden dadurch weniger, verschwanden aber erst völlig,
      nachdem wir für die lokalen VNC-Server \file{tightvncserver}
      durch \file{tigervncserver} ersetzt hatten.
      Dies kann bedeuten, daß die Instabilitäten überhaupt nichts mit \file{websockify}
      zu tun hatten. Weitere Untersuchungen sind geplant.
    
      \bigbreak
    
      Um \file{websockify.js} ausführen zu können,
      müssen der Node-JS-Interpreter und die benötigten Bibliotheken installiert werden:
      \begin{lstlisting}[style=cmd]
        apt install node node-optimist node-mime-types
      \end{lstlisting}
      Damit \term{noVNC\/} das Node-JS-Programm \file{websockify.js} aufrufen kann,
      verwenden wir ein Shell-Skript \file{/usr/local/bin/websockify} als Wrapper:
      \begin{lstlisting}[style=terminal]
        #!/bin/sh
        node /usr/local/bin/websockify.js "$@"
      \end{lstlisting}
      Sollte sich in zukünftigen Lasttests herausstellen,
      daß der hier beschriebene Austausch von \file{websockify} doch nicht benötigt wird,
      werden wir diese Anleitung entsprechend aktualisieren.
    
      \section{Zum Nachtisch: tmux}
    
      Fortgeschrittenen Studierenden Informatik-naher Studiengänge
      kann man auch eine gemeinsame Shell für den Lesezugriff anbieten.
    
      Hierfür lege man ein "`normales"' Benutzerkonto \file{lecture} an
      und hinterlege die öffentlichen Schlüssel der Studierenden wie folgt
      in der Datei \lstinline{~lecture/.ssh/authorized_keys}:
      \begin{lstlisting}[style=terminal]
        command="tmux attach -r",restrict,pty
          ¡ssh-rsa AAAAB3NzaC1yc2EAA[...]Q== user@host¿
      \end{lstlisting}
      (Wie immer gilt: kein Umbruch, sondern eine lange Zeile pro Schlüssel.)
    
      Anschließend können sich die Studierenden mit einem vorher
      von der*dem Vortragenden unter demselben Benutzerkonto gestarteten \file{tmux}
      lesend verbinden.
    
      \bigskip
    
      \strut\hfill\emph{Viel Erfolg!}
    
      \vfill
    
      \begingroup
    
        \small
    
        \setlength{\leftskip}{3cm}
    
        Stand: 14.\ April 2020
    
        Copyright \copyright\ 2020\quad Peter Gerwinski, Benedikt Wildenhain\\
        Lizenz: \mylicense
    
        Sie können diese Anleitung einschließlich \LaTeX-Quelltext
        herunterladen unter:\\
        \url{https://gitlab.cvh-server.de/pgerwinski/ow}
    
      \endgroup
    
    \end{document}