Linux

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;
        }
    }
}

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

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;

  • 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

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.

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 :

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.

Prendre en main UFW Uncomplicated Firewall sous Linux Ubuntu

Vous avez sans doute entendu parler de iptables, ce firewall très connu sous Linux, mais peut être u peu difficile à configurer car très technique et verbeux. Il existe un autre équivalent beaucoup plus friendly : UFW. UFW est un e interface d’accès à iptables, pour faciliter l’usage de ce dernier.

Un pare feu a pour rôle de bloquer le traffic réseau sortant ou entrant, sur le protocole que vous voulez (par exemple SSH, HTTP etc). Vous pouvez blocker des ports, des adresses IP et des intervalle d’adresses IP.

Installation de UFW et activation

Si ce n’est déjà installé vous pouvez faire la commande suivante:

$ sudo apt update
$ sudo apt upgrade
# vérification préalable de l'existence de UFW
$ which ufw


# le cas échéant
$ sudo apt-get install ufw

# après installation on véirifie l'état d'UFW
$ sudo ufw status verbose

-----------------------------
Output
Status: inactive

# on active UFW
$ sudo ufw enable

#pour désactiver
$ sudo ufw disable

La commande status est importante pour avoir l’état des lieux, je vous recommande de souvent la faire pour diagnostiquer des erreur.

On eptu utiliser une autre command pour avoir le status

systemctl status ufw
● ufw.service - Uncomplicated firewall
     Loaded: loaded (/lib/systemd/system/ufw.service; enabled; vendor preset: enabled)
     Active: active (exited) since Sun 2025-02-16 09:12:11 CET; 30min ago
       Docs: man:ufw(8)
   Main PID: 129 (code=exited, status=0/SUCCESS)

Feb 16 09:12:11 PC-YVON systemd[1]: Starting Uncomplicated firewall...
Feb 16 09:12:11 PC-YVON systemd[1]: Finished Uncomplicated firewall.

Autoriser un port sur un protocol : port 80 sur TCP

# va autoriser les connexion HTTP (web)
$ sudo ufw allow 80/tcp

Rule added
Rule added (v6)

Status: active
Logging: on (low)
Default: allow (incoming), allow (outgoing), disabled (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
80/tcp                     ALLOW IN    Anywhere
80/tcp (v6)                ALLOW IN    Anywhere (v6)

Nettoyer toutes les règles:

ufw reset

# après redémarrer
ufw enable

Liste des commandes de UFW:

Usage: ufw COMMAND

Commands:
 enable                          enables the firewall
 disable                         disables the firewall
 default ARG                     set default policy
 logging LEVEL                   set logging to LEVEL
 allow ARGS                      add allow rule
 deny ARGS                       add deny rule
 reject ARGS                     add reject rule
 limit ARGS                      add limit rule
 delete RULE|NUM                 delete RULE
 insert NUM RULE                 insert RULE at NUM
 prepend RULE                    prepend RULE
 route RULE                      add route RULE
 route delete RULE|NUM           delete route RULE
 route insert NUM RULE           insert route RULE at NUM
 reload                          reload firewall
 reset                           reset firewall
 status                          show firewall status
 status numbered                 show firewall status as numbered list of RULES
 status verbose                  show verbose firewall status
 show ARG                        show firewall report
 version                         display version information

Application profile commands:
 app list                        list application profiles
 app info PROFILE                show information on PROFILE
 app update PROFILE              update PROFILE
 app default ARG                 set default application policy

https://www.vps-mart.com/blog/how-to-configure-firewall-with-ufw-on-ubuntu

// Principales commandes de ufw
===============================
sudo ufw enable	
sudo ufw disable	
sudo ufw status	
sudo ufw status numbered	
sudo ufw allow 22	
sudo ufw allow http	
sudo ufw allow 8080/tcp	
sudo ufw deny from 192.168.1.100	"192,168,1,255 adresse de broadcast
decouverte de réseau
imprimante qui annonce sa disponibilité"
sudo ufw deny 23	
sudo ufw status numbered	
sudo ufw delete NUMERO	
sudo ufw reset	
sudo ufw allow from 192.168.1.0/24	"notation CIDR sert à représenter un bloc d'adresses IP, IP est codé sur 32 bits, ici 24 premiers bits sont fixes
Quelle plage d’adresses couvre ce bloc ? 192.168.1.1 à 192.168.1.254
/24 correspond à 255.255.255.0 (masque de sous réseau)"
sudo ufw deny from 10.0.0.0/8	
sudo ufw limit ssh	

Configurer le firewall Linux iptables

iptables est un firewall de Linux. La configuration est vaste car en matière de réseau il y a différents types de protocole. Par exemple si vous pingez une adresse IP c’est le protocole ICMP qui est en jeu. nftables est censé remplacer iptables.

Installation de iptables

apt install iptables

// connaitre la version de iptables
iptables --version

Concepts clé d’iptables

  • Tables, les 4 tables filter, nat, mangle,raw
  • Chains INPUT OUTPUT, FORWARD
  • Policies comportement par défaut d’une chaine (ACCEPT or DROP)
  • Rules règles appliquées au réseau

Lister et voir les règles

Pour voir les règles tapez la commande suivante :

iptables -L



Pour lister les règles avec leur numéro :
iptables -L --line-numbers

La politique par défaut c’est quoi?

Imaginez une clause switch case, le cas par défaut est celui qui n’est couvert par aucune règle.

Comment définir une politique par défaut?

avec le flag -P

iptables -P <chaine> <cible>

iptables -P INPUT DROP

iptables -P OUTPUT ACCEPT

iptables -P FORWARD ACCEPT

Le flag -P ne crée pas de nouvelle règle.

Exemple de politique par défaut

iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

Exemple de règles

Ajouter une règle d’interdiction pour les ping (protocole ICMP)

#Tapez la commande suivante pour ajouter une règle à iptables
iptables -I INPUT -p ICMP --icmp-type 8 -j DROP

Bloquer les demandes SSH

iptables -A INPUT -i eth0 -p tcp --dport 22 -j DROP

Supprimer un règle

//Pour supprimer les règles :
supprime la règle 1
iptables -D INPUT 1

Création de règles

Autoriser SSH

sudo iptables -A INPUT -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
sudo iptables -A OUTPUT -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT

Autoriser HTTP et HTTPS

sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT

Autoriser le ping (ICMP)

iptables -A INPUT -p icmp -j ACCEPT

Autoriser le traffic local (loopback)

iptables -A INPUT -i lo -j ACCEPT

Refuser une IP spécifique

iptables -A INPUT -s 192.168.1.100 -j DROP

Limitation brute force

sudo iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --set --name SSH
sudo iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 4 --name SSH -j DROP

Exemple de configuration typique d’un serveur

# Vider les règles existantes
iptables -F
iptables -X

# Politique par défaut
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

# Autoriser loopback
iptables -A INPUT -i lo -j ACCEPT

# Autoriser les connexions établies
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# Autoriser SSH
iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# Autoriser HTTP / HTTPS
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# Autoriser ping
iptables -A INPUT -p icmp -j ACCEPT

// on sauvegarde les règles
iptables-save > /etc/iptables/rules.v4

C’est quoi le loopback?

C’est l’interface réseau de votre ordinateur, appelé lo (lettre l et lettre o)

Configurer fail2ban

Qu’est ce que c’est fail2ban?

Fail2ban, c’est un outil de sécurité pour les serveurs, principalement utilisé sous Linux. Son rôle principal est de protéger le serveur contre les attaques par force brute (par exemple, quand un attaquant essaie de deviner un mot de passe en tentant plein de fois de se connecter).

Voici ce que fait fail2ban concrètement :

  • Il surveille les fichiers logs des services (comme SSH, FTP, Apache, etc.) pour détecter des tentatives de connexion échouées répétées.
  • Dès qu’il remarque qu’une même adresse IP tente plusieurs fois sans succès (configurable), il va bloquer cette IP temporairement via le pare-feu (iptables, nftables, etc.).
  • Le blocage est temporaire (par exemple 10 minutes, 1 heure), mais si l’IP continue à poser problème, fail2ban peut prolonger ce blocage.
  • Cela limite efficacement les risques d’intrusion par brute force sans que tu aies à intervenir manuellement.

Ce que n’est pas fail2ban

Fail2ban ne va pas vous bloquer tout seul, il a besoin d’un firewall comme iptables pour le faire ou ufw. Fail2ban met juste en place des IP à bloquer.

Installer fail2ban

Si vous êtes sous Debian faites la commande suivante :

sudo apt install fail2ban

#apt est une nouvelle version de la commande apt-get, designé pour être plus ergonomique

Ensuite dupliquez les fichiers fail2ban.conf et jail.conf e, fail2ban.local et jail.local, c’est une habitude à prendre pour en cas de mise à jour de fail2ban, vous perdiez votre configuration.

Configurer fail2ban pour protéger ssh

Nous allons modifier avec vim ou nano le fichier jail.local. Comme nous voulons protéger dans cet article seulement sshd, nous allons trouver la section [sshd] et nous assurer de trouver les lignes suivantes

[sshd]

maxretry=2
findtime=600   #10 minutes soit 600 secondes
bantime=600  # temps d ebanissement

bantime est le temps de banissement, findtime est le temps durant lequel les tentatives infructueuses de login se déroulent, c’est la fenêtre d’observation.

Expérimentation:

Connectez vous à un compte et faites exprès d’échouer 2 sessions de connexion de suite.

Ensuite tentez de vous connecter à nouveau.

Quelques commandes relatives à fail2ban

connaitre l’état des lieux de fail2ban

# connaitre l'état des lieux des bans pour un programme comme sshd
fail2ban-client status sshd

#Redémarrer fail2ban après une modification de fichier d configuration

sudo systemctl restart fail2ban

Le fichier de log de fail2ban se trouve dans /var/log/fail2ban.log

en conjonction de fail2ban, il est intéressant de monitorer les logs de connexion du fichier auth.log. Si ce fichier n’est pas présent c’est qu’il faut installer via la command suivante :

sudo apt-get install rsyslog

NodeJS Express et variables d’environnement tout ce qu’il faut savoir

Vous connaissez tous ce code si vous avez fait du Node-Express :

const port = process.env.PORT || 3000;
const folder = process.env.FOLDER || '';

Lorsque vous démarrez votre serveur NodeJS, il écoute le port 3000 grâce à ce bout de code

app.listen(port, () => {
    console.log(`Server running on http://localhost:${port}`);
});


la ligne de code process.env.PORT || 3000; veut dire qu’en environnement de développement l’url pour atteindre le serveur est http://localhost:3000. Quid de l’environnement de production? Et d’abord, comment sait on que c’est pour l’environnement de production? Tout simplement en développement la variable port vaut 3000 car la constante PORT n’est pas définie en dévelolppement (normalement). En vertue de l’opérateur || (OU), ce sera al valeur 3000 qui sera assignée à al variable port.

En général en programmation, les constante (valeurs qui ne bougent pas sont en majuscule, et les variables en minuscule.

Considérons les différents cas de figure où la variable port peut être définie

Environnement local

On décide d’assigner une valeur à port (chose qu’on ne fait pas normalement) mais c’est pour illustrer. La commande ci-dessous est valable pour la session.

#MACOS/Linux
PORT=3000 node server.js

ou 
export PORT=3000
node server.js


#windows CMD
set PORT=3000
node server.js

Utilisation de fichier d’environnement

Créer un fichier .env
#installer dotenv
npm install dotenv


require('dotenv').config();

const port = process.env.PORT || 3000;
console.log(`Server running on port ${port}`);

configuration niveau système

Dans les systèmes Linux, vous pouvez ajouter la variable d’environnement au fichier .bashrc ou au fichier etc/environment

Faire une archive tar sans préserver les chemins de fichiers

Syntaxe usuelle d la commande tar pour la création d’une archive

soit la structure de fichiers suivant :
./test/folder1/folder1a/fichier1.txt
./test/folder1/fichier1.txt
./test/folder2/fichier3.txt


Nous sommes dans le répertoire test, et nous créons une archive de façon classique sans compression:
> tar -cvf archive.tar *

folder1/
folder1/folder1a/
folder1/folder1a/fichier1.txt
folder1/fichier1.txt
folder2/
folder2/fichier3.txt

Pour voir le contenu sans le désarchiver

> tar -tf archive.tar

folder1/
folder1/folder1a/
folder1/folder1a/fichier1.txt
folder1/fichier1.txt
folder2/
folder2/fichier3.txt

Nous voyons que les fichier ainsi que les dossiers sont préservés, ainsi si vous décompressez l’archive dans un autres répertoire, la structure sera conservée.

Archiver avec tar sans garder la structure des fichiers

Parfois on a envie de rassembler tous les fichiers sans conserver l’arborescence, dans un unique répertoire. Voici comment faire :

On se place dans le répertoire à archiver.
> find . -type f | tar --transform='s|^\./||;s|/|_|g' -T - -cvf archive.tar

on pipe deux commandes
find .-type f va trouver tous les fichiers à partir de là où se trouve l'invite de commande

Le seconde commande va archiver avec une transformation, on renomme les fichiers qui sont à archiver pour les rendre uniques. Le format du nom du fichier est composé de mot du chemin vers le fichier dont les slash seront transformés en underscore.

> tar -tf archive.tar
folder1_folder1a_fichier1.txt
folder1_fichier1.txt
folder2_fichier3.txt

Le renommage est plus prudent car on peut avoir deux fichiers du même nom.

Retour en haut