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.
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
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,
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
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
# 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
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
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
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
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
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
Voici ce qui pourrit se passer si on n’a pas de Supervisor qui fait du redémarrage automatique, du logging, du monitoring :
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.
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.
Processus d’arrière-plan peu fiables Si vous essayez de démarrer plusieurs processus avec des scripts shell, comme :
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.
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.
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
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.
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.
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
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)
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
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
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
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.
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
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
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>
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
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
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.
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 !
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
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.
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
// 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
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)
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 :
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
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.