Python : comment créer un serveur web en une seule ligne de commande ?
Sommaire
I. Présentation
Nous allons voir dans ce tutoriel comment créer rapidement et facilement un serveur web via Python3, et cela, en une seule ligne de commande !
La création d'un serveur web rapide peut répondre à plusieurs besoins : tests rapides, échanges de fichiers entre systèmes, mise en place d'un service léger pour un besoin ponctuel, etc. Python3 possède un module fait pour répondre à ce besoin : http.server. C'est ce module que nous allons utiliser ici.
Libraire, bibliothèque, module : quelle différence ?
La différence principale entre un module Python et une bibliothèque réside dans leur portée et leur structure.
- Module : un module est un fichier unique contenant du code Python. Ce fichier peut contenir des variables, des fonctions, des classes et des objets. Exemple : Un fichier nommé "math.py" qui contient des fonctions mathématiques.
- Bibliothèque : une bibliothèque est un ensemble de modules regroupés. Elle peut contenir plusieurs modules organisés de manière à offrir des fonctionnalités plus complexes ou plus complètes. Exemple : La bibliothèque “NumPy” contient plusieurs modules pour la manipulation et le calcul sur les tableaux.
- Librairie : il s'agit d'une erreur de traduction qui provient du mot "library" en anglais, dont la traduction est ... "bibliothèque". Cependant, cette erreur est tellement fréquente que tout le monde comprend bien de quoi il s'agit lorsque l'on parle de librairie en programmation.
II. Premiers pas avec Python3 http.server
Imaginons que nous avons besoin partager rapidement du contenu disponible sur notre système à un collègue situé sur le même réseau que nous. Nous pouvons choisir d'utiliser le module "http.server" pour lui partager en direct tout notre répertoire courant. Je prépare pour l'exemple un répertoire de travail :
cd /tmp
mkdir a_partager
cd a_partager
mkdir dossier1 a_partager/dossier2
touch dossier1/liste.docx dossier2/image.jpg README.txt
cd a_partager
Il ne s'agit ici que d'un exemple, libre à vous de partager ce que vous souhaitez. Mais, gardez en tête que, par défaut, votre serveur web mettra à disposition le contenu du répertoire dans lequel la commande est exécutée.
Attention : il n'y a ici ni chiffrement ni authentification. Cela signifie que n'importe qui sur le réseau peut découvrir, parcourir et récupérer les documents que vous partagerez. Il faut en être conscient et opter pour d'autres solutions si la sécurité est un critère à prendre en compte.
Une fois dans le répertoire que nous souhaitons partager (il convient de se positionner dans ce répertoire avec "cd"), il nous suffit de démarrer notre service web via l’option "-m" et en indiquant module "http.server" :
# Lancer un service web léger avec http.server
python3 -m http.server
Dès lors, Python mettra en écoute un service web qui sera donc accessible sur l’ensemble de vos interfaces web sur le port TCP/8000.
Pour connaître vos différentes adresses IP (si vous avez plusieurs interfaces réseau actives), utiliser la commande “ip a”.
Ce port sera notamment accessible depuis d'autres systèmes du réseau si aucun pare-feu n'en bloque l'accès, pour l’exemple, j’y accède ici via mon adresse localhost (127.0.0.1) :
Lorsque vous accéderez aux ressources de votre service web, des logs apparaîtront dans le terminal depuis lequel vous avez lancé votre service web :
Cela vous permettra de suivre les requêtes qui ont été faites, ainsi que les réponses (code HTTP) obtenues par vos clients. Pour mettre fin à votre service web, il vous suffit de faire un "Ctrl+C" à l'aide du clavier.
Si vous souhaitez que votre service web écoute sur un autre port que le port TCP/8000, vous pouvez le spécifier à la suite de notre première commande :
# Mise en écoute du service web sur un port choisi
python3 -m http.server <port>
# Exemple
$ python3 -m http.server 8082
Serving HTTP on 0.0.0.0 port 8082 (http://0.0.0.0:8082/) ...
Le premier message affiché vous permettra de valider la mise en écoute sur le port choisi. Si vous souhaitez mettre en écoute votre service web sur un port inférieur à 1024, il vous faudra les permissions de l'utilisateur "root" pour le faire.
# Utilisation de sudo pour la mise en écoute sur un port privilégié
sudo python3 -m http.server 80
Message "Address already in use", qu'est-ce que ça veut dire ?
Lors du lancement de votre serveur web léger Python3, vous pouvez obtenir le message d'erreur suivant :
Cela signifie qu’un autre service est déjà en écoute sur ce port, vous pouvez tenter d’identifier lequel via la commande "ss -petulan" ou en choisir un autre.
III. Aller plus loin : les options de http.server
A. Ne pas partager le contenu du répertoire
Si vous ne souhaitez pas que les visiteurs de votre service web puissent voir le "Directory Listing", c'est-à-dire la page par défaut qui affiche le contenu du répertoire courant, il vous suffit de créer un fichier "index.html" (même vide) dans votre répertoire :
Gardez cependant à l'esprit que les fichiers et dossiers de votre répertoire courant ne seront toujours accessibles si le client en connaît le chemin ou le nom ! Il s'agit plus d'un élément esthétique que d'une mesure de sécurité.
B. Partager un répertoire précis
Nous pouvons aussi facilement partager un répertoire précis au lieu du répertoire courant lors de la création de notre service web. Il faut pour cela spécifier l'option "-d" ou "--directory" :
# Précision du répertoire à exposer via http.server
python3 -m http.server -d <chemin_repertoire>
# Exemple
$ python3 -m http.server -d /tmp/a_partager/
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
Dès lors, quel que soit le répertoire dans lequel on se trouve dans le système de fichier, c'est le répertoire indiqué qui sera exposé :
C. Exposer le service sur une interface précise
Nous avons vu au tout début de ce tutoriel que, par défaut et si vous disposez de plusieurs adresses IP, le module “http.server” de Python3 va mettre en écoute son service web sur toutes vos adresses IP en même temps. Ce comportement peut être modifié grâce à l'option "-b" ou "--bind". Par exemple, si je souhaite ne rendre accessible mon service web que sur mon adresse loopback (localhost), il suffit de préciser l'adresse IP de l'interface en question :
# Restreindre l'interface d'exposition du service web http.server
python3 -m http.server <adresse IP>
# Exemple
$ python3 -m http.server --bind 127.0.0.1
Serving HTTP on 127.0.0.1 port 8000 (http://127.0.0.1:8000/) ...
Vous aurez dans votre terminal la validation que c'est bien sur cette adresse IP là que sera exposé le service web, et aucune autre. Dans mon exemple, cela me permet d'être sûr qu'aucun voisin sur le réseau local de mes autres interfaces ne pourra accéder à mon service web.
Vous pouvez naturellement combiner cette option avec la sélection du port vue précédemment.
IV. Conclusion
Nous avons vu dans ce tutoriel comment mettre en place très rapidement un service web léger en Python grâce au module "http.server". C'est une méthode très pratique qui possède quelques options de personnalisation.
Il faut savoir que le module "http.server" de Python3 peut être utilisé de façon beaucoup plus avancée via des scripts et véritables programmes. Malgré tout, on peut vite atteindre ses limites, notamment concernant ses performances qui ne pourront égaler celles des services web complets et dédiés comme Nginx ou Apache.