Artisan Numérique

/système/réseau/ssh/dm/x11/ Lancer des applications graphiques à distance

A l'heure où l'on nous bassine avec l'avancée extraordinaire que représente WayLand, il n'est sans doute pas inutile de rappeler que si X11 ne brille sans doute pas par ses performances, sa couche réseau lui permet de résoudre une vaste palette de problématique comme ici accéder à distance à un environnement graphique.

Comme vous ne l'ignorez peut-être pas, X11 est une technologie client/serveur. C'est à dire que lorsqu'une application est lancée, elle n'écrit jamais directement sur le périphérique graphique mais se connecte, par l'intermédiaire d'un kit graphique (Qt, GTK, etc) à un serveur d'affichage, le fameux Xorg exploitant le protocole X11.

Ainsi, à chaque fois qu'une application X11 veut afficher un rectangle, ou une image, c'est à ce serveur que cette demande est transmise et c'est lui qui effectue le rendu visuel. Dans l'autre sens, le serveur recueille les entrées telles la souris ou le clavier pour retransmettre cela à l'application.

Alors évidemment lorsque le client et le serveur sont sur une même machine, tout ceci ne va pas sans une certaine perte de performance. Cependant les impacts sur la vitesse sont limités à plusieurs étages comme par l'utilisation de sockets rapides (sockets UNIX) au lieu des classiques sockets sur IP, ou encore par un accès direct au GPU dans des cas critiques comme la 3D ou la vidéo.

Maintenant cette toute relative perte de performance ne doit pas faire oublier les immenses avantages de cette solution : la transparence réseau. En effet déporter l'affichage d'une application sur une machine distante, exécuter sur son écran local une application qui se trouve sur un serveur distant, tout cela et bien d'autres choses encore sont rendues possibles grâce au X11.

Pour la petite histoire il faut bien comprendre que cette transparence réseau n'est pas un coquetterie d'Unixien. En effet, à son origine, une architecture UNIX classique se composait d'un ou plusieurs serveur "puissant" et d'une myriade de petits terminaux graphiques causant couramment le X11 "en dur", le tout sur un LAN 1Mb/s.

Aujourd'hui la transparence réseau offerte par X11 n'est même pas soupçonnée la majorité des utilisateurs de Linux qui ne travaillent que sur une et une seule machine. Mais X11 permet de couvrir un vaste ensemble de cas d'usage allant du pratique à l'indispensable.

  • ouvrir une session graphique complète sur une machine distante. Tout ce qui sera exécuté tournera sur la machine distante et s'affichera via le serveur X11 de la machine locale.
  • ouvrir juste une application graphique, généralement via SSH, sur la machine distante.

Dans tous les cas le principe sera le même, une application est lancée à distance et se connecte à votre serveur X11 local. Voyons cela de plus près.

L'option "native"

Comme nous l'avons vu, un serveur X11 utilise les sockets pour communiquer avec le client. Et pour que cette communication soit la plus rapide possible, il en utilise deux types : des sockets "lents" TCP/IP, et des sockets "rapides" UNIX. Dans le cas d'un serveur local parlant à une application locale, le socket utilisé est systématiquement de type UNIX.

Pour des raisons de sécurité, il y a de forte chance que votre serveur X soit paramétré de sorte à ne pas utiliser les sockets TCP/IP, et donc de ne pas permettre son utilisation par une machine distante. Nous allons donc changer cela en ayant conscience que cette manipulation n'est sure que sur un réseau local de confiance et protégé du réseau public.

Le lancement de votre serveur X11 est effectué par l'intermédiaire d'un gestionnaire de session, par exemple GDM pour Gnome. Pour autoriser les clients distant à utiliser ce serveur X11 via TCP, il faut donc lancer en tant que root l'outil gdmsetup, aller dans l'onglet sécurité, et décocher la ligne Refuser les connexions TCP au serveur X. Ceci fait vous pouvez fermer gdmsetup et relancer votre serveur X. Au retour, le port 6000 correspondant à l'écran X11 :0.0 (si c'est :1.0 le port sera 6001, et ainsi de suite) devrait être écouté par le serveur :

