Commit 4ecde848 authored by Peter Gerwinski's avatar Peter Gerwinski
Browse files

online-werkzeuge-admin: noVNC (Fortsetzung), tmux (zum Nachtisch)

parent cfe11d5f
......@@ -601,7 +601,7 @@
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
Die entsprechende Apache-Konfiguration erfolgt in der Konfigurationsdatei\\
\file{/etc/apache2/sites-enabled/novnc.cvh-server.de.conf}:
\begin{lstlisting}[style=terminal]
<VirtualHost _default_:80>
......@@ -659,12 +659,401 @@
Die Optionen \lstinline{&reconnect=1&resize=scale}
bewirken eine Vorkonfiguration des \term{noVNC\/}-Clients,
daß er sich bei Verbindungsabbruch automatisch wiederverbinden soll
und daß er das VNC-Bild auf die Größe des Browser-Fensters skalieren soll.
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).
\emph{(Fortsetzung folgt.)}
\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 installnode 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
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment