!!! Terminalserver unter Linux

Bei einem Terminalserver geht es darum, daß ich einen relativ
einfachen Client-Rechner habe, der normalerweise auch keine
Festplatte besitzt (DisklessClient bzw. ThinClient) und der von
einem zentralen Server aus alle Daten bekommt, um zu arbeiten. Der
große Vorteil ist, daß man nur noch eine zentrale Stelle hat, an
der man ein ganzes Netzwerk von Rechnern konfiguriert und wartet.

Grundsätzlich gibt es die Frage, welche Aufgaben vom Server und
welche von Client übernommen werden sollen. Klassische
Terminalserver-Projekte wie das ursprüngliche 
[LTSP (Linux Terminal Server Projekt)|http://ltsp.org/] bis Version 5 gehen davon aus, daß der Client in ThinClient, also so
einfach (d.h. billig) wie möglich aufgebaut ist und eigentlich nur
als verlängerter Bildschirm und Tastatur des Servers dient. Dies
hat den großen Vorteil, daß alle Benutzer wirklich nur auf einem
System (nämlich dem Server) arbeiten und lediglich ein Mini-Linux
mit X-Server auf dem Client laufen muss.

Eine Alternative ist, den Server lediglich als Fileserver benutzen
und die Applikationen dadurch jeweils auf dem Client laufen zu
lassen. ThomasBayen hat seine Erfahrungen dazu auf der Seite
DisklessClient und BootenVomNetzwerk sowie NeuesLTSP zusammengefasst.

Zur Skalierung eines LTSP-Systems ist zu sagen, daß ich von
Skolelinux-Installationen an Universitäten gehört habe, die
tausende(!) von Clients in einer Installation laufen haben.

Wer lediglich einen Linux-Rechner aus der Ferne bedienen will,
sucht (neben {{ssh -X}}) vielleicht nach der Seite
XdmcpTerminalServer oder einem VncServer. Ein alternatives Projekt
zu LTSP ist [OpenSLX|http://lp-srv02a.ruf.uni-freiburg.de/trac/dxs/wiki].

!! Technischer Hintergrund

Im April 2006 habe ich (ThomasBayen) einen [http://ltsp.org/
LTSP-Server] aufgesetzt. Hierbei habe ich einige Dinge zur
Architektur eines LTSP-Systems bemerkt, die mir nicht direkt klar
waren. Deshalb erkläre ich das Ganze hier nochmal etwas: Am Anfang
steht ein ganz normales Linux-System. Dieses System hat eine
graphische Oberfläche, d.h. insbesondere einen ''Display Manager''
wie z.B. __kdm__ installiert. Dieses Programm erzeugt den uns
allen wahrscheinlich wohlbekannten Login-Dialog, der nach dem
Einschalten auf dem Bildschirm erscheint. Der erste Schritt ist
nun, den kdm so zu konfigurieren, daß er XDMCP-Anfragen von
außerhalb annimmt (das ist nur eine Zeile in einer Config-Datei).
Siehe hierzu auch XdmcpTerminalServer. Nun können X-Server (mit "X
-query" o.ä.) von einem anderen Rechner aus auf unseren
Hauptrechner zugreifen und erhalten dann einen eigenen
Login-Dialog.

Bisher haben wir einen normalen XDMCP-Server. Was wir jetzt brauchen, sind Clients, die automatisch booten und per XDMCP an unseren Hauptrechner andocken. Diese Clients müssen im Grunde wie ein DisklessClient gebootet werden (natürlich kannen auch ein ThinClientLokalBooten, das hat aber nur in Ausnahmefällen Sinn). Hierzu benötigen wir einen Server, der einerseits die hierzu benötigten Dienste (DHCP, TFTPD, NFS) laufen hat und andererseits das root-Filesystem der Clients in einem eigenen Verzeichnis enthält.

Die Besonderheit an LTSP im Vergleich zu einem normalen
DisklessClient ist nun, daß das root-Filesystem des Clients ganz
speziell auf diesen Zweck zugeschnitten ist. LTSP ist insofern eine
ganz eigene Distribution für [ThinClient]s. Das Filesystem wird
read-only gemountet und daher vom Client nicht geändert. Deshalb
können alle Clients mit einem identischen Filesystem booten. Beim
Hochfahren wird eine automatische Erkennung des X-Servers
vorgenommen und dieser dann mit einer XDMCP-Anfrage an den
Hauptserver gestartet.

Der LTSP-Server ist normalerweise identisch mit dem Hauptserver
(muss aber nicht). Da die LTSP-Distribution in einem ganz eigenen
Verzeichnis liegt, braucht man keine Sorgen zu haben, sein
Hauptsystem in irgendeiner Weise zu verändern. Es werden lediglich
die o.g. Netzwerkdienste installiert und eingerichtet.


!! Installation

! Projekt Mue-Cow

Unter Ubuntu-Linux gibt es die Alternative der neueren Mue-Cow-Pakete, die in Zusammenarbeit mit Ubuntu entwickelt wurden.

Dadurch, daß LTSP bis Version 4.x im Grunde eine eigene Distribution ist, haben die
LTSP-Betreuer viel Arbeit am Hals, alle Komponenten ständig auf dem
laufenden zu halten. Insbesondere gibt es natürlich einige
Applikationen, die man eventuell dann doch auf dem Client und nicht
auf dem Server laufen lassen will (z.B. ein VNC-Client oder ein
Seti@home-Client). Die Installation solcher Applikationen auf dem
Client geht nun aber nicht einfach mit ''apt'' oder ''rpm'',
sondern muss immer genau auf LTSP abgestimmt sein.

Um diesem Problem zu begegnen, möchte das LTSP-Team die Architektur
unter dem Namen "Projekt Mue-Cow" verändern. Statt eines Paketes
''ltsp-utils'', das dann LTSP-tgz-Pakete nachlädt, um die
LTSP-Distribution zu installieren, wird die Client-Distribution in
Zukunft auf einem normalen Debian (oder Redhat oder Suse oder
Ubuntu) basieren. Dazu kommt dann noch ein spezielles "ltsp-client"
Debian-Paket, das aus der Standard-Distribution einen LTSP-Client
macht. Um den Server einzurichten, gibt es dann ein
"ltsp-server"-Paket.

Die neueren Pakete gibt es bereits in Debian Etch, allerdings
habe ich sie auf meinem Sarge-System nicht ans laufen gebracht.
Deshalb habe ich obigen Installationsweg beschritten.

In Ubuntu seit "Breezy Badger" (5.10) sind bereits Pakete nach dem
Mue-Cow Standard enthalten. Wem das also besser gefällt, sollte
überlegen, seine LTSP-Experimente mit Ubuntu zu machen.


! Debian Sarge

Ich habe mir das __ltsp-utils__-Paket von der [http://ltsp.org/
LTSP-Webseite] geholt. Dies lief nach der vorhandenen Doku relativ
einfach und unkompliziert. Dennoch empfehle ich, von Anfang an mit Etch und den Muecow-Paketen (d.h. LTSP 5) zu arbeiten. -- ThomasBayen''


! Debian Etch

seit Debian etch sind die neueren Pakete (bekannt als ''Muecow'' oder auch als ''LTSP 5'') in die normale Distribution gewandert. Dort macht man folgendes:

  aptitude install ltsp-server
  ltsp-build-client
  echo "/opt/ltsp       *(ro,no_root_squash,async)" >>/etc/exports
  invoke-rc.d nfs-kernel-server reload
  invoke-rc.d openbsd-inetd reload
  invoke-rc.d portmap reload

Bei ThomasBayen, der ein LinuxMit64Bit betreibt, war es nötig, bei "ltsp-build-client" den Parameter "--arch i386" anzufügen. Dadurch bekommen die Clients (unabhängig davon, welche Architektur der Server benutzt) ein System mit einer i386-Architektur.

Dann muss man in ''/var/lib/tftpboot/ltsp/i386/pxelinux.cfg/default'' den Parameter '''nfsroot=auto''' anfügen (Scheint ein Bug im Debian-Paket zu sein, oder wer kann das anders zum laufen bringen?!?).

Einen richtig konfigurierten DHCP-Server vorausgesetzt (siehe DnsMasq) sollte das LTSP-System jetzt auch schon funktionieren! Der Haupt-Unterschied ist nun, daß man mit chroot in das Verzeichnis ''/opt/ltsp/i386/'' gehen kann und dort ein normales Debian-System hat, das man entsprechend anpassen und z.B. mit ''aptitude'' erweitern kann.

Die Standardeinstellungen sind so gewählt, daß sogar auf eine ''/etc/lts.conf'' verzichtet werden kann (und wird). Wer eine selber schreibt, sollte darauf achten, dass man die SCREENs 00-06 nicht benutzen sollte, solange ''/etc/inittab'' dort gettys startet (sonst gibts keine Tastatur!). Ansonsten bietet sich die Erstellung einer ''lts.conf'' alleine schon an, um die deutsche Tastaturbelegung zu aktivieren:

  [Default]
        SCREEN_07       = startx
        XkbModel        = pc105
        XkbLayout       = de


!! lokale Applikationen

Eigentlich ist LTSP ja dazu da, das alle Applikationen auf dem
Server laufen. Dies hat viele Vorteile. Man braucht nur ein System
zu warten und die Ressoucen dieses Systems werden viel besser ge-
und verteilt. Dennoch gibt es Gründe, Applikationen dezentral
laufen zu lassen. Spontan fallen mir hier einige Gründe ein:

* Programme, deren primärer Zweck die Verbindung zwischen Display und einem dritten Server ist: __Vnc__ (siehe VncServer), __RDesktop__ (für Windows Terminalserver)
* Programme, die den X-Server besonders fordern wie z.B. Videoplayer oder Streamingclients
* Programme, die besonders viel Rechenleistung benötigen und die Ressourcen des Hauptservers damit zu stark blockieren würden wie z.B. Seti@home oder DosEmu. (Ich habe selber den DosEmu auf einem LTSP-Client installiert. Dies habe ich auf DosEmuAufLTSPClient dokumentiert.)



== lokaler Sound ==

Auf der LTSP-Webseite gibt es umfangreiche Doku zum Thema "Sound". Es gibt dazu verschiedene netzwerktaugliche Sound-Server. Dennoch habe ich für den normalen Büroarbeitsplatz eine viel einfachere und bessere Lösung! Ich benötige nämlich in Wirklichkeit gar keinen Sound mit Boxen, die ein extra Stromkabel brauchen und mir wieder den Schreibtisch zustellen. Ich brauche nur ab und an mal eine Nachricht, z.B. über eingegangene EMails.

Für diesen Zweck haben die Urväter des PC bei allem Blödsinn, den sie gemacht haben, eine Super-Idee gehabt: Den internen Lautsprecher. Nun habe ich aus dem Debian-Paket '''beep''' das Executable in mein LTSP-Verzeichnis nach /usr/bin/ kopiert. Nun kommt in die ''/opt/ltsp/i386/etc/lts.conf'' folgende Zeile:

  MODULE_01 = pcspkr

Da ich für eine andere Anwendung bereits einen Public Key habe, dessen Passwort ich über einen ssh-agent verwalte, mit dem ich mich dann später ohne Passwort auf dem Thin Client einloggen kann, reicht es nun, in Notify-Programmen wie im KDE-Kontrollcenter oder insbesondere im von mir benutzten KBiff folgenden Befehl anzugeben:

  ssh root@${DISPLAY/:*/} beep

Wer eine hübsche Melodie vorzieht, findet auf der Seite ThomasBayen eine Anregung...

''Eine Konfiguration, bei der man gar kein Passwort mehr braucht, ist natürlich auch denkbar. Ob es sinnvoll ist, allen Benutzern auf allen Clients root-Rechte einzuräumen und ob das was schaden würde, bleibt jedem selbst überlassen.''



== lokale Medien (USB-Sticks) ==

Es ist möglich, Medien wie USB-Sticks, Disketten oder CDs lokal einzustecken. Diese erscheinen dann automatisch als Icon auf dem Desktop und können durch einen simplen Klick benutzt werden. Jeweils zwei Sekunden nach dem letzten Zugriff werden beschreibbare Medien (USB-Sticks) gesynct und können heruasgezogen werden. Hierzu muss ein bisschen was auf dem Server eingerichtet werden. Dies ist auf der Seite http://wiki.ltsp.org/twiki/bin/view/Ltsp/LTSP-42-LocalDev-DebianEtch beschrieben.

== andere lokale USB-Geräte ==

Wenn man keinen lokalen Treiber mit einer lokalen Software installieren will, bleibt nur der Ansatz, den USB-Bus über das Netzwerk weiterzuleiten. Die einzige freie Linux-Lösung hierzu ist [usbip|http://usbip.sourceforge.net/#documentation], das ich jedoch noch nicht persönlich getestet habe.

:Hierzu findet sich einiges an Information im Themenschwerpunkt des aktuellen [Linux-Magazins|http://www.linux-magazin.de/heft_abo/ausgaben/2007/10]:
[LTSP und lokale Storage-Devices|http://www.linux-magazin.de/heft_abo/ausgaben/2007/10/einer_fuer_alle]

(Die Ausgabe lohnt i.m.h.o. alleine schon wegen des zehnjährigen Perlsnapshot-Jubiläums) -- MarkusMonderkamp am 12.09.2007

== Clients ausschalten ==

Beim laufenden Betrieb unseres Terminalservers ist mir ein sehr praktisches Problem aufgefallen: Es gibt keine vernünftige Methode, um die Clients auszuschalten. Versucht man, beim ausloggen oder im Login-Bildschirm "herunterfahren" auszuwählen, fährt man den Terminalserver herunter (was wohl nicht Sinn der Sache sein sollte und deshalb von mir abgeschaltet wurde). Aber wie fährt man den Client herunter?!? Nun - man kann, '''wenn''' man sich ausgeloggt hat und '''wenn''' man sich dazu traut und '''wenn''' man den Ein-/Ausschalter 4 Sekunden drückt, den Client einfach ausschalten. Das sind mir aber drei "wenn"s zu viel...

Der normale Client-Kernel aktiviert interessanterweise soviel ACPI, daß man den Client nicht mehr mit dem Power-Button ausschalten kann (ohne diesen 4 Sekunden festzuhalten). Außerdem möchte ich gerne, daß die laufende KDE-Session sauber beendet wird (wie es ja auf Standalone-Rechnern auch üblich ist), bevor der Client ausgeschaltet wird. Also dachte ich mir, daß es am besten sei, ebendieses aktivierte ACPI auch zu benutzen. ''(Eine Alternative wäre, einen Ausschaltknopf in die GUI zu pflanzen. Aber wohin und wie?)''

=== Client ===

==== LTSP 4.x ====

Zuerstmal habe ich mir aus dem Debian-'''acpid'''-Paket ein kleines acpid.tgz-Archiv gebastelt, indem ich

* alles unnötige weggelassen habe (Doku etc.)
* Den '''nc'''-Befehl hinzugefügt habe (netcat)
* ''etc/acpi/powerbtn.sh'' modifiziert habe
* ''etc/rc.d/acpid'' geschrieben habe

Folgende Dateien wurden besonders angepasst:

'''etc/acpi/powerbtn.sh:'''

  #!/bin/sh
  # /etc/acpi/powerbtn.sh
  # -TB-
  echo "shutdown" | nc terminalserver 4711 -q 0
  sleep 5
  init 0

'''etc/rc.d/acpid:'''

  #!/bin/bash
  modprobe button
  /usr/sbin/acpid -c /etc/acpi/events

Dieses Archiv kann man nun in das LTSP-Client-Rootverzeichnis entpacken. ''(Wer ein Mue-Cow-LTSP hat, kann den LTSP natürlich viel einfacher installieren...)''

In der Datei ''lts.conf'' im LTSP-Client-Rootverzeichnis habe ich noch folgendes hinzugefügt:

        RCFILE_01 = acpid

Hierdurch wird die obige Datei ''etc/rc.d/acpid'' bei Starten der Clients ausgeführt. Dadurch wird der '''acpid'''-Daemon gestartet. Sobald der Powerbutton gedrückt wird, wird per "nc" ein Kommando an den Port 4711 des Rechners '''terminalserver''' geschickt. Hier habe ich nun einen Server in Perl implementiert, der dieses Kommando aufnimmt. Der Server schließt die zu diesem Client gehörende KDE-Session sauber ab. KDE-Programme speichern dabei Ihren Session-Status wie z.B. Fensterpositionen etc. und beenden sich. Hierzu läßt der Client dem Server 5 Sekunden Zeit. Nach dieser Zeit wird der Client dann endgültig heruntergefahren.

==== LTSP 5 ====

Ich habe auf dem Client (also im chroot) das Debian-Paket '''acpid''' installiert. Dann habe ich eine Datei angepasst:

'''etc/acpi/powerbtn.sh:'''

  #!/bin/sh
  # /etc/acpi/powerbtn.sh
  # -TB-
  echo "shutdown" | nc terminalserver 4711 -q 0
  sleep 5
  init 0

Das wars dann auch schon. :-)


=== Server ===

Der Perl-Server wird durch eine Zeile in der ''/etc/inetd.conf'' aktiviert:

  4711    stream  tcp     nowait  root    /usr/sbin/thinclientserver

Die Datei ''/usr/sbin/thinclientserver'' sieht dann so aus:

  #!/usr/bin/perl
  use strict;
  use Socket;
  use Net::Domain qw(hostname hostfqdn hostdomain);
  #
  # Dieses Programm wird in der /etc/inetd.conf mit folgender Zeile eingebunden:
  #   4711    stream  tcp     nowait  root    /usr/sbin/thinclientserver
  #
  # Dann wird es von einem fernen Client gestartet mit:
  #  echo "shutdown" | netcat terminalserver 4711 -q 1
  #
  while(<>){
    s/\n//;
    system('logger thinclientserver '.$_);
    if($_ eq 'shutdown'){
      # So stelle ich den Namen der Gegenstelle, also des Clients, der
      # heruntergefahren werden soll, fest (siehe "perldoc -f getpeername"):
      unless(-S STDIN){
        print "Kann nur per inetd aufgerufen werden!\n";
        exit 1;
      }
      my $hersockaddr = getpeername(STDIN);
      my (undef, $iaddr) = sockaddr_in($hersockaddr);
      my $clientname = gethostbyaddr($iaddr, AF_INET);
      # Meinen eigenen Namen brauche ich auch:
      my $servername = hostname();
      # Dies ist die Liste der Sessions, die dieser Server kennt:
      open INPUT, 'dcop --list-sessions --all-users |';
      my $input = join('',<INPUT>);
      # Per RegEx suche ich den User heraus, der an diesem Client angemeldet ist (und seine Session)
      if($input =~ /Active sessions for user \/home\/(.*) :(?:(?:\n[^\n]).*?)+\s*(\S.*$servername\_$clientname\_\d*)\n/){
        my ($user,$session) = ($1,$2);
        print "$user, $session\n";
        # Und jetzt fahre ich die KDE-Session herunter:
        system "dcop --user $user --session $session ksmserver ksmserver logout 0 0 0";
      }else{
        system "logger Keine Session fuer Shutdown aktiv.";
      }
    }
  }

Mit dieser Anpassung kann man nun seinen Client jederzeit sauber herunterfahren, indem man den Power-Off-Button drückt. Dieser Knopf ist meiner Meinung nach die sauberste "Benutzeroberfläche", die für dieses Problem zur Verfügung steht und sollte deshalb auch dafür benutzt werden. Man sollte beachten, daß es immer eine gute Idee ist, trotzdem seine Programme vorher sauber zu beenden. :-) Insbesondere Nicht-KDE-Programme (z.B. Openoffice) reagieren recht ungehalten, wenn sie "von außen" heruntergefahren werden. Hoffen wir, daß sich da in der Entwicklung noch etwas tut...

Es bleibt die Warnung, daß mein "shutdown-Server" keine hundertprozentige Authentifizierung bietet. Jemand könnte die Shutdown-Verbindung "faken" und so beliebig Client-Sessions beenden. Außerdem könnte jemand durch wiederholten Aufruf des Servers mit sehr langen Eingabedateien einen DoS-Angriff starten. Wen das stört bzw. wer weitere Sicherheitslücken findet, kann dies gerne kundtun bzw. den Server verbessern! -- ThomasBayen

== Scanner ==

Auf der Seite http://wiki.ltsp.org/twiki/bin/view/Ltsp/Scanners steht eine gute Anleitung für LTSP 4.x, die eigentlich darauf hinausläuft, daß man eine einzige Zeile in die ''lts.conf'' schreibt und fertig.

Bei LTSP 5 ist SANE allerdings nicht mehr automatisch enthalten (das ist ja sozusagen der Sinn von LTSP 5), deshalb muss man das Paket "sane-utils" in das Client-root installieren. Dann folgende Befehle ausführen:

  echo "sane-port stream tcp nowait root.root /usr/sbin/saned saned" >>/etc/inetd.conf
  echo "+" >>/etc/sane.d/saned.conf

Wenn "scanimage -L" auf dem Client zwei Geräte anzeigt (eins lokal, eins über das Netz), hat man gewonnen! Weiteres zur Konfiguration des Terminalservers (also des Sane-Clients) auf obiger Seite und auf der Seite ScannerImNetzwerk.

Der saned läuft so übrigens mit root-Rechten. Wen das stört, der sollte in der ''inetd.conf'' das "root.root" durch "saned.saned" ersetzen, muss dann aber auch udev so konfigurieren, daß ein eingesteckter Scanner der Gruppe "saned" gehört. -- ThomasBayen

== LTSP testen ==

Edubuntu Maintainer Oliver Grawert fordert in seinem [Blog|http://www.grawert.net/weblog.cgi] Entwickler zum Testen des beschleunigten LTSP-Bootprozesses auf. --MarkusMonderkamp

[{Tag ThinClient}]