Linux

Chroot d’un utilisateur sous CentOS/Linux : à quoi ça sert vraiment ?

Le chroot, on en parle souvent comme d’une cage pour utilisateur. L’image n’est pas mauvaise, à condition de ne pas la prendre au pied de la lettre. Sur CentOS ou sur une autre distribution Linux, faire un chroot pour un compte revient à lui montrer un faux point de départ dans l’arborescence du système. Au lieu de voir le vrai /, l’utilisateur voit un répertoire choisi par l’administrateur, et pour lui, ce dossier devient sa racine.

Dit comme ça, ça paraît très propre. En pratique, c’est utile, parfois très utile, mais ce n’est pas une baguette magique. Si vous gérez un serveur avec des accès SFTP, des comptes techniques ou un hébergement mutualisé un peu artisanal, comprendre ce mécanisme évite beaucoup d’erreurs. Si vous cherchez d’autres repères autour de l’administration Linux côté hébergement, vous pouvez aussi jeter un oeil à cet article, qui complète bien la logique de cloisonnement des services. Dans le même esprit, cette autre ressource aide à replacer le chroot dans des usages serveur plus concrets.

Ce que voit réellement un utilisateur chrooté

# exemple fréquent avec SFTP
Match Group sftpusers
    ChrootDirectory /srv/sftp/%u
    ForceCommand internal-sftp
    X11Forwarding no
    AllowTcpForwarding no

Le plus simple est d’imaginer un couloir d’hôtel dont on a fermé toutes les autres portes. L’utilisateur peut circuler dans sa zone, créer des fichiers, lire ce qu’on lui a autorisé, mais il ne remonte pas librement dans tout le bâtiment. Son environnement peut contenir un dossier home, un sous-répertoire de dépôt, parfois quelques bibliothèques si on veut lui laisser un shell ou certains outils.

Le point important, c’est que le chroot ne change pas l’identité du compte. Il ne transforme pas un utilisateur ordinaire en prisonnier parfait. Il change sa vue du système de fichiers. C’est pour ça qu’on l’emploie souvent pour limiter les dégâts ou pour éviter qu’un compte destiné à une tâche précise se balade partout sur le serveur.

Sur CentOS, l’idée apparaît vite dès qu’on met en place des accès de transfert. Beaucoup d’administrateurs veulent qu’un client, un prestataire ou un utilisateur métier puisse déposer et récupérer des fichiers sans tomber sur les répertoires système, sans voir les autres comptes, et sans faire n’importe quoi dans /etc ou /var.

Dans quels cas le chroot est vraiment utile

Le cas le plus parlant, c’est le SFTP. Vous avez un utilisateur qui doit envoyer des fichiers comptables, des exports ou des sauvegardes applicatives. Il n’a pas besoin d’un shell interactif, encore moins d’un accès large au serveur. Vous le chrootiez dans un dossier dédié, par exemple /data/client1, et son univers s’arrête là. Pour lui, ce dossier devient la racine.

On retrouve la même logique avec certains serveurs FTP, même si aujourd’hui SFTP est souvent préféré. Mentalement, c’est très simple : vous ne donnez pas les clés de la maison, vous ouvrez seulement le local de dépôt. C’est propre, lisible, et ça évite les confusions du genre utilisateur perdu dans des chemins qu’il ne comprend pas.

Le chroot peut aussi servir avec des comptes techniques qui doivent manipuler un jeu de fichiers précis. Il rend l’usage plus étroit, donc plus prévisible. Ce n’est pas seulement une question de sécurité pure. C’est aussi une manière de réduire le risque d’erreur humaine. Un utilisateur qui ne voit que son périmètre a moins de chances d’effacer le mauvais répertoire.

Pourquoi ce n’est pas une frontière de sécurité absolue

# vérifier les droits du dossier de chroot
ls -ld /srv/sftp
ls -ld /srv/sftp/monuser

C’est ici que beaucoup de gens vont trop vite. Un chroot n’est pas un conteneur moderne, ce n’est pas une machine virtuelle, et ce n’est pas une sandbox totale. Si un processus a des privilèges élevés ou si l’environnement chrooté est mal préparé, le niveau de protection réel peut être bien plus faible qu’on l’imagine.

Autrement dit, le chroot aide à enfermer une vue du système, mais il ne remplace pas une vraie politique de droits, ni SELinux, ni les permissions Unix, ni les contrôles applicatifs. Si vous laissez des binaires mal placés, des droits d’écriture là où il ne faut pas, ou si vous donnez un shell complet sans réfléchir aux dépendances et aux permissions, vous vous fabriquez un faux sentiment de sécurité.

Il faut aussi garder en tête qu’un service qui supporte le chroot ne l’implémente pas toujours de la même façon. Dans OpenSSH pour SFTP, par exemple, les règles de propriété sur les répertoires sont strictes pour une raison simple : si l’utilisateur peut modifier certains éléments de sa racine chrootée, l’isolement devient discutable.

Les erreurs fréquentes quand on veut chrooter un compte trop vite

L’erreur classique consiste à penser qu’il suffit de pointer un utilisateur vers son dossier personnel et que tout va marcher. En réalité, beaucoup de services refusent un chroot mal construit. Avec SFTP via SSH, le répertoire racine du chroot doit souvent appartenir à root et ne pas être inscriptible par l’utilisateur. Le compte doit écrire dans un sous-dossier, pas directement à la racine chrootée.

Autre erreur fréquente : vouloir fournir un shell complet dans un chroot minimal sans embarquer les bibliothèques, les commandes et l’environnement nécessaires. Résultat, l’utilisateur se connecte, puis tout casse de manière assez opaque. Une commande banale échoue, un shell ne se lance pas correctement, ou certains chemins attendus n’existent pas.

Il y a aussi le cas des permissions mal pensées. On veut enfermer un compte, mais on mélange propriété, groupes, ACL et besoins applicatifs sans plan clair. Le chroot devient alors pénible à maintenir, et chacun finit par ajouter des exceptions jusqu’à annuler l’intérêt de départ.

Le bon réflexe, c’est de partir du besoin réel. Est-ce qu’on veut un simple dépôt SFTP ? Un accès lecture seule ? Un compte qui dépose des fichiers dans un sous-répertoire précis ? Plus le besoin est net, plus le chroot reste propre. Dès qu’on essaie d’en faire un environnement polyvalent pour un utilisateur qui veut presque un vrai serveur, ça se complique très vite.

Le bon modèle mental pour ne pas se tromper

Le chroot fonctionne bien quand on l’utilise comme un couloir balisé, pas comme une forteresse parfaite. Pour un compte SFTP ou FTP, c’est souvent exactement ce qu’il faut. L’utilisateur arrive, voit uniquement son espace, dépose ses fichiers, repart. C’est clair pour lui, et c’est plus sain pour le serveur.

Si votre objectif est une isolation forte, il faut regarder plus loin : séparation stricte des droits, services dédiés, conteneurs, virtualisation, politiques SELinux, journalisation propre. Le chroot reste une brique utile, mais seulement une brique. Bien employé, il simplifie beaucoup de situations d’administration sous CentOS/Linux. Mal compris, il donne surtout l’impression d’avoir fermé la porte alors qu’une fenêtre est encore ouverte.

Pourquoi utiliser rsync entre deux serveurs Linux ?

Quand on administre deux serveurs Linux, il y a vite un besoin très concret qui revient: copier des fichiers sans tout retransférer à chaque fois. C’est là que rsync devient vraiment utile. L’outil existe depuis longtemps, il n’a rien de spectaculaire dans sa forme, mais il rend des services énormes dès qu’on doit synchroniser un répertoire web, répliquer des sauvegardes ou envoyer des fichiers de logs vers une autre machine.

Son intérêt principal tient dans sa manière de travailler. Rsync compare la source et la destination, puis n’envoie que ce qui a changé. Sur un gros volume de données, la différence est immédiate. On gagne du temps, de la bande passante et, franchement, pas mal de tranquillité quand on doit automatiser ça la nuit avec cron ou systemd timers.

Si vous gérez aussi des accès distants et des transferts sécurisés, vous pouvez prolonger le sujet avec cet article sur la copie de fichiers entre machines Linux. Et pour rester dans les usages concrets côté administration, ce billet sur les commandes Linux utiles au quotidien complète bien la logique.

À quoi sert rsync au quotidien

# synchroniser un dossier vers un autre serveur
rsync -avz /var/www/ user@serveur2:/var/www/

# sauvegarde avec suppression des fichiers effacés côté source
rsync -av --delete /data/ backup@serveur2:/backups/data/

Dans la vraie vie, rsync sert rarement pour faire joli. On l’utilise parce qu’on a un besoin simple: garder deux emplacements cohérents sans recopier bêtement l’ensemble. Typiquement, un serveur de production envoie chaque nuit une sauvegarde vers un second serveur. Autre cas classique, un développeur pousse un répertoire d’application vers une machine distante en excluant les fichiers temporaires. On le voit aussi dans les migrations, par exemple pour déplacer un site volumineux sans couper le service trop longtemps.

La commande de base ressemble à ceci:

  • rsync -avz /source/ user@serveur-distant:/destination/

Le -a conserve les permissions, dates et liens symboliques. Le -v affiche le détail des opérations. Le -z compresse les données pendant le transfert, ce qui peut être utile sur un lien lent. Dans la plupart des environnements, on l’associe à SSH pour éviter de transférer des données en clair.

Comment synchroniser des fichiers entre deux serveurs

Le plus simple consiste à lancer rsync depuis le serveur source vers le serveur cible. Par exemple, pour synchroniser un dossier de sauvegarde:

  • rsync -av /var/backups/ admin@192.0.2.10:/srv/backups/

Le slash final a son importance. /var/backups/ signifie qu’on copie le contenu du dossier. Sans ce slash, on copie le dossier lui-même dans la destination. C’est un détail qui semble mineur jusqu’au jour où l’arborescence d’arrivée n’est plus celle qu’on attendait.

Pour passer par SSH avec une clé précise ou un port non standard, on peut faire:

  • rsync -av -e "ssh -p 2222 -i /root/.ssh/id_rsa" /data/ backup@serveur2:/data/

Cette approche est propre pour les scripts automatisés. Elle évite les mots de passe interactifs et s’intègre bien dans une routine de sauvegarde. Si vous devez d’abord tester sans rien modifier, ajoutez --dry-run. C’est probablement l’option la plus rassurante de tout l’outil, parce qu’elle montre ce que rsync ferait sans toucher aux fichiers.

Les options qui font vraiment la différence

# simulation avant exécution réelle
rsync -avzn --delete /data/ backup@serveur2:/backups/data/

Au-delà de la base, quelques options changent clairement la manière de travailler. --progress permet de suivre l’avancement, ce qui est appréciable sur un gros transfert. --exclude évite d’embarquer des caches, des dossiers Git ou des fichiers temporaires. --bwlimit limite la bande passante si vous ne voulez pas saturer un lien partagé avec d’autres services.

Pour une sauvegarde plus fidèle, beaucoup utilisent aussi --numeric-ids quand les UID et GID doivent rester strictement identiques entre les deux serveurs. Dans certains contextes, --delete entre également en jeu, mais c’est une option qui mérite un minimum de respect. J’y reviens juste après, parce qu’elle peut rendre service aussi vite qu’elle peut faire disparaître des fichiers.

Il y a aussi un duo très pratique pour les sauvegardes incrémentales artisanales: --link-dest et les liens matériels. Ce n’est pas toujours nécessaire, mais sur un serveur de backup, cela permet de conserver plusieurs états d’un répertoire sans dupliquer physiquement tous les fichiers inchangés.

Pourquoi il faut être prudent avec –delete

--delete indique à rsync de supprimer, côté destination, les fichiers qui n’existent plus côté source. Sur le papier, c’est logique: si l’on veut une vraie synchronisation, la destination doit refléter la source. En pratique, c’est aussi la meilleure façon d’effacer un contenu utile si l’on s’est trompé de répertoire ou si la source n’est pas dans l’état attendu.

Un exemple simple: vous pensez synchroniser /var/www/site/, mais vous pointez par erreur vers un dossier vide. Avec --delete, rsync peut très bien nettoyer la destination pour la rendre conforme à ce dossier vide. Ce n’est pas un bug, c’est exactement ce qu’on lui a demandé.

La bonne habitude consiste à tester d’abord avec --dry-run, à relire la source et la destination, puis à activer --delete seulement quand le scénario est clair. Beaucoup d’admins préfèrent aussi journaliser les exécutions pour garder une trace des suppressions et repérer immédiatement un comportement anormal.

Des usages réels en administration Linux

Rsync est très à l’aise dans plusieurs situations concrètes. Pour un serveur web, il peut envoyer chaque nuit une copie des fichiers statiques vers une machine de secours. Pour une base de fichiers utilisateurs, il permet de répliquer régulièrement les documents sur un stockage distant. Dans un contexte de supervision, il peut aussi centraliser des logs ou des exports générés par différents serveurs.

On le croise souvent dans des scripts simples mais robustes. Un cron lance une synchronisation à 2 h du matin, écrit le résultat dans un fichier log, puis envoie une alerte seulement en cas d’erreur. Ce n’est pas l’outil le plus moderne du monde, mais il reste très bon pour faire un travail précis sans complexité inutile.

Autre usage intéressant, la préparation d’une migration. On lance un premier rsync plusieurs jours avant le basculement, puis un second juste avant la coupure pour transférer uniquement les derniers changements. Cela réduit fortement la fenêtre d’interruption et évite de recopier plusieurs centaines de gigaoctets au dernier moment.

Quand un outil dure aussi longtemps dans les environnements Linux, ce n’est généralement pas un hasard. Rsync reste là parce qu’il répond à un besoin concret, avec une logique simple: transférer seulement ce qui doit l’être, garder la main sur les options, et pouvoir automatiser le tout sans transformer une tâche banale en usine à gaz.

Comment organiser ses fichiers sous Linux sans se compliquer la vie ?

On utilise souvent Linux pour sa souplesse, mais cette liberté a un revers: si on manipule ses fichiers sans méthode, on finit vite avec des dossiers en vrac, des copies en double et un terminal qui devient plus risqué qu’utile. L’idée de ce mémento n’est pas d’aligner des commandes comme dans une fiche de révision. Le but est plutôt de garder sous la main les gestes qui servent vraiment quand on trie, déplace, cherche ou nettoie des fichiers au quotidien.

Si vous aimez avoir une base claire avant d’aller plus loin, vous pouvez aussi jeter un oeil à cet autre repère pratique. Et pour compléter avec une lecture qui aide à mieux prendre ses marques dans l’environnement Linux, ce contenu lié s’intègre naturellement à la même logique d’apprentissage concret.

Voir ce qu’il y a vraiment dans un dossier

ls -lah
find . -type f | wc -l
find . -type f -name "*.log"

La commande ls paraît banale, pourtant c’est souvent elle qui donne le ton. Utilisée seule, elle affiche une liste brute. Utilisée avec un peu plus d’attention, elle permet déjà d’éviter pas mal d’erreurs. ls -lah, par exemple, montre les fichiers cachés, les tailles lisibles et les droits. Quand on revient sur un vieux projet ou sur un répertoire système, ce simple réflexe évite de déplacer ou supprimer quelque chose sans avoir vu qu’il s’agissait d’un fichier caché ou d’un lien symbolique.

Dans la pratique, je conseille de ne pas regarder seulement les noms. Regardez aussi la taille, la date et le propriétaire. Un dossier rempli de sauvegardes oubliées saute vite aux yeux. Un fichier de configuration modifié récemment aussi. Linux donne beaucoup d’informations d’un coup, à condition de prendre deux secondes pour les lire.

Exemple utile: pour inspecter un dossier de téléchargements devenu illisible, un ls -lah ~/Téléchargements permet déjà de repérer les archives lourdes, les doublons nommés (1) ou final-final, et les fichiers cachés laissés par certains logiciels.

Copier et déplacer sans créer de désordre

cp -a projet projet.backup
mv ancien.txt archive/ancien.txt
rm -i fichier.txt

cp et mv font partie des commandes qu’on croit maîtriser trop vite. Copier un fichier, c’est simple. Copier un dossier entier demande en revanche un peu d’attention. Avec cp -r dossier source dossier-copie, on recopie l’arborescence. Avec cp -a, on conserve en plus les permissions, les dates et la structure de façon plus fidèle. C’est souvent le bon choix pour archiver un projet ou dupliquer un répertoire de configuration.

mv, lui, ne sert pas seulement à déplacer. Il sert aussi à renommer proprement. C’est pratique quand on veut remettre de l’ordre sans ouvrir d’interface graphique. Renommer rapport-v2-bon.docx en rapport-client-avril.docx avec mv prend une seconde et impose au passage une vraie discipline de nommage.

Le piège classique, c’est l’écrasement silencieux. Selon le contexte, une copie ou un déplacement peut remplacer un fichier existant. Pour garder la main, beaucoup préfèrent cp -i et mv -i, qui demandent confirmation avant d’écraser. Ce n’est pas spectaculaire, mais c’est exactement le genre d’habitude qui évite une perte bête un lundi matin.

  • cp -a projet/ sauvegarde-projet/ pour cloner un dossier en gardant ses attributs
  • mv facture.txt archives/ pour ranger un fichier
  • mv notes.txt notes-reunion.txt pour renommer sans ambiguïté

Supprimer avec prudence, surtout avec rm

rm est rapide, direct et parfois trop direct. Sous Linux, supprimer avec rm ne passe pas par une corbeille classique. Une fois parti, le fichier n’est pas censé revenir facilement. C’est pour ça qu’il vaut mieux considérer rm comme un outil de finition, pas comme une gomme qu’on utilise à la légère.

Pour un fichier isolé, rm -i reste une bonne ceinture de sécurité. Pour un dossier, rm -r enlève tout le contenu récursivement. C’est précisément là que les erreurs coûtent cher. Une mauvaise complétion automatique, un espace mal placé ou une variable vide dans un script, et on peut effacer bien plus que prévu.

Une méthode saine consiste à vérifier d’abord avec ls ou find, puis à supprimer ensuite. Autre bonne habitude: tester sa commande sur un petit sous-ensemble avant de lancer un nettoyage massif. Si vous voulez supprimer tous les fichiers .tmp d’un dossier de travail, commencez par les lister. Le terminal n’aime pas l’improvisation.

Trouver le bon fichier au bon moment

Quand l’arborescence grossit, find devient vite plus utile qu’un navigateur de fichiers. C’est la commande qui sauve du temps quand on sait à peu près ce qu’on cherche sans savoir où ça se trouve. Un find . -name "*.pdf" dans un répertoire parent permet de remonter toute une série de documents éparpillés. Un find . -type f -mtime -7 aide à voir ce qui a changé récemment.

Ce qui rend find vraiment pratique, c’est qu’il ne sert pas seulement à chercher. Il aide à préparer une action propre. On peut repérer les gros fichiers, les fichiers vieux, les extensions oubliées, ou les dossiers vides avant de décider quoi faire. Cela change tout: on arrête de nettoyer à l’aveugle.

Exemple concret: dans un dossier de projet, find . -type f -size +100M mettra rapidement en évidence une vidéo de test, une archive exportée ou un binaire oublié qui gonfle inutilement l’espace disque.

Comprendre les permissions pour éviter les blocages absurdes

Les permissions semblent techniques au départ, puis elles deviennent très concrètes. Quand un fichier refuse de s’ouvrir, de se modifier ou de s’exécuter, le problème vient souvent de là. Dans un ls -l, la suite de lettres comme rwxr-xr-- indique qui peut lire, écrire ou exécuter.

Avec chmod, on ajuste les droits. Avec chown, on change le propriétaire. Il ne s’agit pas de mémoriser toutes les combinaisons d’un coup. Il suffit de comprendre l’essentiel: un script sans droit d’exécution ne se lance pas, un fichier appartenant à un autre utilisateur peut résister à l’édition, et un dossier sans droit d’écriture empêche d’y créer quoi que ce soit.

Un cas fréquent: vous récupérez un script shell, vous essayez de le lancer, et Linux répond que l’accès est refusé. Dans bien des cas, chmod +x script.sh règle simplement le souci. Là encore, la logique compte plus que la récitation.

Les habitudes qui rendent tout ça vraiment sûr

Les bonnes commandes ne suffisent pas. Ce qui fait la différence, ce sont les habitudes. Vérifier le chemin courant avec pwd avant une suppression importante. Utiliser l’autocomplétion, mais sans lui faire une confiance aveugle. Nommer ses fichiers clairement, avec des dates cohérentes et sans variantes floues. Éviter d’agir en superutilisateur quand ce n’est pas nécessaire.

J’ajouterais une règle simple: avant toute commande destructive, pouvoir expliquer en une phrase ce qu’elle va toucher. Si ce n’est pas clair, mieux vaut s’arrêter dix secondes. C’est souvent ce petit temps mort qui évite les grosses erreurs.

Au fond, gérer ses fichiers sous Linux revient moins à connaître cent commandes qu’à bien utiliser six ou sept outils de base. ls pour voir, cp pour dupliquer, mv pour ranger, rm pour nettoyer, find pour retrouver, et un minimum de compréhension des permissions pour ne pas subir le système. Avec ça, on travaille plus vite, mais surtout plus proprement.

Quand un serveur Apache devient lent, quels réglages faut-il regarder en premier ?

Un Apache qui rame ne demande pas toujours une grosse opération de tuning. Dans beaucoup de cas, le problème vient de quelques réglages très concrets qu’on oublie parce qu’ils tournent en arrière-plan depuis longtemps. On pense tout de suite au CPU, à la RAM ou au réseau, alors que le vrai frein se cache parfois dans le mode de gestion des processus, un KeepAlive trop généreux, un module chargé pour rien ou des logs qui racontent depuis des jours ce qui ne va pas.

Le plus important, c’est d’éviter l’optimisation à l’aveugle. Changer dix paramètres d’un coup donne rarement un bon résultat, et ça rend le diagnostic presque impossible. Mieux vaut partir d’une lecture simple du comportement du serveur, puis corriger ce qui coûte vraiment du temps de réponse.

Si vous voulez déjà remettre à plat quelques bases côté pile web et hébergement, vous pouvez aussi jeter un œil à cet article. Et pour compléter avec une approche plus large sur la stabilité d’un site quand la charge monte, cette ressource apporte un bon contrepoint.

Commencer par le mode de fonctionnement d’Apache

# vérifier la configuration Apache
apachectl -t
apachectl -M
apachectl -S

Le premier réflexe utile consiste à regarder comment Apache gère ses processus ou ses threads. Beaucoup de lenteurs viennent d’un MPM mal adapté au type de trafic reçu. Entre prefork, worker et event, le comportement n’a rien d’anodin. Un serveur encore en prefork avec une charge dynamique importante peut consommer beaucoup plus de mémoire que nécessaire, surtout si PHP est encore branché d’une façon ancienne.

En pratique, il faut vérifier combien de processus sont lancés, s’ils restent occupés longtemps et si la machine commence à échanger sur le disque faute de mémoire libre. Un Apache lent n’est pas toujours saturé au sens spectaculaire du terme. Il peut simplement être engorgé par trop de workers ouverts, ou au contraire être trop court en capacité et mettre les requêtes en file d’attente.

Les directives comme StartServers, MinSpareServers, MaxSpareServers, MaxRequestWorkers ou ServerLimit méritent donc une vraie lecture. Le bon réglage dépend du volume de connexions, du poids de l’application servie et de la mémoire réellement disponible. Copier une configuration trouvée sur un forum n’a pas beaucoup de sens si votre trafic, vos modules et votre version de PHP n’ont rien à voir.

KeepAlive, utile mais parfois trop coûteux

# quelques réglages souvent regardés
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 2

<IfModule mpm_event_module>
    StartServers             2
    ThreadsPerChild         25
    MaxRequestWorkers      150
</IfModule>

KeepAlive est souvent un bon allié, parce qu’il évite d’ouvrir une nouvelle connexion TCP pour chaque ressource. Sur un site avec plusieurs fichiers statiques, c’est utile. Le problème arrive quand la durée d’attente est trop longue. Avec un KeepAliveTimeout élevé, des processus restent accrochés à des clients inactifs au lieu de traiter de nouvelles requêtes.

Sur un serveur peu chargé, cela passe inaperçu. Sous montée en charge, c’est souvent l’un des premiers points à vérifier. Un timeout court, cohérent avec le comportement du site, libère plus vite les ressources. Il faut aussi regarder MaxKeepAliveRequests. Une valeur trop basse casse l’intérêt de la persistance, une valeur trop large ne sert pas toujours davantage.

Le bon réglage n’est pas théorique. Il se mesure. Si vos visiteurs chargent des pages courtes et repartent vite, garder des connexions ouvertes trop longtemps n’apporte presque rien. Si le front sert encore beaucoup d’assets via Apache, l’effet peut être différent. C’est précisément pour ça qu’il vaut mieux observer les temps de réponse et le nombre de connexions actives avant de toucher au fichier de configuration.

Faire le tri dans les modules et la compression

Un autre classique, c’est l’empilement de modules activés “au cas où”. Avec le temps, on laisse mod_status, mod_autoindex, des réécritures complexes, des filtres de sortie ou des briques de compatibilité qui ne rendent plus vraiment service. Chaque module n’a pas le même coût, mais plus la pile est chargée, plus le chemin de traitement peut devenir lourd.

Il ne s’agit pas de désactiver tout ce qui bouge. Il faut repérer ce qui est réellement utilisé. Les modules de compression, par exemple, sont très utiles pour réduire le poids des réponses, mais ils peuvent aussi ajouter de la charge CPU si le serveur compresse trop agressivement ou compresse des contenus qui le sont déjà. Gzip ou Brotli doivent être réglés avec un peu de bon sens. Compresser du HTML, du CSS ou du JavaScript est souvent rentable. Compresser à nouveau des images ou des archives ne l’est généralement pas.

Il faut aussi regarder si Apache sert des fichiers statiques qui pourraient être déportés vers un cache, un proxy ou un CDN. Quand le serveur principal fait tout lui-même, la lenteur perçue n’est pas toujours liée à une seule page dynamique. Elle peut venir de centaines de petites réponses statiques délivrées dans des conditions pas idéales.

Lire les logs avant de toucher aux curseurs

Les logs restent la source la plus sous-exploitée quand un serveur commence à ralentir. L’access log permet déjà de voir des motifs simples, comme une explosion de requêtes sur une URL, un bot agressif, ou une ressource appelée beaucoup plus que prévu. L’error log, lui, montre souvent des signaux ignorés pendant des semaines : délais d’exécution, backend qui répond mal, problèmes de proxy, modules qui génèrent des erreurs répétées.

Activer une mesure plus fine pendant un créneau court peut aussi aider. Le but n’est pas de noyer la machine sous du debug permanent, mais d’obtenir des indices propres. Quand on voit qu’une poignée de routes concentre la majorité du temps passé, la suite devient plus claire. On sait si le problème est Apache lui-même, PHP-FPM, la base de données, un reverse proxy, ou simplement une application trop bavarde.

Les logs évitent surtout un piège courant : accuser le serveur web alors que le ralentissement vient d’ailleurs. Apache sert de façade, donc il donne l’impression d’être responsable. En réalité, il est souvent seulement l’endroit où la lenteur devient visible.

Adopter une méthode pragmatique au lieu d’optimiser au hasard

Quand un serveur Apache devient lent, il vaut mieux avancer dans un ordre simple. D’abord mesurer : charge système, mémoire, nombre de workers occupés, temps de réponse, volume de connexions. Ensuite identifier le goulot réel. Puis changer un paramètre à la fois et vérifier l’effet. Cette discipline paraît un peu lente, mais elle fait gagner du temps, justement parce qu’elle évite les faux remèdes.

Une bonne séquence consiste souvent à vérifier d’abord le MPM, ensuite KeepAlive, puis la liste des modules, la compression, et enfin les logs applicatifs ou proxy si rien n’explique encore les symptômes. À chaque étape, il faut noter l’état initial, le changement appliqué et le résultat observé. C’est basique, mais c’est ce qui permet de revenir en arrière proprement si le réglage aggrave la situation.

Le vrai objectif n’est pas d’obtenir une configuration “parfaite” sur le papier. C’est d’avoir un Apache cohérent avec le trafic réel, la machine réelle et l’application réelle. Entre un serveur vitrine, un WordPress chargé en plugins, une API sous reverse proxy ou un intranet peu fréquenté, les priorités ne sont pas les mêmes. Les premiers réglages à regarder sont toujours ceux qui bloquent la capacité immédiate du serveur à répondre sans attendre inutilement.

À quoi sert PAM sous Linux et pourquoi on en entend si souvent parler ?

Quand on administre une machine Linux ou Unix, on croise vite le mot PAM sans toujours comprendre ce qu’il fait réellement. Pourtant, il est là dans des moments très concrets: une connexion SSH, un changement de mot de passe, une ouverture de session locale, parfois même un accès à sudo. PAM, pour Pluggable Authentication Modules, n’est pas un service de plus qu’on lance en arrière-plan. C’est plutôt une couche d’intermédiaire, un cadre commun qui permet aux applications de déléguer l’authentification, la gestion de compte ou des règles de session sans réinventer le sujet à chaque fois.

Dit autrement, PAM évite qu’OpenSSH, login, su, sudo ou un gestionnaire d’affichage aient chacun leur propre logique maison pour vérifier qui a le droit d’entrer. Ce principe paraît discret, mais il simplifie énormément l’administration d’un système et rend les politiques de sécurité plus cohérentes d’un service à l’autre.

Pourquoi PAM existe-t-il au juste ?

# exemple courant: pile PAM pour sshd
cat /etc/pam.d/sshd

# tester un service lié à l'authentification
sudo pam-auth-update

Avant PAM, chaque programme pouvait embarquer sa propre façon d’authentifier un utilisateur. C’était pénible à maintenir, difficile à harmoniser et source d’écarts de sécurité. Avec PAM, les développeurs d’applications n’ont plus besoin de coder eux-mêmes toutes les variantes possibles de l’authentification. Ils appellent une interface standard, puis le système décide quels modules appliquer.

C’est ce qui permet, par exemple, de demander un mot de passe classique sur une machine, d’imposer des règles supplémentaires sur une autre, ou encore d’intégrer une authentification centralisée via LDAP, Kerberos ou un second facteur, sans remplacer tous les services un par un. On adapte la politique, pas toute l’architecture.

Si vous vous intéressez plus largement aux mécanismes de sécurité sous Unix, vous pouvez aussi jeter un œil à cet article sur la gestion des accès et des droits, qui complète bien la logique de PAM dans un environnement multi-utilisateur.

Comment PAM s’insère-t-il entre les services et l’authentification ?

Le point clé, c’est que PAM se place entre l’application et la méthode d’authentification. Un service comme SSH ne va pas directement lire /etc/shadow et décider seul du résultat. Il appelle PAM. Ensuite, PAM consulte sa configuration et exécute les modules prévus pour ce service.

En pratique, la chaîne ressemble souvent à ceci: un utilisateur tente de se connecter, le service transmet la demande à PAM, PAM applique une pile de modules, puis renvoie une réponse au service. Cette réponse peut être “oui”, “non”, ou parfois “oui, mais avec des conditions” comme des restrictions horaires, un mot de passe expiré ou l’ouverture d’une session avec certains montages et variables d’environnement.

Les fichiers de configuration se trouvent généralement dans /etc/pam.d/. Chaque service y possède souvent son propre fichier, par exemple sshd, sudo ou login. On y voit des types comme auth, account, password et session. Ce découpage est très utile:

  • auth vérifie l’identité de l’utilisateur
  • account contrôle si le compte est autorisé à accéder au service
  • password gère le changement de mot de passe
  • session prépare et ferme le contexte de session

Ce fonctionnement modulaire explique pourquoi PAM est si présent dans l’écosystème Unix: il sert de point d’assemblage entre les services et les règles de sécurité réelles.

Quels sont les cas d’usage les plus courants ?

# extrait typique d'une règle PAM
auth    required    pam_unix.so
account required    pam_unix.so
session required    pam_limits.so

Le cas le plus évident reste l’authentification par mot de passe local, mais PAM va beaucoup plus loin. Il peut refuser une connexion si le compte est verrouillé, limiter l’accès à certains groupes, empêcher un mot de passe trop faible, exécuter un montage automatique à l’ouverture de session ou afficher un message légal avant connexion.

Dans une entreprise, PAM est souvent impliqué lorsqu’on relie des machines Linux à un annuaire central. L’utilisateur garde une expérience relativement uniforme, tandis que l’équipe système applique une politique commune. Sur un poste autonome, PAM peut aussi servir à durcir sudo, imposer des règles de complexité de mot de passe ou journaliser plus finement certaines ouvertures de session.

Pour replacer cela dans l’administration quotidienne, on peut faire le lien avec cette ressource sur les bases de l’authentification sous Linux, utile pour comprendre où PAM intervient et où il laisse la main aux autres composants du système.

Quelles précautions prendre avant de modifier sa configuration PAM ?

C’est le point où il faut rester calme. PAM est puissant, mais une mauvaise ligne peut vous bloquer hors de la machine, surtout si vous modifiez l’authentification distante sur un serveur que vous administrez en SSH. Le vrai risque n’est pas seulement de casser une connexion, c’est de casser toutes les suivantes.

La première précaution consiste à garder une session root déjà ouverte avant tout changement. Ainsi, si la nouvelle configuration empêche les connexions normales, vous avez encore une porte de sortie. La deuxième est de sauvegarder les fichiers PAM concernés avant édition. La troisième, souvent négligée, est de tester petit à petit au lieu de réécrire tout un empilement de modules d’un coup.

Il vaut aussi mieux comprendre les indicateurs de contrôle comme required, requisite, sufficient et optional. Ils changent complètement le comportement de la pile. Un module correct au mauvais endroit, avec le mauvais drapeau, peut produire un résultat très différent de celui attendu.

Sur une machine sensible, le bon réflexe est simple: documenter chaque changement, tester depuis une seconde session, prévoir un retour arrière rapide et éviter les modifications “à chaud” sans filet. PAM n’est pas compliqué parce qu’il serait obscur par nature. Il devient délicat parce qu’il est placé exactement à l’endroit où une erreur coupe l’accès.

Une fois qu’on l’a compris comme une couche d’orchestration entre services, comptes et politiques de sécurité, PAM devient beaucoup moins intimidant. On voit mieux pourquoi il est partout, pourquoi il reste central sur les systèmes Unix modernes, et pourquoi les administrateurs le manipulent avec autant de respect.

Créer une paire de clés SSH pour s’authentifier sans mot de passe

A quoi ça sert?

Principalement pour vous connecter à un terminal distant sans mot de passe. Le principe étant d’avoir une paire de clé privée/publique. Vosu déposez la clé publique sur le terminal distant, ensuite pour vous y connecter il suffit de ssh à l’adresse IP

Il faut d’abord installer OpenSSH, qui va vous donner les outils

Génération de la paire de clé SSH

ssh-keygen -t rsa -C "your_email@example.com"

Vous serez amené à entrer un mot de passe (optionnel) appelée passphrase.

Uploader la clé publique sur le serveur distant

Il s’agit d’uploader la clé dans le répertoire /home/user. An l’absence de logiciel FTP, vous pouvez faire un SSH. LE plus simple est de se logger en root dans le serveur distant et de copier à la mains les texte des clés publiques. Le plus simple eset de copier coller le texte de la clé publique et le coller dans le fichier authorized_keys du serveur.

Connectez vous en root et éditez le fichier authorized_keys.

ssh-copy-id (source)

// syntaxe générale
ssh-copy-id [-f] [-n] [-i identity file] [-p port] [-o ssh_option] [user@]hostname

ssh-copy-id root@123.123.123.123

Créer un serveur FTP dans un Droplet Digital Ocean

Vous pouvez essayer de faire ce tuto dans un container docker sous Debian

On va d’abord créer un droplet, puis mettre à jour le package et installer Proftpd

apt update
apt install proftpd

On va créer un utilisateur FTP (pas un utiliser avec Shell), on est sous root

useradd yvon -d /home/yvon -m -s /bin/false yvon  // ce user ne possède pas de shell, et son répertoire home est /home/yvon
passwd yvon

//définir le mot de passe

Le but est que l’utilisateur lorsqu’il se connecte avec Filezilla, voit le répertoire /home/yvon, pour y mettre ses fichiers

Puis on va configurer le fichier /etc/proftpd/proftpd.conf

//Afin de contraindre le répertoire à /home/yvon on doit avoir

DefaultRoot ~

// comme yvon n'a pas accès au shell
RequireValidShell off

// spécifier les port passif (intervalle de ports)
PassivePorts 49152 65534

Il faut ouvrir les port 21 et la plage de port dans

ufw allow 21/tcp
ufw allow 49152:65534/tcp

// vérifier le status
ufw status

To                         Action      From
--                         ------      ----
21/tcp                     ALLOW       Anywhere                  
49152:65534/tcp            ALLOW       Anywhere                  
21/tcp (v6)                ALLOW       Anywhere (v6)             
49152:65534/tcp (v6)       ALLOW       Anywhere (v6)   

Faire un script bash pour envoyer des fichiers vers ce serveur FTP

Nous allons d’abord installer le client ftp si ce n’est déjà fait

apt install ftp

// upload d'un fichier (il faut créer le user et le login)
ftp -n 165.22.194.80 <<EOF
user yvon motdepasse
put fichier_local.txt
quit
EOF

On peut faire l’équivalent en script bash c’est plus sympa pour la simplicité

//script bash  syncftp.sh

// on définit les variables
HOST=165.22.194.80
USER=yvon
PASS=123
FILE=date.log

ftp -n $HOST << EOF
user $USER $PASS
put $FILE
quit
EOF

Mettez les lignes dans l’ordre, au début j’ai fait une bêtise j’ai mis le put avant le user !

Voici une version un peu améliorée, va setter le mode de transfert en binary malgré que ce soit du texte, ceci pour ménager les caractères spéciaux, les retour chariots CLRF <-> LF, le ls va lister le fichier pour vérifier que le fichier est bien uploadé !

HOST=165.22.194.80
USER=yvon
PASS=123
FILE=date.log

ftp -n $HOST << EOF
user $USER $PASS
binary
put $FILE
ls
quit
EOF

Cours administrateur de serveur Web Dans un Linux Debian Dans un Docker

Que contient ce cours Linux et administration de serveur web?

A partir d’une image Docker de Debian, on va installer différents éléments tels nginx, php-fpm, postgreSQL et faire tourner un serveur web. Nous allons voir la configuration d’un vhost, expliquer l’architecture client serveur, les DNS?

Puis on va installer un serveur FTP proftpD, nftable, fail2ban pour protéger le serveur web.

Puis on va faire un backup et un certificat autosigné, puis un certificat Let’s Encrypt

Nous allons aussi voir les commandes de base de Linux, les outils de base de Linux,

Sommaire et liens vers les cours

Article bonus sur Nginx

Introduction à nftables le remplaçant de iptables

Installation de nftables

Visualisation des règles (rules)

nft list ruleset


#Si vous avez le message même en étant root :

netlink: Error: cache initialization failed: Operation not permitted 

#il faut lancer le container avec le flag --privileged

docker run --privileged -it <image_docker>

Rien n’apparait, il n’y a pas de règles on va en créer une, d’abord on va créer une table

nft add table inet filter

puis nft list ruleset

table inet filter {
}

C’est vide pour l’instant, on va ajouter une règle pour autoriser les connexion sur le port 22

nft add rule inet filter input tcp dport 22 accept

mais vous risquez d'avoir l'erreur

Error: Could not process rule: No such file or directory
add rule inet filter input tcp dport 22 accept
                     ^^^^^                                                         

Comment ajouter une règle

nftable organise les règle en hiérarchie : table (conteneur de niveau supérieur) > chaine (groupe de règle dans une table) > règle (instruction de filtrage)

Types de tables:

  • ip : ipv4
  • ip6 : ipv6
  • inet : ipv4 + ipv6
  • arp : ARP
  • bridge : bridge
  • netdev : interface réseau

Création table puis chaine puis règle

# Créer la table inet filter (on vient de le faire)
nft add table inet filter

# Créer la chaîne input
nft add chain inet filter input { type filter hook input priority 0 \; policy accept \; }

# Maintenant ajouter votre règle SSH
nft add rule inet filter input tcp dport 22 accept

# lister les règles
nft list ruleset

table inet filter {
        chain input {
                type filter hook input priority filter; policy accept;
                tcp dport 22 accept
        }
}

Commandes de diagnostic

# voir une table spécifique
nft list table inet filter

# Voir le contenu d'une table spécifique
nft list table inet filter

# Voir les chaînes d'une table
nft list chains inet filter

# Voir une chaîne spécifique
nft list chain inet filter input

Générer un certificat autosigné dans Debian et mapper les ports docker et hôte

Cet article fait suite à l’article sur la mise en place d’un serveur web Nginx et php-fpm, suivi de Postgresql.

J’avais déjà fait par le passé un blog sur comment configurer pour Apache un https, il suffisait de pointer vers les certificats SSL dans le fichier vhost

Un certificat autosigné ne sert que lors de la phase de développement. EN effet si vous l’utilisez en production, il y a aura des avertissements. Les certificats permettent une marque de confiance, donc d’une autorité tierce de confiance. De ce fait un certificat autosigné n’aura aucue valeur, puisuqe c’est l’éditeur de site qui le génère. Il faut que ce soit un tiers indépendant qui le fasse, comme par exemple Lets Encrypt. Ce dernier ne génère que des certificat ordinaires, mais utilisable en production. Si vous voulez des certificats plus qualitatifs, comme les certificats EV, il faudra les acheter sur des sites spécialisés.

Nous allons générer un certificat SSL autosigné

mkdir -p /etc/ssl/private/mycert && cd /etc/ssl/private/mycert

ou vous pouvez aller dans le répertoire mycert pour avoir une commande plus courte
cd /etc/ssl/private

mkdir -p /mycert && cd mycert

Le flag -p permet de créer les dossier parents manquant dans la commande mkdir

Génération du certificat (ce sont deux fichiers)

openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout selfsigned.key \
  -out selfsigned.crt \
  -subj "/C=FR/ST=France/L=Paris/O=MonEntreprise/CN=localhost"
  • -x509 : pour un certificat autosigné.
  • -nodes : ne pas chiffrer la clé privée (pas de mot de passe).
  • -days 365 : durée de validité (365 jours).
  • -newkey rsa:2048 : crée une nouvelle clé RSA 2048 bits.
  • -keyout : chemin vers la clé privée.
  • -out : chemin vers le fichier de certificat.
  • -subj : informations du certificat.

Maintenant dans le répertoire mycert vous avez les fichiers selfsigned.crt et selfsigned.key

Modification du fichier de configuration Nginx qu’on a vu dans cet article

# Redirection HTTP vers HTTPS (optionnel mais recommandé)
server {
    listen 80;
    server_name phpsite;
    return 301 https://$host$request_uri;
}

# Bloc HTTPS avec certificat autosigné
server {
    listen 443 ssl;
    server_name phpsite;

    ssl_certificate     /etc/ssl/private/mycert/selfsigned.crt;
    ssl_certificate_key /etc/ssl/private/mycert/selfsigned.key;

    root /var/www/phpsite;
    index index.php index.html;

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass 127.0.0.1:9000;
    }
}

Votre site non https va rediriger vers le https.

$ curl https://phpsite/info.php
// néanmoins vous aurez un erreur de type 
curl: (60) SSL certificate problem: self-signed certificate
More details here: https://curl.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.

Ceci est dû au fait que ce soit un certificat autocertifié. Pour bypasser cette vérification, il faut rajouter le flag -k à la requête

curl -k https://phpsite/info.php

Redémarrer votre container docker et redémarrer les services

vous avez installé nginx, php-fpm, postgresql, et configuré votre vhost. Le soucis c’est la prochaine que vous faites un docker start <Id container> (après avoir stoppé votre container (ce ne sera pas le cas si vous fiates un exit de votre container), il faut redémarrer les services. Vous pouvez intégrer une commande

De même le vhost que vous avez ajouté dans /etc/hosts a disparu ! ceci est dû à la nature éphémère du container docker, mais heureusement il existe un flag pour ajouter le vhost quand vous faites un run

docker run -d \
  --name mon-site \
  -p 80:80 \
  --add-host=phpsite:127.0.0.1 \
  mon-image

// ce qui donne dans notre cas sauf qu'on est en mode interactif

docker run -it \
  --name phpsite \
  -p 80:80 \
  --add-host=phpsite:127.0.0.1 \
  debian-nginx

// il nous manque la commande bash pour démarrer php-fpm et nginx (remplacez le nom de l'image par votre image)
docker run -it \
  --name phpsite \
  -p 80:80 \
  --add-host=phpsite:127.0.0.1 \
  nginx_postgres_image \
  bash -c "/usr/sbin/php-fpm8.2 -F && nginx -g 'daemon off;'"


// ce qui donne en une seul ligne
docker run -it --name phpsite -p 80:80 --add-host=phpsite:127.0.0.1 nginx_postgres_image  bash -c "/usr/sbin/php-fpm8.2 -F && nginx -g 'daemon off;'"

// en non interactif
docker run -d --name phpsite -p 80:80 -p 443:443 --add-host=phpsite:127.0.0.1 nginx_postgres_image  bash -c "/usr/sbin/php-fpm8.2 -F && nginx -g 'daemon off;'"

Attention avec la syntaxe ci-dessus pour le bash bash -c « /usr/sbin/php-fpm8.2 -F && nginx -g ‘daemon off;' », ça ne va pas marcher car php-fpm étant lancé en foreground, il ne laissera pas la main à nginx pour démarrer, donc il faut remplacer le double && par le simple & , qui va lancer php-fpm en background

docker run -d --name phpsite -p 80:80 -p 443:443 --add-host=phpsite:127.0.0.1 nginx_postgres_image  bash -c "/usr/sbin/php-fpm8.2 -F & nginx -g 'daemon off;'"

On peut améliorer ceci en mettant dans un script bash. Nous pouvons aussi inclure le démarrage de postgresql afin d’avoir une stack complète pour développer.

Accéder au site phpsite depuis l’hôte

La partie intéressante est de se connecter à notre site dans docker depuis notre navigateur ou curl, car on a mappé les ports de docker et de l’hôte. Pour ce faire nous devons ajouter au fichier hosts de l’hôte : 127.0.0.1 phpsite.

//  depuis l'hôte

curl -k https://phpsite/info.php

// depuis votre navigateur vous aurez un avertissement de site non sécurisé, confirmez l'exception.

Prochaine étape nous allons plutôt explorer les volumes docker afin de pouvoir héberger les scripts php sur notre hôte.

Les volumes sous Docker c’est quoi?

C’est un répertoire sur l’hôte, qui sert à herberger des fichiers de code, mais accessible par le container docker, voyez ça comme un mount d’un drive sur un système de fichier Linux. Cela permet de travailler plus facilement et efficacement avec des container Docker. En effet notreIDE préféré est sur notre hôte et pas sur un container docker.

Dans la suite, mon répertoire se trouve dans le drive E: sur Windows dans le répertoire volume_nginx

docker run -d --name phpsite -p 80:80 -p 443:443 -v E:\volume_nginx:/var/www/phpsite --add-host=phpsite:127.0.0.1 nginx_postgres_image  bash -c "/usr/sbin/php-fpm8.2 -F & nginx -g 'daemon off;'"


// avec la ligne -v E:\volume_nginx:/var/www/phpsite on monte le répertoire hôte dans le container docker, du coup ce dernier va être masqué par le répertoire windows

// connextez vous en interactif dans le container en question

$ docker exec -it <idContainer> bash
// allez dans le répertoire /var/www/phpsite, il est vide pour l'instant mais créez un fichier index.php dedans et faites un ls vous verrez ce fichier. Félicitation vous avez réussi à connecter un volume ! 

Avouez que maintenant vous allez être beaucoup plus confortable pour faire un site web en php !

Générer un meilleur certificat SSL avec Let’s Encrypt

Avec une autorité externe les certificats sont de milleurs qualité. Let’s Encrypt délivre des certificats gratuitement et de grade production. MAIS il faut que votre site soit accessible depuis internet, car Let’s Encrypt va accéder à votre site pour installer des fichiers.

#installation de certbot
apt install certbot

# Génération du certificat
certbot certonly --webroot -w /var/www/html -d votre-domaine.com -d www.votre-domaine.com

Installation de Postgresql dans un container docker Debian

Installation de postgresSQL

apt update
apt install postgresql

Nous sommes dans le cas où il n’y a pas systemd ou supervisor, et cet article reprend la suite de la procédure d’installation de nginx et php-fpm

Normalement si vous avez installé avec apt, pas besoin de créer un répertoire ni d’initialiser une base de données.

Nous allons maintenant lancer postgresql, la commande est un peut longue et vous ne pouvez pas lancer en root

postgres /usr/lib/postgresql/15/bin/postgres -D /var/lib/postgresql/15/main


"root" execution of the PostgreSQL server is not permitted.
The server must be started under an unprivileged user ID to prevent
possible system security compromise.  See the documentation for
more information on how to properly start the server.

De plus si on veut ne pas taper cette commande il vaut mieux ajouter au PATH

export PATH="$PATH:/usr/lib/postgresql/15/bin"

La commande à faire est via un utilisateur non root, il faut créer un utilisateur

// création d'utilisateur 
adduser refschool   // il vaut mieux utiliser adduser car useradd nécessite de setter le password avec la commande passwd

// on ajouter refschool dans la liste de sudoer
usermod -aG sudo refschool  // en fait on l'ajoute au groupe sudoer

On exécute en tant que utilisateur postgres

sudo -u postgres /usr/lib/postgresql/15/bin/postgres -D /var/lib/postgresql/15/main

Si vous avez l’erreur suivante : postgres: could not access the server configuration file « /var/lib/postgresql/15/main/postgresql.conf »: No such file or directory

c’est que la base de donnée a été initialisée mais ne contient pas le fichier de configuration postgresql.conf.

Nous allons initialiser la base dans un autre répertoire

mkdir -p /opt/postgres_data
chown postgres:postgres /opt/postgres_data
sudo -u postgres /usr/lib/postgresql/15/bin/initdb -D /opt/postgres_data

Une base de données sera initialisée dans le répertoire /opt/postgres_data

Sortie de cette commande

The files belonging to this database system will be owned by user "postgres".
This user must also own the server process.

The database cluster will be initialized with locale "C".                                                               The default database encoding has accordingly been set to "SQL_ASCII".                                                  The default text search configuration will be set to "english".

Data page checksums are disabled.

fixing permissions on existing directory /opt/postgres_data ... ok
creating subdirectories ... ok
selecting dynamic shared memory implementation ... posix
selecting default max_connections ... 100
selecting default shared_buffers ... 128MB
selecting default time zone ... Etc/UTC
creating configuration files ... ok
running bootstrap script ... ok
performing post-bootstrap initialization ... ok
syncing data to disk ... ok

initdb: warning: enabling "trust" authentication for local connections
initdb: hint: You can change this by editing pg_hba.conf or using the option -A, or --auth-local and --auth-host, the next time you run initdb.

Success. You can now start the database server using:

    /usr/lib/postgresql/15/bin/pg_ctl -D /opt/postgres_data -l logfile start

Attention lorsque vous arrêtez Postgresql, la commande pour le redémarrer est différente, en effet, on fait ici (ci-dessus) un initdb, qu’on fait une seule fois, pour les fois suivantes:

// à exécuter lorsque vous êtes loggé en utilisateur refschool (mais pas root)


sudo -u postgres /usr/lib/postgresql/15/bin/postgres -D /opt/postgres_data

Pratique des commandes principales de Postgresql

Une fois que vous êtes dans le prompt de Postgresql, vous pouvez faire les commandes suivantes:

Je rappelle qu’il faut démarrer postgresql avant, vous ne pouvez le faire en root, donc switchez sur un user normal et lancez la commande suivante :

// vous êtes en user normal (non root)

sudo -u postgres /usr/lib/postgresql/15/bin/postgres -D /opt/postgres_data

//puis dans un autre shell connectez vous avec la commande psql en tant que user postgres

psql -U postgres

lister les bases de données

\l  ou \list

postgres=# \list
                                             List of databases
   Name    |  Owner   | Encoding  | Collate | Ctype | ICU Locale | Locale Provider |   Access privileges   
-----------+----------+-----------+---------+-------+------------+-----------------+-----------------------
 devdb     | devuser  | SQL_ASCII | C       | C     |            | libc            | =Tc/devuser          +
           |          |           |         |       |            |                 | devuser=CTc/devuser
 postgres  | postgres | SQL_ASCII | C       | C     |            | libc            | 
 template0 | postgres | SQL_ASCII | C       | C     |            | libc            | =c/postgres          +
           |          |           |         |       |            |                 | postgres=CTc/postgres
 template1 | postgres | SQL_ASCII | C       | C     |            | libc            | =c/postgres          +
           |          |           |         |       |            |                 | postgres=CTc/postgres
(4 rows)

Choisir une base de donnés

Nous devons comme dans tous les sytème sde base de données choisir une base pour faire des requêtes

postgres=# \c devdb
You are now connected to database "devdb" as user "postgres".

// à noter que le prompt a changé

Créer une table et lister les tables

Coller ce code

devdb=# CREATE TABLE produit (
    id SERIAL PRIMARY KEY,
    nom VARCHAR(100) NOT NULL,
    description TEXT,
    prix NUMERIC(10,2) NOT NULL,
    stock INTEGER DEFAULT 0,
    date_creation TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);


devdb=# \dt
          List of relations
 Schema |  Name   | Type  |  Owner   
--------+---------+-------+----------
 public | produit | table | postgres
(1 row)

Accessoirement pour lister les schémas dans toutes les bases de données
\dt *.*

pour sortir du mode "pager" appuyez sur la touche "q"

Exécuter une requête SQL pour insérer des données

On va insérer des données :

devdb=# INSERT INTO produit (nom, description, prix, stock)
VALUES 
('Iphone', 'Description du Iphone', 1999, 10),
('Samsung', 'Description du Samsung', 299, 5);

// afficher les données de la table avec un SELECT
// attention il faut respecter la casse

SELECT * FROM produit

Faire un dump de la base de données

On va utiliser l’utilitaire pg_dump

pg_dump -U postgres -d devdb -f sav.sql

Supervisor pour Linux, un système de controle de process

Supervisor est un programme qui manage l’exécution des autres programmes. Il démarre, arrête ou redémarre un programme en cas de crash, et monitore leur status.

Ce que fait Supervisor:

Process management :

Au boot de Linux, il peut démarrer plusieurs programmes, et les garde en exécution continuellement.

Redémarrage automatique

Supervisor peut redémarrer un process qui a crashé

Logging :

Enregistre dans un fichier de logs tous les événements

Monitoring :

Vous pouvez checker le status de chaque programme managé via une interface web, ou en ligne de commande.

Dans ce tutoriel sur le load balancing, on a un container Docker qui fait tourner plusieurs process, un process Nginx, et 3 process python. Il n’est peut être pas un système très stable, et un process peut s’arrêter, donc il faudrait le redémarrer manuellement. D’où l’utilisation de Supervisor qui nous garantit que les process vont redémarrer automatique.

Le Supervisor démarre en premier, et ensuite démarre les autres process en lisant le fichier ci-dessous

[supervisord]
nodaemon=true
user=root

[program:nginx]
command=nginx -g "daemon off;"
autostart=true
autorestart=true
stderr_logfile=/var/log/supervisor/nginx_err.log
stdout_logfile=/var/log/supervisor/nginx_out.log

[program:python-server-1]
command=python3 /app/app.py 8001
directory=/app
autostart=true
autorestart=true
stderr_logfile=/var/log/supervisor/python1_err.log
stdout_logfile=/var/log/supervisor/python1_out.log

[program:python-server-2]
command=python3 /app/app.py 8002
directory=/app
autostart=true
autorestart=true
stderr_logfile=/var/log/supervisor/python2_err.log
stdout_logfile=/var/log/supervisor/python2_out.log

[program:python-server-3]
command=python3 /app/app.py 8003
directory=/app
autostart=true
autorestart=true
stderr_logfile=/var/log/supervisor/python3_err.log
stdout_logfile=/var/log/supervisor/python3_out.log

Tous les process sont monitorés par Supervisor.

Que risque t on si on n’a pas Supervisor?

Voici ce qui pourrit se passer si on n’a pas de Supervisor qui fait du redémarrage automatique, du logging, du monitoring :

  1. Défaillance du conteneur suite à la défaillance d’un seul processus
    Sans Supervisor, si votre processus principal s’arrête, le conteneur entier s’arrête. Par exemple :

Si vous démarrez uniquement Nginx, vous n’avez pas de backend Python.
Si vous démarrez un seul serveur Python, vous n’avez pas d’équilibrage de charge.
Si vous essayez de démarrer plusieurs processus avec des scripts shell et que l’un d’eux plante, les autres peuvent continuer à s’exécuter, mais vous perdez la supervision.

  1. Absence de récupération automatique
    En cas de panne d’un serveur Python (due à des bugs, des problèmes de mémoire, etc.) :

Avec Supervisor : Redémarrage automatique du serveur en panne en quelques secondes.
Sans Supervisor : Le serveur reste inactif, réduisant votre capacité de 3 à 2 serveurs, puis à 1, puis à 0.

  1. Processus d’arrière-plan peu fiables
    Si vous essayez de démarrer plusieurs processus avec des scripts shell, comme :
bashpython3 app.py 8001 &
python3 app.py 8002 &
python3 app.py 8003 &
nginx -g "daemon off;" Risques :

Les processus d’arrière-plan peuvent devenir orphelins.
Si le processus nginx principal meurt, le conteneur s’arrête, mais les processus Python peuvent continuer à s’exécuter comme des zombies.
Il est impossible de vérifier facilement si les processus d’arrière-plan sont réellement en cours d’exécution.
La gestion des journaux devient un cauchemar.

Pannes silencieuses
Sans surveillance des processus :

Vous ne saurez pas quand un serveur back-end tombe en panne.
Nginx tentera sans cesse de rediriger le trafic vers des serveurs inactifs.
Les utilisateurs reçoivent des erreurs 502/503, sans que vous sachiez pourquoi.
Absence de journalisation centralisée pour déboguer les problèmes.

  1. Difficultés opérationnelles

Déploiement : Difficile de garantir le bon démarrage de tous les processus.
Débogage : Impossible de déterminer facilement le processus à l’origine des problèmes.
Mise à l’échelle : Impossible d’ajouter ou de supprimer facilement des serveurs back-end.
Contrôles de santé : Impossible de vérifier par programmation si tous les services sont en cours d’exécution.

Tuto : Load balancer avec Nginx dans un unique container Docker

Ce tuto concerne la mise en place à titre d’illustration d’un load balancer pour en comprendre les principes, dans un seul container docker. Dans ce container docker, il ya aura Linux Debian et tous les programmes nécessaires, dont Nginx bien sûr, mais aussi Supervisor. En effet faire tourner dans un docker Nginx et plusieurs instances de serveur n’est pas très compatible, puisque Docker n’assure qu’un process, dans le cas du load balancer on a Nginx et trois instances de serveur.

Supervisor permet de gérer à l’instar de SystemD les process, c’est un programme qui manage les autres programmes.

On se procure l’image Docker de Debian Linux officiel

docker pull debian
docker run -it debian

Ensuite on installe les programmes nécessaire pour faire tourner le load balancer

// ici on installe dans le docker les programmes nécessaire
// mise à jour de la BDD des packages
apt update


apt install nginx python3 supervisor  curl

Configuration du fichier supervisord.conf

Tout d’abord nous allons créer deux répertoires, un pour stocker le fichier de configuration, et un pour les logs

mkdir -p /etc/supervisor/conf.d/
mkdir -p /var/log/supervisor/
// créons le fichier de configuration qui n'existe pas au début
nano /etc/supervisor/conf.d/supervisord.conf
[supervisord]
nodaemon=true
user=root

[program:nginx]
command=nginx -g "daemon off;"
autostart=true
autorestart=true
stderr_logfile=/var/log/supervisor/nginx_err.log
stdout_logfile=/var/log/supervisor/nginx_out.log

[program:python-server-1]
command=python3 /app/app.py 8001
directory=/app
autostart=true
autorestart=true
stderr_logfile=/var/log/supervisor/python1_err.log
stdout_logfile=/var/log/supervisor/python1_out.log

[program:python-server-2]
command=python3 /app/app.py 8002
directory=/app
autostart=true
autorestart=true
stderr_logfile=/var/log/supervisor/python2_err.log
stdout_logfile=/var/log/supervisor/python2_out.log

[program:python-server-3]
command=python3 /app/app.py 8003
directory=/app
autostart=true
autorestart=true
stderr_logfile=/var/log/supervisor/python3_err.log
stdout_logfile=/var/log/supervisor/python3_out.log

Le fichier de Supervisor démarre les 3 serveurs python, nous allons faire le script de serveur Python

Script Python du serveur

// Création du répertoire de l'application

mkdir -p /app
nano /app/app.py

// code du fichier serveur minimal

#!/usr/bin/env python3
import http.server
import socketserver
import sys

# Get port from command line argument
PORT = int(sys.argv[1]) if len(sys.argv) > 1 else 8001

class MyHandler(http.server.SimpleHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header('Content-type', 'text/html')
        self.end_headers()
        response = f"""
        <h1>Hello from Server {PORT}</h1>
        <p>Server ID: {PORT}</p>
        <p>Path: {self.path}</p>
        """
        self.wfile.write(response.encode())

if __name__ == '__main__':
    with socketserver.TCPServer(("", PORT), MyHandler) as httpd:
        print(f"Server running on port {PORT}")
        httpd.serve_forever()

Configuration de Nginx

events {
    worker_connections 1024;
}

http {
    # Define upstream servers (Python backends)
    upstream backend {
        server 127.0.0.1:8001;
        server 127.0.0.1:8002;
        server 127.0.0.1:8003;
        
        # Load balancing method options:
        # least_conn;     # Route to server with fewest active connections
        # ip_hash;        # Route based on client IP (sticky sessions)
        # Default is round-robin
    }
    
    # Health check configuration
    server {
        listen 80;
        
        location / {
            proxy_pass http://backend;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            
            # Connection and timeout settings
            proxy_connect_timeout 5s;
            proxy_send_timeout 60s;
            proxy_read_timeout 60s;
            
            # Health check
            proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
        }
        
        # Health check endpoint
        location /health {
            access_log off;
            return 200 "OK\n";
            add_header Content-Type text/plain;
        }
    }
}

N’oubliez pas d’unlinker le fichier de configuration par défaut

sudo unlink /etc/nginx/sites-enabled/default

Lancement du serveur Nginx

comme on n'a pas systemd on lance en direct depuis Supervisor

sudo supervisord -c /etc/supervisor/conf.d/supervisord.conf

Normalement tous les services sont lancés, et vous pouvez faire un curl pour tester le serveur frontal

curl http://localhost

<h1>Hello from Server 8001</h1>
        <p>Server ID: 8001</p>
        <p>Path: /</p>


curl http://localhost

<h1>Hello from Server 8002</h1>
        <p>Server ID: 8002</p>
        <p>Path: /</p>

curl http://localhost

<h1>Hello from Server 8003</h1>
        <p>Server ID: 8003</p>
        <p>Path: /</p>

curl http://localhost

<h1>Hello from Server 8001</h1>
        <p>Server ID: 8001</p>
        <p>Path: /</p>

Là nous voyons quelque chose de très intéressant, on requête la même url, mais ce n’est pas le même serveur qui nous retourne la réponse. Vous y êtes !

Et maintenant?

Là nous avons un seul container docker, c’est de l’expérience de laboratoire. Le docker est là pour des raisons de convénience, nonobstant la plateforme (mac, linux ou Windows) vous pouvez faire les mêmes commandes.

Vous pouvez faire ce tuto dans WSL, dans Linux. Cependant voyons quels scénarios nous pouvons explorer

-Load balancing vers des serveurs dans d’autres containers docker au sein d’une même plateforme.

-load balancing vers des serveurs par leurs urls

ff

Comment fonctionne le protocol FTP?

En 2025, je vois que de plus en plus de monde ne connait plus le protocole FTP. Les apprenants savent déployer vers Vercel ou Heroku, mais sont incapables de faire un simple FTP. Lorsque le web a pris son envol un peu avant l’an 2000, les webmaster(c’est comme ça qu’on les appelait à l’époque) déplayaient le site en FTP, et aujourd’hui ça fait un peu rigoler les jeunes quand je parle de ça.

Ce n’est pas l’objet de cet article, je vais vous parler de FTP dans sa globalité.

FTP (File Transfert Protocole)

Le FTP a été inventé en 1971, et servait à transférer des fichiers entre deux ordinateurs, plutôt entre un client et le serveur, qui est à la base de l’architecture FTP. En effet quand vous allez sur la page de Filezilla pour télécharger le client FTP, vous avez aussi la possibilité de télécharger les serveurs. Si vous êtes webmaster vous avez besoin de la version client.

Le client FTP se connecte au serveur FTP, il faut souvent un identifiant et un mot de passe, un fois la connexion établie, un échange de données et de commandes se fait entre les deux entités.

Deux ports sont ouverts de part et d’autres pour la communication, le port 20 pour les données et le port 21 pour les commandes. Avant d’avoir un client graphique tel que Filezilla, le FTP se pratiquait en ligne de commande.

Le langage FTP

Voici une liste succincte de commandes FTP que vous devez faire depuis votre client pour manipuler des fichiers. Pour se connecter à FTP en ligne de commande depuis le terminal vous faites ftp nom_hote, ce dernier peut être une adresse IP, après la connexion réussie, vous aurez une invite de commande de type ftp>. Ceci indique que vous êtes déjà sur le serveur.

  • cd change de répertoire sur le serveur
  • lcd change de répertoire sur le client
  • get : télécharge un fichier du serveur vers le client
  • mget : télécharge plusieurs fichiers (wildcards acceptés)
  • put : envoi un fichier vers le serveur
  • mput : envoi multiple fichiers vers le serveur
  • prompt : active ou désactive la confirmation lors de transfert de fichier, utile en multiple
  • delete
  • mkdir : crée un répertoire sur le serveur
  • rmdir : efface un répertoire sur le serveur
  • rename : renomme un fichier
  • help ou ? : affiche la liste des commandes disponibles
  • status : affiche les paramètres actuels

Les commandes brutes FTP

  • CWD : change de répertoire, cd est un wrapper sur CWD
  • STOR : wrapper sur put
  • RETR : wrapper sur get
  • LIST : wrapper sur ls

Les canaux de communication FTP 20 et 21 (channels)

FTP utilise deux canaux de communication :

Control channel : port 21

Ce canal est utilisé pour envoyer les commandes

Data channel : port 20

Ce canal est utilisé pour transmettre les données proprement dites.

Mode actif ou mode passif (pour le serveur)

Dans les logiciels comme Filezilla, la configuration vous propose une connexion passive ou active. Il faut savoir que l’on se place dans le contexte du serveur et non du client..

Le mode actif (Active Mode)

Mode par défaut du FTP, le client envoit par le canal de control sur quel port se connecter, et le serveur répond en se connectant à ce port pour le Data Channel

Le mode passif (Passive mode)

le serveur indique au client quel port auquel se connecter, et le client se connecte à ce port.

Pourquoi il existe deux modes de connexions?

Le parefeu (firewall) est la raison pour laquelle il y a les deux modes.

Problème avec le mode actif :

les serveur essaye de se connecter au port du client, mais le parefeu du client peut être configuré de façon à bloquer le port 21.

Solution avec le mode passif :

Le client se connecte au port du serveur que ce dernier a spécifié. Le pare feu du serveur normalement ne bloque pas le port puisqu’il est censé être configuré pour permettre les connexion.

Dans un cas comme l’autre des problème d’autorisation peuvent se produire, et il convient de tester les solutions pour établir la connexion.

FTP et le modèle OSI à 7 couches

Le fameux modèle à 7 couches, vraiment très abstrait, mais je vais essayer de vous expliquer.

C’est quoi le modèle à 7 couches ?

Le FTP est sur la couche Application, car elle sert directement les application et les utilisateurs. Est ce que le FTP est sur la couche. Par exemple pourquoi ne dit on pas que FTP est sur la couche Transport? La couche Transport s’occupe de découper et réassembler les paquets de données, or FTP ne s’occupe pas du tout de ça. FTP délègue à la couche Transport (TCP Transport Layer Protocol) le soin de le faire.

De même peut on dire que FTP est dans la couche Presentation? La couche Presentation s’occupe de l’encryption, de la compression/decompression, FTP ne s’occupe pas du fait que l’image qu’il transfère soit JPG ou PNG, il transfère juste.

De même est ce que FTP est dans la couche Session? On peut le penser car il y une authentification,et le maintient de la connexion de façon stateful, c’est à dire que le contact est maintenu. Pour autant FTP n’est pas dans la couche Session même si elle gère elle même par dessus TCP l’authentification et le maintient de la connexion.

Installer Proftpd sous Debian dans WSL et accéder via FileZilla depuis l’hôte Windows

Pourquoi ce titre? Non seulement je voulais faire l’installation de Proftpd, mais je voulais aussi tester l’accès à ce serveur FTP logé dans WSL depuis l’hôte Windows. Pourquoi est ce que c’est intéressant? hé bien WSL est un milieu isolé de l’hôte et on ne peut y accéder que grâce à une translation d’adresse IP.

Installation de Proftpd

D’abord on fait un update de précaution et on installe, l aconfiguration devrait être minimale

sudo apt update

sudo apt install proftpd

// le fichier de configuration se trouve dans /etc/proftpd/proftpd.conf
Voyons voir quelques clé de configuration:

ServerType standalone   // proftpd fonctionne tout seul, il est autosuffisant

Ce bout de configuration est commenté
<Anonymous ~ftp>
  User ftp
  Group nogroup
  UserAlias anonymous ftp
  MaxClients 10
  <Directory *>
    <Limit WRITE>
      DenyAll
    </Limit>
  </Directory>
</Anonymous>
Il permet de se connecter sans authentification, ce qui n'est pas recommandé à moins que vous ne sachiez ce que vous faites.

A un autre endroit (commenté également)
DefaultRoot ~  // si le tilde est collé à la lettre t c'est une erreur de syntaxe  et cause le non démarrage de pProftpd
cette directive restreint les utlisateurs dans leur propre répertoire home.

RequireValidShell off  // si actif permet aux utilisateur n'ayant pas de shell (nologin) d'accéder au FTP

Accès au serveur FTP depuis WSL

a présent sans configuration vous pouvez accéder via FTP à votre répertoire home avec la commande suivante:

ftp localhost
il va vous être demandé le user et le mot de passe. Et ensuite en cas de réussite vous aurez un prompt ftp.

Accès depuis l’hôte Windows dans le ftp de WSL

Translation d’adresse IP

Revenons à votre hôte Windows et essayez avec fileZilla de vous connecter au FTP, normalement vous ne pouvez pas, à moins que vous ayez déjà fait le manipulation de translation d’adresse IP, c’est à dire relier l’adresse IP de l’hôte (souvent 192.168.1.XX vers l’adresse IP de WSL. Commençons par connaitre les 2 adresse IP de ‘lhôte et de WSL

Dans l’hôte, on est sous Windows

ipconfig

Configuration IP de Windows


Carte Ethernet Ethernet 2 :

   Suffixe DNS propre à la connexion. . . : lan
   Adresse IPv4. . . . . . . . . . . . . .: 192.168.1.151
   Masque de sous-réseau. . . . . . . . . : 255.255.255.0
   Passerelle par défaut. . . . . . . . . : 192.168.1.254

Carte inconnue Connexion au réseau local :

   Statut du média. . . . . . . . . . . . : Média déconnecté
   Suffixe DNS propre à la connexion. . . :

Carte Ethernet vEthernet (Default Switch) :

   Suffixe DNS propre à la connexion. . . :
   Adresse IPv6 de liaison locale. . . . .: fe80::302e:b41d:9890:f78f%41
   Adresse IPv4. . . . . . . . . . . . . .: 172.25.144.1
   Masque de sous-réseau. . . . . . . . . : 255.255.240.0
   Passerelle par défaut. . . . . . . . . :

Carte Ethernet vEthernet (WSL) :

   Suffixe DNS propre à la connexion. . . :
   Adresse IPv6 de liaison locale. . . . .: fe80::94b8:a9bc:705a:2d44%55
   Adresse IPv4. . . . . . . . . . . . . .: 172.18.96.1
   Masque de sous-réseau. . . . . . . . . : 255.255.240.0
   Passerelle par défaut. . . . . . . . . :

Dans WSL

ip a

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1404 qdisc mq state UP group default qlen 1000
    link/ether 00:15:5d:d9:50:6a brd ff:ff:ff:ff:ff:ff
    inet 172.18.104.160/20 brd 172.18.111.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::215:5dff:fed9:506a/64 scope link
       valid_lft forever preferred_lft forever

Maintenant dans Windows nous devons faire la translation d’IP (dans une autre occasion on a pu le faire mais je remets ici la commande à faire sous Powershell

netsh interface portproxy add v4tov4 listenport=21 listenaddress=127.0.0.1 connectport=21 connectaddress=172.18.104.160

Protocole FTP

Si vous voulez en savoir plus sur les verbes FTP qui permettent de télécharger des fichiers et autres manipulation, visitez le lien ci-dessous :

https://www.cs.colostate.edu/helpdocs/ftp.html

Construire un serveur de chat en shellscript avec socat !

Nous avons vu comment créer un serveur qui répond à des messages avec socat, lancé en ligne de commande, on va aller plus loin en mettant la ligne de lancement de socat dans un script shell, et en loggant les messages échangés

//server.sh

#!/bin/bash

mkdir -p logs
echo "Serveur socat en écoute sur le port 5000..."

socat TCP-LISTEN:5000,reuseaddr,fork EXEC:"$(pwd)/handler.sh"
//handler.sh

#!/bin/bash

timestamp=$(date +"%Y-%m-%d_%H-%M-%S")
client_ip=$SOCAT_PEERADDR
logfile="logs/client_${client_ip}_${timestamp}.log"

echo "Client $client_ip connecté à $timestamp" >> "$logfile"
echo "Bienvenue $client_ip ! Tape 'exit' pour quitter." 

while read line; do
    echo "[$(date +%H:%M:%S)] $client_ip: $line" >> "$logfile"
    [ "$line" = "exit" ] && echo "Au revoir $client_ip !" && break
    echo "Tu as dit : $line"
done

echo "Déconnexion de $client_ip" >> "$logfile"

Le fichier server.sh est presque inchangé, par contre le fichier de traitement handler.sh est plus complexe. Il consigne d’abord l’adresse IP du client qui servira a nommer le fichier de log, et utilise le timestamp dans le nom du fichier. Dans la boucle while, les messages entrés par le client sont redirigé vers le fichier de log en mode append (sans écrasement du contenu)

Allons plus loin avec un broadcast !

Le broadcast consiste à diffuser à tout le monde, on se rapproche du chat

Avec ce qui suit on aura :

  • Plusieurs clients peuvent se connecter.
  • Chacun reçoit tous les messages envoyés par les autres.
  • On utilise une file nommée (FIFO) pour centraliser les messages.
  • socat crée un processus par client.

Cette fois-ci on va se doter d’un named pipe

Strucutre des fichiers
home/refschool/
├── server.sh         # Démarre le serveur socat
├── handler.sh        # Gère chaque client
├── broadcast.fifo    # File partagée pour les messages
└── logs/             # Logs par client

//   server.sh
#!/bin/bash

mkdir -p logs

FIFO="broadcast.fifo"
[ -p "$FIFO" ] || mkfifo "$FIFO"

echo "Serveur de chat en écoute sur le port 5000..."
socat TCP-LISTEN:5000,reuseaddr,fork EXEC:"$(pwd)/handler.sh"

Serveur :

#!/bin/bash

timestamp=$(date +"%Y-%m-%d_%H-%M-%S")
client_ip=$SOCAT_PEERADDR
logfile="logs/client_${client_ip}_${timestamp}.log"
fifo="broadcast.fifo"

echo "Client $client_ip connecté à $timestamp" >> "$logfile"

# Démarrer un lecteur en arrière-plan qui lit la FIFO et envoie au client
tail -f "$fifo" &

# Lire les messages du client et les écrire dans la FIFO
while read line; do
    [ "$line" = "exit" ] && echo "💬 $client_ip s'est déconnecté." >> "$fifo" && break
    echo "[$(date +%H:%M:%S)] $client_ip: $line" >> "$logfile"
    echo "💬 $client_ip: $line" >> "$fifo"
done

# Nettoyer le processus tail
kill %1 2>/dev/null
echo "Déconnexion de $client_ip" >> "$logfile"

Voilà avec ce script, tous les clients auront ce que les autres ont tapé dans l’invite. On peut utiliser ce système pour faire un jeu en réseau même simple (tic tac toe)

Combiner netcat et les named pipe pour un système d’écoute à travers le réseau

Soit le script suivant (inspiré de cet article sur Stackoverflow)

Utiliser un named pipe combiné à un serveur netcat pour écouter des messages sur localhost

Si vous n’êtes pas familier des named pip, lisez cet article sur les named pipe

#!/bin/sh
request=pipe
rm "$request"
mkfifo "$request"

HandleCommand () {
  echo "received command: $1"
  [ "$1" = "exit" ] && return 1
  return 0
}

while :; do
  while read line; do
    HandleCommand "$line" || break
  done <"$request" | nc -l -p 5000 >"$request"
done

Pour la première démonstration de ce script on se mettra en wsl dans le répertoire /home/refschool pour faire fonctionner le script, car il faut veiller à ce qu’on soit dans un système de fichier Linux pour pouvoir créer un named pipe.

De plus on utilisera le tutoriel Tmux pour avoir un multifenêtrage dans une seule console.

Le script ci-dessus va effacer un named pipe appelé « pipe », et aussitôt en recréer un, puis entre dans une boucle infinie pour écouter sur le port 5000 du serveur netcat (nc)

On va ouvrir tmux et créer deux panneaux verticaux avec le raccourcis CTRL + B puis « % », et pour basculer d’un panneau à l’autre, utiliser le raccourcis CTRL +B puis « o », le premier panneau servira à exécuter le script shell, et le second servira à entrer des messages au serveur netcat.

Donc dans le premier panneau on va lancer le script shell, et on bascule vers le second panneau avec le raccourci CTRL + B puis « o », une fois dans le second panneau, on va se connecter au serveur netcat sur le port 5000

nc localhost 5000
// ensuite dans le même panneau entrez des textes
hello
bonjour
puis entrez exit qui sera interprété par le script shell comme une interruption du programme.

Dans ce qui a précédé, le serveur netcat écoutait sur la boucle locale localhost, ou 127.0.0.1 ou loopback. Mais un autre ordinateur sur le même réseau LAN ou WIFI ne peut pas s’y connecter. Pour ce faire il faudrait démarrer netcat pour écouter sur 0.0.0.0 (tous les interfaces du LAN), mais pas d’Internet bien sûr et ce pour plusieurs raisons :

  • votre ordinateur est derrière un routeur (votre box si vous êtes chez vous), il faut utiliser le port forwarding
  • il se peut aussi que le firewall de Windows bloque le port 5000 (hypothétique)

Vous pouvez utiliser un tunnel pour créer une connexion avec le monde extérieur.

Ecouter les messages d’ordinateur du même réseau domestique

Votre serveur netcat va démarrer sur votre poste, donc il est utile de connaitre son adresse IP dans le LAN avec cette commande

ip addr show

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1404 qdisc mq state UP group default qlen 1000
    link/ether 00:15:5d:d9:5f:23 brd ff:ff:ff:ff:ff:ff
    inet 172.18.104.160/20 brd 172.18.111.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::215:5dff:fed9:5f23/64 scope link
       valid_lft forever preferred_lft forever

Remarquez que l’adresse IP affichée ici (en rapport avec eth0) es 172.18.104.160, vous vous attendez à une adresse du type 192.168.1.xx, c’est parce que on est à l’intérieur de WSL, et que cette adresse est interne à WSL.

Pour connaitre l’adresse IP de l’hôte avec ipconfig:

C:\Users\admin>ipconfig

Configuration IP de Windows


Carte Ethernet Ethernet 2 :

   Suffixe DNS propre à la connexion. . . : lan
   Adresse IPv4. . . . . . . . . . . . . .: 192.168.1.151
   Masque de sous-réseau. . . . . . . . . : 255.255.255.0
   Passerelle par défaut. . . . . . . . . : 192.168.1.254

Carte inconnue Connexion au réseau local :

   Statut du média. . . . . . . . . . . . : Média déconnecté
   Suffixe DNS propre à la connexion. . . :

Carte Ethernet vEthernet (Default Switch) :

   Suffixe DNS propre à la connexion. . . :
   Adresse IPv6 de liaison locale. . . . .: fe80::302e:b41d:9890:f78f%41
   Adresse IPv4. . . . . . . . . . . . . .: 172.25.144.1
   Masque de sous-réseau. . . . . . . . . : 255.255.240.0
   Passerelle par défaut. . . . . . . . . :

Carte Ethernet vEthernet (WSL) :

   Suffixe DNS propre à la connexion. . . :
   Adresse IPv6 de liaison locale. . . . .: fe80::94b8:a9bc:705a:2d44%55
   Adresse IPv4. . . . . . . . . . . . . .: 172.18.96.1
   Masque de sous-réseau. . . . . . . . . : 255.255.240.0
   Passerelle par défaut. . . . . . . . . :

Maintenant nous allons corriger le script shell pour que netcat écoute sur toutes les interfaces, j’appelle ce fichier

#!/bin/sh
request=pipe
rm "$request"
mkfifo "$request"

HandleCommand () {
  echo "received command: $1"
  [ "$1" = "exit" ] && return 1
  return 0
}

while :; do
  while read line; do
    HandleCommand "$line" || break
  done <"$request" | nc -l -p 5000 -s 0.0.0.0 >"$request"
done

A la ligne 15, nc (netcat) écoute sur toutes les interfaces, donc les ordinateurs du réseau local vont pouvoir communiquer avec mon serveur nc

Je vais utiliser mon Macbook pour faire la commande nc pour me connecter au serveur netcat.

nc 172.18.104.160 5000

mais rien ne se passe !

Souvenez vous que 172.18.104.160 est une adresse IP de WSL, ce n’est pas l’hôte (Windows) qui a l’adresse 192.168.1.151. Donc il faut que le Macbook se connect à cette dernière adresse. Mais ce n’est pas tout, le Macbook se connectant à 192.168.1.151, il faut que le message parviennet au 172.18.104.160. On obtient cette redirect par ce qu’on appelle la redirection de port, port forwarding de Windows à WSL. Pour ce faire il faut s’aider de Powershell en mode administrateur

Redirection de port avec Powershell

Ajout d’une règle de port forwarding

Powershell est asse imbittable comme syntaxe !

netsh interface portproxy add v4tov4 listenport=5000 listenaddress=0.0.0.0 connectport=5000 connectaddress=172.18.104.160

Ensuite nous allons agir sur le firewall pour autoriser les connexions sur le port 5000.

Autoriser le port 5000 en écoute sur Windows

New-NetFirewallRule -DisplayName "Allow Port 5000" -Direction Inbound -Protocol TCP -LocalPort 5000 -Action Allow

Je vous conseille de redémarrer le script shell sous WSL et de tester d’abord en local puis depuis le Mac. Si vous ne faites pas le redémarrage, ça ne marche pas.

Pour confirmer le port forwarding sous Windows

netsh interface portproxy show all

Listen on IPv4:             Connect to IPv4:
Address         Port       Address         Port
--------------- ---------- --------------- ----------
0.0.0.0         5000       172.18.104.160  5000

En mpeme temps depuis votre WSL confirmez que le script shell écoute aussi sur le port 5000

ss -tlnp | grep 5000

LISTEN 0      128          0.0.0.0:5000       0.0.0.0:*     users:(("nc",pid,fd))

Normalement ça marche depuis le Macbook maintenant ! Mais si nous essayons en même temps de le faire depuis un autre panneau de WSL ça ne marche pas. Par contre coupez toutes les connexions, puis commencez sur WSL ça marche ! mais ensuite vous basculez sur Macbook ça ne marche pas !

Limites de nc et socat à la rescousse

Hé oui nc n’écoute qu’une seule communication à la fois ! nc -l est en mono connexion, il accepte une connexion puis se ferme. Il faudrait une boucle infinie qui lance en continue nc du type

while true; do
  nc -l -p 5000 -s 0.0.0.0
done

Mais il n’y a pas de parallélisme véritable, c’es séquentiel, donc un peu de lag au final.

Pour avoir du vrai parallélisme, il faut utiliser socat pour faire ce boulot. Donc on va l’installer

sudo apt install socat
// fonctionnement de socat
socat lance un fichier que vous désignez qui va prendre en charge les requêtes, un peu comme >> node server.js
La manipulation consiste à écrire un script shell qui va lire en entrée et faire quelque chose avec ce qui est lu,voici le script handler.sh

#!/bin/bash
echo "Bienvenue sur le serveur !"
while read line; do
    echo "Tu as dit : $line"
done


Ensuite nous allons lancer le serveur socat :

socat TCP-LISTEN:5000,reuseaddr,fork EXEC:./handler.sh

En une ligne nous lançons le serveur socat, qui grâce aux paramétrage précédent de Windows (Firewall et translation d’adresse IP) va écouter sur tout le réseau local, depuis le Macbook, je lance

nc 192.168.1.151 5000

bienvenue sur le serveur !

Et on peut envoyer des messages au serveru socat depuis plusieurs clients !

On peut pousser plus loin la chose en mettant la ligne de lancement de socat dans un fichier shell, et consigner les messages dans un fichier de log personnalisé à chaque client.

Cet article traite de ce sujet !

Linux Parallel pour exécuter des process en parallèle et gagner du temps

Pourquoi utiliser parallel?

Parallel nous permet de faire tourner un programme simultanément sur plusieurs coeurs. Comme aujourd’hui tous les ordinateur on t des chips multicoeur, il ne faudrait pas s’en priver si nous avons des tâches intensives en calcul à faire.

Pour installer parallel :

sudo apt install parallel

Parallel exploite le multicoeur de votre système, pour connaitre le nombre de coeurs physique de votre machine :

$ lscpu

Autre méthode comme tout est fichier dans linux, dans le répertoire proc

vim /proc/cpuinfo

La commande nproc affiche des informations plusconcises

$ nproc

4

Rappel : les process, jobs, avant plan (foreground) et arrière plan (background)

Le signe & pour mettre en arrière plan

ping google.com > ping.txt &
[1] 2606

# exemple avec un script shell
./script.sh  &

La commande jobs

Elle permet de lister les process en arrière plan

jobs
[2]+  Running                 ping google.fr > ping.txt &
 
# pour tuer un process :
kill -9 2606 << le numéro de process

Attendre que des process en background se terminent avant de lancer un autre process

command 1 &
command 2 &
wait
command3

ex  dans un script shell : 
#!/bin/bash
sleep 5 &
sleep 10 &
wait
echo "Bonjour"

Comparaison de la conversion de fichier image avec la commande convert (d’ImageMagick)

Nous allons convertir des images jpg en image png avec la commande convert, d’abord sans parallel puis avec parallel.

Pour télécharger les images, les urls sont dans le fichier à télécharger, ce sont des images du site unsplash.com.

Avec une commande en une ligne on va télécharger toutes ces images, je vous conseille de créer un répertoire image

cat images.txt | xargs wget
grâce au piping et avec xargs, et wget.
Mais les images téléchargée doivent être renommées pour que ce soit plus pratique, voici le script à lancer (il n'est pas parfait mais fait le job)

#!/bin/bash
IMAGES=$(ls)
I=0
for IMAGE in $IMAGES
do
        MIME=$(file -b --mime-type $IMAGE)
        EXT=$(echo "$MIME" | cut -d'/' -f2)
        if
        mv $IMAGE "image"_${I}.$EXT
        I=$((I+1))
done

Ce script va nommer les images avec l’extension trouvée à partir du MIME-type, et numéroter les images. A présent on est prêt pour la conversion. On va utiliser la commande time pour avoir la durée d’exécution

#script bash avec parallel

#!/bin/bash
parallel convert {} {.}.png ::: *.jpeg


# avec parallel
real    1m44,358s
user    6m13,489s
sys     0m21,999s

#script sans parallel

#!/bin/bash
IMAGES=$(ls *.jpeg)
for IMAGE in $IMAGES
do
        FILENAME="${IMAGE%.*}"
        convert $IMAGE ${FILENAME}.png


done

real    2m26,348s
user    2m39,110s
sys     0m2,865s

Linux Nohup pour détacheer un process shell

Lorsque vous quittez un shell, tous les process lancées sont arrêtés. Ce qui est ok si vous arrêtez de travaillez, mais imaginez que vous avez un process qui prend beaucoup de temps, par exemple la conversion d’une vidéo, vous avez intérêt à garder le shell ouvert.

Cependant il existe une commande Linux qui permet de lancer un process dans un shell et de le fermer sans interrompre son exécution : c’est nohup. Il n’est pas forcément installé par défaut dans ce cas voici ce qu’il faut faire pour l’installer sous Ubuntu/Debian :

sudo apt update
sudo apt install coreutils

Comment utiliser nohup

# par exemple un script de conversion en python
python convertisseur.py

#pour lancer avec la possibilité de fermer le shell sans arrêter le programme
nohup python convertisseur.py

# pour un script shell
nohup ./monscript.sh

# pour une commande
nohup curl -O https://monsite.com

Pour ça s’appelle nohup?

En Linux, il existe un appel système SIGHUP qui va arrêter un process. Nohup va simplement empêcher cet appel d’affecter un process lancé avec lui, d’où le nom No HUP.

Mise en application de nohup

Nous allons lancer un process qui va prendre du temps, mais tout simple, et que nous allons passer avec nohup dans un second temps

ping google.fr

PING google.com (142.250.201.46) 56(84) bytes of data.
64 bytes from mrs08s20-in-f14.1e100.net (142.250.201.46): icmp_seq=1 ttl=115 time=24.5 ms
64 bytes from mrs08s20-in-f14.1e100.net (142.250.201.46): icmp_seq=2 ttl=115 time=13.8 ms
64 bytes from mrs08s20-in-f14.1e100.net (142.250.201.46): icmp_seq=3 ttl=115 time=8.44 ms
64 bytes from mrs08s20-in-f14.1e100.net (142.250.201.46): icmp_seq=4 ttl=115 time=12.3 ms
64 bytes from mrs08s20-in-f14.1e100.net (142.250.201.46): icmp_seq=5 ttl=115 time=8.01 ms
64 bytes from mrs08s20-in-f14.1e100.net (142.250.201.46): icmp_seq=6 ttl=115 time=11.8 ms
64 bytes from mrs08s20-in-f14.1e100.net (142.250.201.46): icmp_seq=7 ttl=115 time=8.41 ms
64 bytes from mrs08s20-in-f14.1e100.net (142.250.201.46): icmp_seq=8 ttl=115 time=9.02 ms

Le ping ne va pas s’arrêter, il prend la main sur le shell. Lançon maintenant avec nohup

nohup ping google.com

nohup: ignoring input and appending output to 'nohup.out'

A ce stade nohup ne vous rend pas la main, mais ouvrez une seconde fenêtre pour afficher le contenu du fichier nohup.out comme indiqué dans le message, vous verrez le même contenu que précédemment. Si vous faites CTRL + C pour arrêter, le process s’arrête. Jusqu’ici nohup n’a pas montré sa valeur ajoutée.

Vous pouvez aussi rediriger vers un fichier spécifique au lieu du fichier par défaut nohup.out.

nohup ping google.com > journal.txt

Un mot à propos de stdout et stderr et stdin

stdout est ce qu’on appelle la sortie standard, en réalité la sortie standard c’est ce que vous voyez à l’écran. Mais il y a stderr, qui est la sortie d’erreur, donc où s’affiche les erreurs? à l’écrant également ! mais on fait le distingo entre la sortie standard et la sortie d’erreur.

On dira que stderr est un flux de sortie, ce qui est très générique comme appellation. ET ne pas oublier qu’il y a stdin ! qui est le flux d’entrée. Il faut savoir que chaque flux possède un numéro de descripteur, stdin a 0, stdout a 1 et stderr a 2. Connaitres ces numéro va nous permettre de mieux comprendre la commande suivante. Donc stdout et stderr affichent tous les deux à l’écran !

Mais on peut faire autrement, ainsi on peut rediriger les erreurs vers un fichier error.log par exemple.

ls /etc /non_existent_dir

ls: cannot access '/non_existent_dir': No such file or directory   << erreur
/etc:   << sortie standard pas d'erreur
adduser.conf                   deluser.conf  ldap            mtab                 rc2.d         sudoers.d
alternatives                   depmod.d      ld.so.cache     nanorc               rc3.d         sudo_logsrvd.conf
apache2                        dhcp          ld.so.conf      netconfig            rc4.d         sysctl.conf
apparmor                       dpkg          ld.so.conf.d    netplan              rc5.d         sysctl.d
apparmor.d                     e2scrub.conf  legal           networkd-dispatcher  rc6.d         systemd

Ici on essait de faire ls sur un répertoire inexistant, donc ça va provoquer une erreur

ls /etc /non_existent_dir  2> errors.txt

dans l’exemple ci-dessus, on va ridiriger les erreurs vers un fichier errors.txt, et ce qui ne déclenche pas d’erreur sort à l’écran.

ls /etc /non_existent_dir > output.txt 2> errors.txt

L’exemple ci-dessus va rediriger les données vers output.txt, et s’il y a des erreurs, va rediriger vers errors.txt

Une syntaxe plus cryptique:

ls /etc /non_existent_dir > fusion.txt 2>&1

L’exemple ci-dessus va rediriger le flux d’erreur (numéro 2) vers le flux 1, donc les erreurs iront au fichier fusion.txt

Encore un mot sur comment lire stdin

tee input.txt   // ce qui est tapé est affiché à l'écran et enregistré dans input.txt
faire CTRL+D pour arrêter

on peut utiliser aussi cat

$ cat > input.txt  // ce qui est tapé n'est pas affiché à l'écran, donc pas de doublon à l'écran CTRL+D pour arrêter

Utiliser la commande script pour tout enregistrer dans un fichier

script input.txt  // taper exit ou CTRL+D pour sortir

Démarrer un process en background avec nohup (arrière plan)

$ nohup ping google.com &
[1] 8519   // numéro aléatoire
nohup: ignoring input and appending output to 'nohup.out'

Pour afficher le processus faire :
$ pgrep -a ping

8519 ping google.com

pour tuer le process :
kill -9 8519

Cette fois-ci nohup vous rend la main. ON va refaire avec un fichier de sortie

nohup ping google.com > output.txt  &

Savoir manipuler les MIME-Type en informatique

Le MIME-Type est une données qui décrit la nature d’un fichier. Par exemple, un fichier texte aura un MIME Type différent d’un fichier Excel. Une image Jpeg aura un MIME-Type différent d’une image PNG.

Rôles du MIME-Type

Le MIME-Type a plusieurs rôles importants, tout d’abord il permet de connaitre la nature d’un fichier en bypassant l’extension du fichier qui peut être trompeur, ou d’un fichier qui a perdu son extension suite à un renommage.

Ensuite dans les communications entre programmes, il permet au receveurs d’une fichier de connaitre la nature de ce qui est reçu : entre un serveur web et un navigateur web. Dans les requêtes AJAX, c’est application/json qui est envoyé de part et d’autres.

Comment connaitre le MUIME-Type d’un fichier?

Nous allons nous intéresser au shell, avec la commande file (version >= 5)

La commande file nous permet de connaitre le MIME-Type d'un fichier

$ file --mime-type image.png
image.png: image/png

$ file -b --mime-type image.png
image/png

$ file -i image.png
image.png image./png; charset=binary

Connaitre le MIME-type dans deivers langages

#PHP
echo mime_content_type('image.png');

#NodeJS

const mime = require('mime');
const file_path = 'files\file.txt'
const mime_type = mime.getType(file_path)

#Javascript côté client
<input type="file" id="your-files" multiple>

<script>
let control = document.getElementById("your-files");
control.addEventListener("change", function(event) {
    // When the control has changed, there are new files
    let files = control.files,
    for (var i = 0; i < files.length; i++) {
        console.log("Filename: " + files[i].name);
        console.log("Type: " + files[i].type);
        console.log("Size: " + files[i].size + " bytes");
    }
}, false);
</script>



Installer le shell zsh sur Ubuntu

Le shell est le moyen le plus puissant d’interaction avec le système d’exploitation. Il existe types de shell : le primitif sh (bourne shell l’original), puis csh (C shell), puis bash (Bourne again shell), ksh (Korn shell), tsh T shell, tcsh, et zsh (j’en ai peut être oublié)

Nous allons installer le petit dernier sur Linux, zsh est intéressant car il a plus de fonctionnalité, dont la capacité de prévisualiser l’autocomplétion, mais aussi facilement personnalisable avec les thèmes.

installation de zsh

D’abord mettons à jour les dépôts

sudo apt update

sudo apt install zsh -y # répond yes à toutes les questions pour aller plus vite

Ensuite vérifiez l'installation

zsh --version

Configuration de zsh

Mais avant d’aller configurer zsh, il faut le démarrer. EN passant voyons comment connaitre le shell courant

Quel est mon shell courant sous Linux?

il y a plusieurs façon de le faire
Méthode 1 : affiche le shell courant 
echo $0


Méthode 2 
echo $SHELL

cette dernière méthode n'affiche pas le vrai shell courant, car si vous changez de shell, l'affichage ne changera pas, car c'est une variable d'environnement.

Pour changer de shell, tapez zsh dans le terminal, et vérifiez que c’est bien le shell courant. Pour savoir où se trouve le chemin vers le programme shell

which zsh

La première fois que vous démarrez le zsh, vous devez le configurer à la différence des autres shell

Appuyez sur q pour quitter la configuration et recommencer la prochaine fois que vous entrerez dans Zsh.
Appuyez sur 0 pour créer un fichier de configuration .zshrc vide et tout configurer à partir de zéro.
Appuyez sur 1 pour accéder au menu principal et configurer chaque paramètre individuellement.
Appuyez sur 2 pour remplir le fichier de configuration .zshrc avec les paramètres par défaut, que vous pourrez ensuite modifier manuellement dans le fichier .zshrc.

Si plus tard vous voulez reconfigurer le zsh tapez la commande

zsh-newuser-install

La commande chsh

Cette commande permet de setter le shell par défaut pour un utilisateur

chsh zsh /chemin/vers/shell/. <username>

souvenez vous que which zsh donne le chemin vers le shell

chsh zsh `which zsh` <username>

En cas d’erreur PAM: Authentication failure

Il s’agit d’une configuration inadéquate de votre fichier /etc/pam.d/chsh, ouvrez le et /

Remplacéez
auth       required   pam_shells.so

par

auth       sufficient   pam_shells.so

Installer Oh My Zsh pour avoir plus de fonctionnalité

sh -c "$(wget https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh -O -)"


sur MacOS on utilise Curl car wget n'est pas installé par défaut
sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"

Copie d’écran MacOS.

OhMy Zsh est une collection de 150 thèmes voici le github. Pour changer de thème il faut éditer le fichier .zshrc

et localiser la ligne ZSH_THEME

rempalcer la ligne
ZSH_THEME="robbyrussel" par
ZSH_THEME="jonathan" par exemple

Installer le plugin autosuggestion

Une des choses les plus sympathique de zsh est l’autosuggestion, avant que vous ayez fini de taper une commande, une liste de choix se propose à vous. installons le plugin

git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions

ouvrez .zshrc et localisez la ligne
plugins=(git) et changez la en
plugins=(git zsh-autosuggestions)
redémarrez le terminal

Quand vous tapez un début de commande, utilisez la flèche de droite (et non la touche Tab) pour choisir al suggestion.

Installer le surlignement de syntaxe (syntax highlighting)

Ceci vous permet une mielleure lisibilité et esthétisme

git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting

redémarrez votre shell et commencez à taper la commande echo $0. (qui affiche le nom du shell courant) et observez le changement de couleur.

Introduction à tmux terminal multiplexer

Qu’est ce que Tmux? (Terminal multiplexer)

tmux est un programme qui permet de splitter son écran shell en plusieurs partie appelé en anglais « pane ». De plus il permet d’avoir plusieurs « window » un peu comme les bureau sous Windows ou MacOS. Mais nous allon spour simplier ne considérer qu’une seule window.

TL;DR;

  • Démarrer une session nommée tmux : tmux new -s nom_session
  • Redimensionner un panneau : CTRB + B puis CTRL + flèche
  • Changer de panneau : CTRL + B puis flèche
  • Sortir d’une session tmux : CTRL +B puis D (ou d)
  • Démarrer tmux avec la dernière session : tmux a
  • Reprendre la session : tmux ls puis tmux attach -d -t <session_id>

Installation de tmux

apt install tmux    -  sur Debian Ubuntu
brew install tmux    - macOs

Lancement tmux et commandes de base

pour lancer tmux rien de plus simple :
$ tmux

l'affichage va un peu changer, car vous avez initié une session tmux, maintenant nous allons diviser l'écran en deux "pane" verticaux. Pour ce faire faites d'abord la combinaison CTRL + B puis % (pourcentage), vous obtenez deux panes verticaux.

Commandes de base

Voyons comment on peut changer de pane. Faites la commande CTRL+B puis flèche gauche ou droite.

Pour fermer un pane, CTRL+B puis « x ». Pour fermer un window CTRL+B puis « & », une confirmation est demandée à chaque fois.

Pour afficher l’aide de tmux : tmux info

Pour afficher les jnuméro des pane : CTRL + B puis q, identifier le numéro permet de basculer vers un pane sans passer par tous les panes, pendant que les numéros restent affichés, appuyer sur un nombre pour y basculer directement.

Pour splitter un pane horizontalement : CTRL + B puis  » (guillemets)

Manipulation importante : autocomplétion

Par défaut l’autocomplétion n’est pas active, il faut toucher au fichier de configuration .tmux.conf, qui n’existe pas par défaut, il faudra le créer. Cependant, vous pouvez afficher la configuration de tmux avec la commande suivante:

tmux show -g

On va pouvoir piper le contenu vers un fichier .tmux.conf qu'on va mettre dans le répertoire home de l'utilisateur
tmux show -g | cat > ~/.tmux.conf
il ne vous reste plus qu'à éditer ce fichier en ajoutant la ligne suivante:
unbind -n Tab
sauvez le fichier. Pour vous assurer que c'est actif redémarrez tmux.

Raccourcis clavier de tmux:

Ctrl-b + d – se détacher de la session en cours.
Ctrl-b + % – divise une fenêtre en deux volets, l’un supérieur et l’autre inférieur.
Ctrl-b + ” – divise une fenêtre en deux volets verticalement.
Ctrl-b + flèche – permet de changer de volet dans une direction donnée.
Ctrl-b + x – fermer le volet en cours.
Ctrl-b + c – créer une nouvelle fenêtre.
Ctrl-b + n – passer à la fenêtre suivante en fonction du numéro.
Ctrl-b + p – retour à la fenêtre précédente.
Ctrl-b + numéro d’identification – permet d’accéder à une fenêtre spécifique à l’aide du numéro d’identification.
Ctrl-b + : – ouvre le mode ligne de commande.
Ctrl-b + ? – imprimer tous les raccourcis.
Ctrl-b + w – liste toutes les fenêtres de la session en cours.

Commandes tmux:
tmux info - liste les commandes

Navigation entre les panneau

Sans modification du fichier de configuration
CTRL + B puis o
CTRL + B + o va déplacer un pane



Dans le fichier .tmux.conf ajoutez les lignes:

#cycle dans les pane
bind -n S-right select-pane -t :.+
bind -n S-left select-pane -t :.-


rechargez la configuration : CTRL +B, puis :source-file ~/.tmux.conf
vous pouvez SHIFT + flèche gauche droite pour cycler dans les pane.

Scroller dans Tmux

CTRL + B et ] sur un clavier français, ça semble impossible mais si , il faut faire ALTGR + touche après le zéro pour obtenir le crochet fermant. Ensuite vous scollez avec les touches fléchées, ou la molette de la souris. Pour quitter le mode scroll, appuyez sur « q ». Mise à part ça il est impossible de scroller et c’est un peu frustrant.

Tmux et les sessions

Lorsque vous faites tmux tout seul vous démarrez une session anonyme. Mais il peut être intéressant de démarrer une session nommée, si vous en démarrez plusieurs

Tmux créer une session nommée

tmux new -s masession

et dans la session même si vous faites tmux ls ou tmux list-session

Ne tentez pas de démarrer une session tmux dans une session tmux, vous aurez le message de découragement suivant : sessions should be nested with care, unset $TMUX to force

Une meilleure pratique est de se détacher d’une session tmux pour revenir à la session principale et d’en démarrer une nouvelle

Se détacher d’une session tmux

CTRL + B puis D

0: 1 windows (created Sat Mar 22 11:00:35 2025) (attached)
session1: 1 windows (created Sat Mar 22 11:01:31 2025)  << session détachée

Pour se rattacher à une session

tmux a    // se rattacher à la dernière session quittée
tmux a -t masession // se rattacher à une session nommée

Si vous quittez votre shell et que vous vous rattachez à l aprochaine session shell c’est possible.

Sortir d’une session Tmux d’un seul coup

tmux kill-server

Si vous avez plusieurs fenêtre ou panneau, pour sortir sans avoir à fermer tous les panneau

Les fenêtres dans tmux

Pour vous dire que tmux a beaucoup de capacité, jusqu’ici vous avez fait connaissance avec des panneaux ou pane en anglais, mais ces panneau sont en réalité dans une fenêtre !

# se détacher de la fenêtre et démarrage d'une nouvelle session avec une session nommée et une fenêtre nommée
$ tmux new -s session2 -n maFenetre
Ensuite faire la commande tmux ls

Pour afficher les fenêtre :  CTRL + D puis W
Pour changer de fenêtre : CTRL +D puis N

Résultat de la commande CTRL + D puis W

Dans cette vue vous pouvez changer de fenêtre avec le raccourcis CTRL + D puis N

Sinon vous voyez qu’il y a un numéro à côté d’une fenêtre, on peut naviguer par numéro : CTR L + B puis numéro de fenêtre.

Pour fermer la fenêtre courante : CTRL + D puis &

source :

Résumé :

  • on a installé les briques nécessaire pour faire fonctionner un site web php
  • pour un site web on édite : /etc/hosts, on crée le fichier virtualhost, avec tmux en multifenêtrage, on lance php-fpm, on lance Nginx, on vérifie que le site marche avec curl.

Comment partager votre site web en local sans utiliser Ngrok, ni localtunnel

Ngrok est (était) un service pratique pour partager votre site web en local à votre client, mais aujourd’hui il nécessite un compte. Il y a des alternatives comme localtunnel, ou serveo. Mais je vais vous ontrer qu’il est possible de faire sans. Pour ce faire il faut que vous disposiez d’un VPS.

Pour l’exemple je me base sur un Droplet DigitalOcean avec authentification par mot de passe.

Vérifiez juste que le firewall (iptable ou ufw) ne bloque par l’accès au port 22 et que le /etc/ssh/sshd_config contienne les lignes suivantes sur le VPS:

GatewayPorts yes
PermitRootLogin yes

Ensuite et c’est là où il faut comprendre qu’il faut faire la commande en local et non sur le VPS !! :

ssh -R 80:localhost:3000 root@159.223.3.3

La commande ci-dessus forwarde le port 80 du serveur VPS (identifié par son adresse IP) vers le localhost:3000.

Il va vous être demandé une authentification (mot de passe), une fois ceci fait, allez dans le navigateur et entrez l’adresse :

http://159.223.3.3

et vous verrez le contenu de votre localhost:3000 !

Utiliser netcat pour écouter des messages locaux et distants

netcat est un utilitaire réseau servant à écouter les ports. Par exemple l’exemple suivant va écouter sur le port 12345

# ouvrez un premier shell et faites la commande suivante:
nc -l -p 12345

# depuis le même hôte ouvrez un second shell et faites la commande suivante :
echo "Hello" | nc 127.0.0.1 12345

dans le premier shell vous allez voir le message "Hello" sortir

L’exercice serait plus intéressant si on envoyait un message depuis un ordinateur extérieur ayant une autre adresse IP:

# dans le premier shell de l'hôte avec l'adresse IP  145.231.65.88 (adresse donnée au hasard)
nc -l -p 12345

# dans le second ordinateur
echo "Hello" | nc 145.231.65.88 12345

# il ne se passe rien, parce que par défaut netcat n'écoute que sur l'interface 127.0.0.1, pour lui demander d'écouter sur toutes les interfaces :
nc -l -p 12345 -s 0.0.0.0 -k -v

cette fois ci ça marche.

Listening on 0.0.0.0 12345
Connection received on 5.48.206.214 63696
Hello

Rediriger ver un named pipe.

Ce que netcat va recevoir on le redirige vers un named pipe.Il faut d’abord créer un pipi appelé mypipe

# dans un premier shell
mkfifo mypipe

nc -l -p 12345 -s 0.0.0.0 -k -v > mypipe

# dans un second shell 
cat < mypipe

# depuis un ordinateur distant
echo '9' | nc 178.62.221.128 12345

# vous constaterez qu'il y a un petit délai d'une seconde pour voir afficher 
# mais le plus gênant c'est du côté de l'ordinateur distant, on ne nous rend pas la main, ceci est dû au fait que netcat  garde la connexion ouvert après l'envoi. Nous allons lui demander de fermer la connexion après envoi avec le paramètre -q à 1
$ echo '7' | nc -q 1 178.62.221.128 12345

la main nous est rendu après envoi.

Rediriger vers un fichier texte

au lieu de rediriger vers le named pipe on redirige vers un fichier 
$ nc -l -p 12345 -s 0.0.0.0 -k -v >> log.txt

Découverte des named pipe dans Linux.

Oubliez le web, revenez 30 ans en arrière, comment faisaient les process (programmes) pour communiquer?

Les named pipe sont une technologie qui le permettent, mais il y a aussi les sockets. Mais dans cet article on va parler uniquement des named pipes.

Mais d’abord c’est quoi les pipes?

Dans Linux un pipe est représenté par le caractère | (une barre verticale)

commande 1 | commande 2

Dans l’exemple ci-dessus, la sortie de la commande 1 est passée en entrée de la commande 2.

Second exemple:
ps aux
la commande ci-dessus nous permet de lister tous les process en cours.
.......
apple            79180   0,0  0,2 67548168  32508   ??  S     9:40     0:00.29 /Applications/Go
apple            75919   0,0  0,0 34151264   1908 s005  S     9:25     0:00.08 -bash
root             75918   0,0  0,0 34151500   4856 s005  Ss    9:25     0:00.03 login -pf apple
apple            75772   0,0  0,0 33619312   2640 s004  Ss+   9:25     0:00.03 /usr/local/bin/b
.......

Il y en a des centaines. On va filtrer la ou les lignes qui contiennent le mot ‘bash’, (vous pouvez choisir le mot que vous voulez). Pour ce faire on va utiliser grep qui permet de chercher dans un fichier un mot ou une expression.

ps aux | grep bash


apple            75919   0,0  0,0 34151264   1908 s005  S     9:25     0:00.08 -bash
apple            75772   0,0  0,0 33619312   2640 s004  Ss+   9:25     0:00.03 /usr/local/bin/bash --init-file /Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/contrib/terminal/common/scripts/shellIntegration-bash.sh
apple            88204   0,0  0,0 34122828    836 s007  S+   10:20     0:00.00 grep bash
apple            83845   0,0  0,0 34151264   1924 s007  S    10:00     0:00.04 -bash
apple            81464   0,0  0,0 34151264   1876 s006  S     9:50     0:00.03 -bash

la réunion de deux commandes avec pipe nous permet d’avoir un affichage plus restreint.

C’est quoi un named pipe?

un named pipe est un fichier qui permet de faire transiter des messages, dans la logique du premier entré premier sorti ( First In First Out en anglais, sous l’acronyme FIFO). Le fait que ce soit un fichier (un peu spécial) fait qu’il est persistent, jusqu’à ce qu’il soit effacé. Un named pipe permet de faire communiquer des process qui n’ont aucun lien entre eux ! Vous pouvez imaginer comme un téléphone pour les programmes.

Création d’un named pipe

la création se fait avec la commande mkfifo
$ mkfifo mypipe

ls -l
total 0
prw-r--r--  1 apple  staff  0 15 fév 21:42 mypipe

Regardez la sortie de la commande ls -l, la première lettre est « p » comme pipe.

Ecriture et lecture d’un named pipe

Dans ce terminal écrivez quelque chose et passez le au pipe :

echo 'Hello le named pipe!' > mypipe
après avoir écrit cette commande, le shell ne vous rend pas la main
ouvrez un second terminal
et tapiez la commande
$ cat < mypipe
Hello le named pipe!

Un exemple plus consistant

Ouvrez un premier terminal et mettez ce code shell :

$ while true;do
> echo "message at $(date)" > mypipe
> sleep 2
> done

Ce script va toutes les 2 secondes afficher le message avec la date et l’envoyer à mypipe. (Pour taper un script multiligne, utilisez la combinaison SHIFT + ENTREE pour sauter une ligne.)

Ouvrez un second terminal et tapez la commande pour lire la sortie de mypipe:

cat < mypipe
message at Sam 15 fév 2025 22:32:53 CET
$

Aussitôt le message lu le shell vous rend la main Essayez d’enchainer rapidement deux cat < mypipe, si rien n’est dispo à la sortie, le shell ne vous rend pas la main. Notez que si vous attendez un peu trop longtemps,les messages se perdent donc il faut lire de façon continue, ce que nous allons faire avec tail.

tail -f < mypipe

Faire une boucle pour écouter continuellement des message

#Le code ci-dessous va écouter en permanence des messages venant du pipe

while true; do cat < mypipe; done

# ouvrez un second terminal dans le même hôte et faites
$ echo "un message" > mypipe

#le code ci dessus va envoyer un message au pipe et rendre la main.

Ecrire sur un named pipe vers un hôte distant (A venir)

Avec Linux, il est très facile via SSH de traverser la frontière du cyberespace !Allez sur un serveur Linux er créez un named pipe.

Retour en haut