rootnetstat -anlp | grep X | grep -v STREAM
tcp        0      0 0.0.0.0:6000                0.0.0.0:*                   LISTEN      5667/X
vérification du serveur X11 en écoute

Ceci fait, nous allons pouvoir nous connecter sur la machine distante, par exemple avec SSH, et y lancer une commande graphique, par exemple evolution :

gastonssh machine_distante
gaston@machine_distante>DISPLAY=mon_desktop:0.0 evolution
Utilisation de la transparence native de X11

C'est aussi simple que cela. Tout passe par l'utilisation de la variable DISPLAY qui indique à l'application où se trouve le serveur X11 à utiliser. En local, votre variable DISPLAY est sûrement :0.0. Le fait qu'il n'y ait rien devant le : indique au client que le serveur est local. Dans notre exemple il va donc aller sur la machine mon_desktop. 0.0 indique d'utiliser l'écran .0 de la carte 0.

Si tout a fonctionné, c'est nickel. Il est possible que votre serveur soit configuré pour refuser les connexions externes et vous aurez alors obtenez l'erreur suivante :

gastonssh machine_distante
gaston@machine_distante>DISPLAY=mon_desktop:0.0 evolution
No protocol specified
Impossible d'ouvrir l'affichage :
Exécuter « evolution --help » pour obtenir la liste complète des options en ligne de commande.
Erreur d'autorisation

Ce qui compte ici c'est le No protocol specified qui dit, à qui sait le comprendre, que vous devez d'abord autoriser les connexions et lançant sur la machine secondaire la commande suivante :

gastonxhost +
access control disabled, clients can connect from any host
gastonssh machine_distante
gaston@machine_distante>DISPLAY=mon_desktop:0.0 evolution&
Autorisation de tous les accès à la machine secondaire

Et là, ça marche... Ceci étant, dans la mesure où nous passons par SSH pour aller sur la machine distante, il existe une méthode plus simple consistant fournie par SSH lui-même.

L'option SSH

SSH permet la redirection de ports, et plus particulièrement est capable de rediriger le socket UNIX d'un serveur distant sur un socket TCP/IP local. Cette caractéristique nous permet en toute simplicité de faire la même chose que précédemment, mais à travers une connexion chiffrée convenant mieux à un réseau LAN moins sécurisé et ce, sans aucun changement des paramétrage de sécurité.

Ainsi, utilisé avec l'option -X (certaines configuration font cela par défaut), ssh va ainsi automatiquement changer la variable DISPLAY pour pointer sur son "faux" serveur X11 local :

gastonssh -X machine_distante
gaston@machine_distante>echo $DISPLAY
localhost:11.0
gaston@machine_distante>evolution&
lancement d'évolution à travers SSH

Là, plus besoin d'autorisation via xhost ni d'écoutes de port TCP/IP, tout se fait automatiquement par la grâce de SSH. Maintenant cette méthode n'est pas sans défaut. En effet, si la machine distante est un peu légère, le chiffrement temps réel de toutes les données circulant dans le tuyau SSH vont un peu pénaliser les performances. Mais sur un LAN moderne cela reste acceptable.

Concernant un réseau distant, par exemple à travers internet, c'est le volume de données échangé qui va pénaliser les performances. Il est donc plus sage dans ce cas d'opter sur une version compressée du protocole X11, comme nomachine/freeNX.

Un bureau distant complet

Pour vous donner un cas d'usage, mon bureau est relié à mon logement par une série de 3 switch Gigabit. Chez moi j'ai un petit portable très léger. Au bureau se trouve la grosse machine de développement. Pour travailler soir et week-end (oui, je sais ;-), je me connecte en mode session sur ma machine de bureau et tout ce que je lance est ainsi routé vers mon portable. A savoir en général firefox, chrome, une dizaine de GVIM, thunderbird, pidgin, skype, etc... Tout ce joli monde tourne donc dans mon bureau et communique avec le serveur X11 de mon portable en mode bi-écran... Et bien croyez moi, je ne vois strictement aucune différence entre cet usage, et le fait de bosser directement dans mon bureau. J'arrive même à lancer une vidéo sans soucis... Voyons donc comme faire pour lancer ainsi une session entière à distance.

Pour d'évidentes raisons de performances, ajouté du fait que je travaille sur un LAN sécurisé, l'approche SSH n'apporte ici que peu d'avantage. Autant donc attaquer nativement le serveur X11 de sorte à bénéficier des meilleurs performances.

Dans mon cas le gestionaire de fenêtre est l'excellent awesome. Le principe va donc être de créer un fichier xinitrc-distant qui va lancer à distance le gestionnaire de fenêtre.

xhost +
ssh ma-machine "DISPLAY=mon-portable:0.0 awesome"

Pour ceux qui ne sont pas à l'aise avec xinitrc, allez jeter oeil à cet article là. Pour les autres, il ne reste plus qu'à lancer la session dans la console linux :

xinit xinitrc-distant

Et hop, je suis sur ma machine distante, dans mon gestionnaire de fenêtres préféré et je peux dés lors lancer les applications que je veux. Voyons maintenant un peu ce que nous avons fait.

Le contenu de xinitrc-distant ne devrais plus vous surprendre outre mesure. On y retrouve déjà le xhost + pour autoriser les accès distants au serveur X11 local. Attention, comme indiqué au premier chapitre, il est nécessaire pour que tout ceci fonctionne que fous ayez activé le mode TCP/IP sur votre serveur X11 !!

Ensuite il s'agit de se connecter via SSH sur la machine distante pour lancer awesome. Le DISPLAY injecté en variable va quant à lui indiquer à awesome d'aller parler au serveur X11 de mon portable, et le tour est joué.

La syntaxe de lancement de X11 est en revanche un peu nouvelle, mais pas tant que cela en réalité. En effet, lorsque vous tapez startx dans la console Linux, c'est comme si vous aviez tapé xinit ~/.xinitrc. C'est commande xinit qui va concrètement lancer le serveur X11 et qui va ensuite exécuter le script xinitrc. Ici nous indiquons donc juste un script alternatif à xinit.

Et le son alors ??

Tout ceci est en effet bien sympa. Nous avons pour nos applications un affichage local, un clavier local, une souris locale, mais quid du son ? Et c'est là que PulseAudio va enfin servir à quelque chose. En effet, comme X11, PulseAudio bénéficie d'une transparence réseau qui par défaut est limité à un socket UNIX. Comme pour X11 nous allons donc commencer par activer le mode TCP/IP allant modifier le fichier /etc/pulse/default.pa. En cherchant dedans vous devez trouvez une ligne normalement commentée load-module module-native-protocol-tcp. Décommentez la ligne, sauvez le fichier et redémarrez la machine. Ceci fait, PulseAudio devrait être en écoute du port 4713 de la machin locale.

Nous devons maintenant modifier notre fichier xinitrc-distant pour injecter dans l'environnement d'awesome la référence au serveur PulseAudio :

xhost +
ssh ma-machine "DISPLAY=mon-portable:0.0 PULSE_SERVER=mon-portable:4713 awesome"

Ceci fait, il ne reste plus qu'à relancer xinit ~/xinit-distant pour avoir maintenant accès à l'audio tant pour les entrées que les sorties. Cela fonctionne tellement bien que j'utilise régulièrement skype de cette manière.

Conclusion

Comme à l'accoutumée, les outils SSH et X11 démontre leur plasticité et leur capacité à s'adapter à toutes les situations tordues auxquelles vous voudrez les plier. Happy Networking :)