Introduction

Historique
Dans le courant des années 60, plusieurs développements ont commencé afin de fournir des systèmes d'exploitation permettant aux utilisateurs de gérer leurs fichiers, de partager le temps de la machine pour l'exécution des processus lancés par ces mêmes utilisateurs. En effet, à l'époque les utilisateurs soumettaient des /batch jobs/ aux opérateurs des ordinateurs de l'époque, et, pour simplifier, revenaient le lendemain - ou la semaine suivante - pour obtenir leurs résultats. Ce qui n'était pas très pratique.
Dès lors, plusieurs systèmes furent imaginés: CTSS (/Compatible Time Sharing System/) du MIT, en 1961, qui proposait déjà du courrier électronique (entre utilisateurs du système), du traitement de texte, etc. Son successeur était censé être /MultiCS/, projet très ambitieux - et difficilement réalisable avec les moyens techniques de l'époque - lancé en 1964. Cependant, au vu du retard pris dans le développement de MultiCS, le concept même de système d'exploitation a failli être abandonné (pour revenir aux /batch jobs/). MultiCS était un OS multiutilisateur, multitâche préemptif avec gestion des priorités entre les processus, et disposant d'un système de fichiers hiérarchique proche des systèmes de fichiers que l'on connaît aujourd'hui.
Cependant, les ressources qu'il demandait (en temps de travail des développeurs) ont conduit un des principaux contributeurs, Bell Labs, à se retirer du projet. Deux ingénieurs, Dennis Ritchie et Ken Thompson, qui travaillaient sur MultiCS décidèrent de développer leur propre OS, qu'ils nommèrent (d'une façon un peu facétieuse) UNICS (/UNiplexed Information and Computing Service/), dont la première version opérationnelle date de la fin 1969 (c'est pour ça que le temps informatique (timestamp UNIX) date du 1er janvier 1970)), qui devint UNIX. Dans la foulée, Dennis Ritchie inventa le langage C, en 1971, lors de la première réécriture d'UNIX.

Dans le courant des années 70 et 80, UNIX devint le système d'exploitation dominant, son modèle Mainframe/"clients légers" (Terminaux physiques, par exemple le légendaire DEC VT100) s'adaptant particulièrement bien aux besoins des entreprises de l'époque.
Il fut le socle sur lequel se construisirent Internet (ARPANet à l'époque) et les différents protocoles encore en cours d'utilisation de nos jours (notamment SMTP (mails), DNS, NNTP (newsgroups), IRC, (S)FTP, etc), les outils de typographie encore utilisés aujourd'hui (TeX/LaTeX dont PDF n'est qu'un dérivé), les éditeurs de texte comme Emacs ou Vi (puis Vim), et il donna le jour à une importante descendance (BSD UNIX, AT&T UNIX, SGI IRIX, Sun Solaris, IBM AIX, macOS, Plan 9 From Bell Labs/9Front - qui était censé devenir son remplaçant avec pleins d'idées novatrices pour l'époque (chaque processus est isolé des autres dans un quasi-container, tout est vraiment fichier, même la carte son, axé réseau (tout est distribuable, du système de fichiers aux CPUs, sur le réseau)), MINIX pour les étudiants).
Cependant, avant l'arrivée des BSD libres et surtout gratuits au début des années 90 (NetBSD, FreeBSD, OpenBSD...), le prix prohibitif des licenses en interdisaient purement et simplement l'acquisition par les particuliers et les petites entreprises, ce qui entraîna le succès d'un certain IBM PC et d'une petite entreprise nommée Microsoft dans le milieu des petites entreprises à la fin des années 80 et dans les années 90, UNIX se retrouvant "cantonné" dans les grandes entreprises qui avaient besoin d'un OS fiable et capable de gérer des milliers voire millions d'utilisateurs au sein de réseaux TCP/IP complexes.
En 1991 (le 25 août pour être précis), un jeune étudiant du nom de Linus Torvalds qui travaillait sur un noyau de système d'exploitation posta sur Usenet (newsgroups, sur le groupe /comp.os.minix/) un message devenu culte:

"Hello everybody out there using minix - I'm doing a (free) operating system (just a hobby, won't be big and professional like gnu) for 386(486) AT clones. This has been brewing since april, and is starting to get ready. I'd like any feedback on things people like/dislike in minix, as my OS resembles it somewhat (same physical layout of the file-system (due to practical reasons) among other things). I've currently ported bash(1.08) and gcc(1.40), and things seem to work. This implies that I'll get something practical within a few months, and I'd like to know what features most people would want. Any suggestions are welcome, but I won't promise I'll implement them
Linus (torvalds at kruuna.helsinki.fi) PS. Yes – it's free of any minix code, and it has a multi-threaded fs. It is NOT portable (uses 386 task switching etc), and it probably never will support anything other than AT-harddisks, as that's all I have
."

Le noyau qui ne devait pas devenir "professionnel" finira par être utilisé partout, de la cafetière connectée aux smartphones, en passant par les ordinateurs (desktop et laptops), et les super-calculateurs. Vous vous en servez tous les jours sans le savoir: dans votre *box, dans votre smartphone, en utilisant la plupart des sites Web, en envoyant un mail, en discutant sur Discord, lorsque vous jouez à des jeux en ligne...

Cependant, il est bon de noter que Linux (le noyau, qui devait s'appeler Freax selon le souhait de Linus Torvalds) n'est pas un noyau UNIX (comme le sont Mach ou le kernel "bsd" d'OpenBSD), mais un noyau de type UNIX. Il peut donc proposer une API différente (mais globalement compatible) de l'API d'un kernel UNIX "standard".
Architecture générale du système
Le noyau Linux
Le noyau (/kernel/) Linux est un noyau de système d'exploitation multitâche préemptif et multi-utilisateurs. C'est un logiciel principalement libre (mais qui peut être complété par des /blobs/ propriétaires (drivers et firmwares non-libres)). Il est développé principalement en langage C par des dizaines de milliers de contributeurs (salariés ou bénévoles).
Un /kernel/ est le coeur d'un OS. Il est en charge de fournir une API permettant aux logiciels de communiquer avec le matériel. Il a été porté sur de nombreuses architectures: m68k (abandonné), ARM, SPARC, MIPS, POWER, x86/amd64, RISC-V...
Il respecte les normes POSIX. C'est un noyau dit /monolithique/, par opposition aux micro-noyaux (GNU Hurd, MINIX, Mach...). Il est modulaire depuis sa version 2.0, c'est à dire qu'on peut ajouter ou supprimer des fonctionnalités du kernel "à la volée", par exemple:
sudo -s
rmmod nvidia
modprobe nvidia
exit; startx
Ce qui rapproche son comportement d'un micro-noyau où les différents drivers sont exécutés dans l'espace utilisateur, bien qu'ils soient, ici, exécutés dans l'espace noyau.
Le kernel 1.0, en 1994, comptait environ 177.000 lignes de code. Il en compte désormais 27.8 millions (ce qui inclus, bien évidemment, les différentes architectures et pilotes de périphériques disponibles. Le /kernel/ que vous faites tourner sur vos machines (x86/amd64 ou ARM (Raspberry Pi par exemple)) n'en utilise qu'une partie lors de sa compilation pour produire l'exécutable correspondant à votre matériel (enfin, plutôt un exécutable correspondant à la plupart (générique) des différents périphériques et CPUs que nous utilisons. Dans l'embarqué, on peut avoir des kernels qui, une fois compilés, pèseront moins de 2Mo, là où par exemple le kernel utilisé par ma machine pèse ~20Mo compressé et ~60Mo décompressé en RAM - mais il inclut des drivers qui ne sont pas nécessaires pour l'utilisation de ma machine, et donc non-utilisés. L'avantage étant que je peux prendre mon SSD, l'installer dans une autre machine avec un équipement différent (par exemple une carte graphique AMD au lieu d'un GPU Intel), et démarrer directement dessus sans configuration particulière). Par exemple, le kernel décompressé de Raspbian (distribution GNU/Linux basée sur Debian spécialisée pour Raspberry Pi) fait 15Mo.
L'espace utilisateur et les outils GNU/Linux

Bien sûr, un /kernel/ tout seul ne permet pas de faire grand chose au commun des mortels (c'est à dire nous!). Il lui faut un ensemble d'utilitaires (l'espace utilisateur) permettant à des opérateurs humains d'interagir avec le matériel, pour, par exemple, regarder une vidéo de chatons qui se cassent la figure sur Youtube® ou envoyer des likes sur Instagram à un ou une influenceur ou influenceuse dont le seul but est de vous faire acheter des trucs inutiles, même si on peut faire des choses bien plus intéressantes avec sa machine.
Plus sérieusement, l'/userland/ va nous permettre de manipuler nos fichiers, d'établir des connexions avec d'autres machines (en réseau local ou sur Internet), de configurer nos périphériques (interfaces réseau, carte graphique, disques durs), d'afficher des caractères sur l'écran, ou des fenêtres avec des caractères dedans, etc.
Quand on parle de distribution Linux, on fait un petit abus de langage: on oublie cet /userland/. Dans le cas des distributions Linux que nous utilisons au jour le jour, il s'agit de l'userland GNU (GNU is Not Unix), projet lancé en 1983 par Richard Stallman, afin de réécrire entièrement l'/userland/ UNIX en remplaçant tous les utilitaires par des utilitaires dont le code source est libre. Par exemple la commande UNIX ls et la commande GNU ls font, à la base, la même chose: afficher le contenu du répertoire courant. Cependant, leurs options (ls -al par exemple) peuvent différer, et l'une ou l'autre version peuvent proposer des options spécifiques afin d'en améliorer - ou pas - le fonctionnement.
On parle de /distribution/ GNU/Linux: il s'agit de l'OS formé par le kernel, l'userland GNU, et les outils spécifiques de la distribution. Par exemple, une distribution Debian GNU/Linux (et ses dérivés: Ubuntu, Mint, etc) utilise le logiciel /apt/ pour installer ou supprimer des logiciels, là où une distribution CentOS GNU/Linux (et ses dérivées: Fedora, etc) utilisera l'utilitaire /yum/. Cependant la base du système (le kernel et les outils GNU) restent identique: le logiciel grep est identique sur Debian ou sur CentOS, par exemple, mais pas forcément sur Alpine, qui n'inclut pas les outils GNU par défaut (elle utilise les outils Busybox, mais propose les outils GNU dans son /gestionnaire de paquets/).

De même, on peut aussi distinguer des distributions axées desktop, comme Ubuntu ou Fedora, ou /power-users/ comme Archlinux ou Gentoo.

Pour les serveurs, on préfèrera les distributions proposant du support à long terme (LTS, /Long Term Support/) comme Debian, Ubuntu LTS, Rocky ou Alma Linux (version communautaire de RedHat, dérivée de CentOS avant que CentOS devienne une rolling release, jusqu'à dix ans de mises à jour!), RHEL (RedHat Enterprise Linux - support payant), qui permettent de se préparer entre chaque version majeure aux changements de configurations et /upgrades/ nécessaires (par exemple en cas de montée de version majeure du logiciel de bases de données utilisé (I'm looking at you, PostgreSQL)) sur plusieurs années, tout en assurant un support de sécurité sur le long - voire très long - terme nécessaire dans les grandes entreprises ou administrations (les "mammouths" mettent du temps à démarrer). En effet, on ne veut pas casser notre base de données de production, ou notre serveur Web, sur une simple mise à jour normale du système.

On pourrait aussi parler de distributions comme ProxmoxVE ou XCP-NG axées virtualisation, haute-disponibilité et /clustering/, ou NixOS, GuixSD axée reproductibilité de l'environnement mais c'est en dehors du contexte de ce cours.

Au final, suivant les besoins, on peut utiliser une distribution "générique" comme Debian, Ubuntu (LTS), CentOS, pour la stabilité et le large choix d'outils disponibles, ou des distributions spécialisées comme Proxmox (rien ne vous empêche d'installer les outils de Proxmox sur Debian, cependant), ou Alpine, ou NixOS pour avoir rapidement le /tooling/ nécessaire disponible tout en se fondant sur une base éprouvée, stable, et maintenue (donc relativement sûre).
L'important est d'utiliser le bon outil par rapport au cahier des charges, au budget, et au temps disponible. C'est aussi cette versatilité qui fait la force de GNU/Linux, n'en déplaise aux détracteurs^Wtrolls que vous pourrez rencontrer sur les divers réseaux sociaux (reddit, hackernews, mastodon, twitter) qui ont tendance à se plaindre de la diversité de l'écosystème Linux et UNIX car le seul truc qui les intéresse c'est leur desktop et leurs jeux vidéos, ce qui n'a aucun rapport avec nos besoins professionnels (fin du troll). Que vous travailliez sur des serveurs Web, de la virtualisation, des orchestrateurs de containers, de l'embarqué, il y a toujours une distribution "clefs en main".
(et en vrai, si vous voulez jouer/bidouiller/etc sous GNU/Linux: Ubuntu si vous n'êtes pas à l'aise, Archlinux si vous voulez le tout dernier driver nvidia. Et pour la bidouille potentiellement destructrice, KVM (inclu dans le kernel) vous permet de créer rapidement des machines virtuelles pour tester avant de tout casser. Une VM, ça se casse, ça se remplace, c'est mieux que Carglass (je suis déjà dehors).)
Les processus
Définition
Un processus est un programme en cours d'exécution. Une application peut être composée de plusieurs processus: par exemple un navigateur Web peut créer un processus par onglet, puis avoir d'autres processus lancés pour interpréter (ou compiler à la volée (JIT)) du javascript, etc.
On parle de processus enfant pour un processus qui a été lancé par un autre processus (son parent). Sous UNIX, il est nécessaire de "tuer" tous les processus enfants d'un processus parent avant de tuer le parent, sinon, les processus enfants deviendront des processus "zombies". La classe, hein? (ou flippant, au choix )
Sous GNU/Linux ou sous UNIX, chaque processus dispose d'un numéro de processus l'identifiant: c'est son PID (/Process IDentifier/).
Le kernel n'a pas de numéro de processus. le processus de PID 1 est le parent de tous les processus, il s'agit en général du processus d'initialisation du système, qu'on appelle /init/. C'est lui qui est en charge de lancer, stopper, redémarrer, allouer des ressources aux services (ensembles de processus) que l'utilisateur lancera (ou qui seront lancés automatiquement au démarrage par /init/).
Par exemple, le serveur Web Apache est un ensemble de processus (un /service/), que l'on voudra lancer au boot sur un serveur: c'est le "boulot" d'un /init/. Si l'administrateur veut stopper, relancer ou recharger la configuration d'Apache, il le "demandera" à l'init en utilisant une commande précise, par exemple, sous Debian (ou ubuntu, etc):
systemctl stop apache2
# pour le relancer au lieu de le stopper:
systemctl restart apache2
# dans le cas d'un changement de configuration
systemctl reload apache2
Dans le cas de la plupart des distributions GNU/Linux ce PID 1 est /systemd/. Mais il existe d'autres /inits/: par exemple la distribution Alpine utilise OpenRC. Il existe aussi sysvinit (init System V UNIX), ou runit. Des fous furieux utilisent aussi Emacs comme init. Dans ce cours on se focalisera sur systemd, vu qu'il s'agit de l'init utilisé par la plupart des distributions GNU/Linux que nous utiliserons.
On ne peut - normalement - pas tuer le PID 1 sous GNU/Linux, là où sous BSD (et macOS) cela va soit rebooter la machine, soit l'éteindre.
Exemple: pstree
La commande /pstree/ permet d'afficher l'ensemble des processus - ainsi que leurs liens de "parenté" - tournant sur le système, et constitue une bonne représentation de la notion que nous venons d'aborder:
# sortie abrégée pour lisibilité
# en vrai il y a bien plus de processus lancés
$ pstree -T -p -A
systemd(1)-+-ModemManager(1164)
|-NetworkManager(1064)
|-accounts-daemon(1057)
|-acpid(1058)
|-at-spi-bus-laun(1416)---dbus-daemon(1421)
|-at-spi-bus-laun(2819)
|-at-spi2-registr(1455)
|-avahi-daemon(1060)---avahi-daemon(1122)
|-bluetoothd(1357)
|-colord(1585)
|-cron(1061)
|-cups-browsed(1158)
|-cupsd(1062)
|-dbus-daemon(1063)
|-dbus-daemon(1874)
|-dbus-launch(1873)
|-dconf-service(4336)
|-snapd(1101)
|-ssh(2212)
|-ssh(2427)
|-ssh(13369)
|-ssh(19621)
|-ssh-agent(2109)
|-switcheroo-cont(1107)
|-systemd(1214)-+-(sd-pam)(1215)
| |-dbus-daemon(1231)
| |-goa-daemon(1310)
| |-goa-identity-se(1327)
| |-gvfs-afc-volume(1343)
| |-gvfs-goa-volume(1304)
| |-gvfs-gphoto2-vo(1334)
| |-gvfs-mtp-volume(1338)
| |-gvfs-udisks2-vo(1278)
| |-gvfsd(1255)
| |-gvfsd-fuse(1270)
| |-pulseaudio(1226)
| `-tracker-miner-f(1228)
|-tmux: server(2403)-+-bash(2404)
| |-bash(2414)---miskatonic.sh(2422)---ssh(2423)
| |-bash(2447)---mosh-client(2480)
| `-bash(2495)---pstree(23527)
|-udisksd(1110)
|-unattended-upgr(1195)
|-upowerd(1358)
|-whoopsie(1683)
|-wmii(1878)
|-wmiirc(1876)-+-witray(1906)
| |-wmiir(2035)
| |-wmiirc(2009)---sleep(23524)
|-wpa_supplicant(1111)
`-xdg-permission-(1442)
Les utilisateurs et l'accès au système
Accès local
L'accès local à la machine se fait via votre couple login/mot de passe, soit directement en console, soit, si une interface graphique a été installée ainsi qu'un /gestionnaire de login/ (LightDM, etc), via une interface graphique.
Accès distant (SSH)
L'accès par SSH (Secure SHell, aka OpenBSD OpenSSH) se fait soit par login/mot de passe (A EVITER A TOUT PRIX!!!!!) soit en utilisant un couple de clefs asymétriques (une clef privée à conserver de façon sécurisée et de préférence individuelle, et une clef publique librement distribuable).
Sur la machine client, pour générer un couple de clefs:
# la clef par défaut s'appelle id_algodechiffrement
# ex: id_rsa, id_ed25519, etc. Attention, si vous avez déjà
# un couple de clefs id_rsa et id_rsa.pub à ne pas l'overwrite!
# ici, un couple de clefs RSA de 4096 bits de taille.
# Par défaut 2048 bits, considéré "suffisant" mais faible
$ ssh-keygen -t rsa -b 4096 -f ~/.ssh/maclef
$ ssh-copy-id -i ~/.ssh/maclef user@machine_distante
# avec une phrase de passe, c'est mieux ;)
# Ou:
$ scp ~/.ssh/maclef.pub user@machine_distante
# Puis sur le serveur:
$ cat maclef.pub >> ~/.ssh/authorized_keys
Il faudra ensuite configurer le serveur SSH pour ne pas autoriser l'authentification par login/mot de passe. On reviendra là dessus en détail dans la partie LAMP.
Typiquement, on décommentera la ligne:
# on édite le fichier /etc/sshd/sshd_config
PasswordAuthentification Yes
# et on remplace Yes par No:
PasswordAuthentification No
# Dans la foulée, si ce n'est pas déjà fait,
# On désactive l'accès superutilisateur distant:
PermitRootLogin No
# on sauvegarde et on quitte
# puis on relance le service sshd:
$ sudo systemctl restart sshd
Les fichiers sous UNIX et GNU/Linux: "Tout est fichier".
Répertoire de connexion ($HOME)
Tout d'abord, lorsqu'on se connecte à son compte utilisateur, on se retrouve dans son répertoire utilisateur, en général situé dans:
$ pwd
/home/mon_utilisateur
# par exemple dans mon cas:
$ pwd
/home/lidstah
NOTE: le répertoire de l'utilisateur root, le super-utilisateur, est situé dans /root
Votre répertoire personnel est aussi référencé par la /variable/ $HOME. Où que vous soyez dans l'arborescence, si vous tapez:
# cd signifie Change Directory.
/home/lidstah/documents/cours/ $ cd $HOME
# qui peut simplement s'abréger ~:
/home/lidstah/documents/cours/ $ cd ~
# ou plus simplement:
/home/lidstah/documents/cours/ $ cd
Vous serez immédiatement "transportés" dans votre répertoire utilisateur personnel.
Ce répertoire sert à stocker toutes vos données utilisateur personnelles:
- Ce que vous téléchargez
- Vos documents de travail
- Vos fichiers de configuration personnels
Tous ces fichiers ne sont, par défaut, modifiables que par vous même, et le super-utilisateur root.
Répertoires
Bien évidemment, on peut créer des répertoires et sous répertoires dans notre répertoire utilisateur. Globalement, les répertoires sous GNU/Linux ou UNIX sont similaires à ce que vous pouvez utiliser sous Windows®© ou macOS®© (qui reste un UNIX). Sous UNIX, GNU/Linux ou macOS, un répertoire est toujours exécutable.
Pour créer un nouveau répertoire, on utilise la commande mkdir: (la commande pwd signifie Print Working Directory, et elle affichera dans quel répertoire vous vous trouvez):
$ mkdir test
$ cd test
$ pwd
$ cd
$ pwd
Bien sûr, on peut vouloir créer directement un répertoire, et un sous-répertoire de ce répertoire, pour cela on utilisera l'option -p:
$ cd
$ mkdir -p test2/folder
$ cd test2/folder
$ pwd
On peut aussi vouloir créer plusieurs sous-répertoires d'un coup:
$ cd
$ mkdir -p test3/{a,b,c}
$ ls -l test3
total 12
drwxrwxr-x 2 lidstah lidstah 4096 oct. 20 19:26 a
drwxrwxr-x 2 lidstah lidstah 4096 oct. 20 19:26 b
drwxrwxr-x 2 lidstah lidstah 4096 oct. 20 19:26 c
# on supprime notre répertoire et ses sous-répertoires:
# ATTENTION avec cette commande: rm signifie ReMove ;)
$ rm -r test3
Chemins absolus et relatifs
On peut indiquer le chemin d'un fichier - par exemple notre répertoire test de tout à l'heure, de plusieurs façons différentes. Soit de façon absolue:
$ cd /home/lidstah/test
# qu'on peut abréger:
$ cd ~/test
soit de façon relative par rapport à notre position dans le système de fichiers. Si je suis dans mon répertoire test2:
$ cd test2
$ pwd
$ cd ../test
$ pwd
On peut donc considérer que le chemin absolu représente la position exacte du fichier ou du répertoire que l'on veut ouvrir, éditer, etc sur nos disques, là où le chemin relatif représente la position du répertoire ou du fichier que l'on veut atteindre par rapport à notre position actuelle.
Types de fichiers
Il y a plusieurs types de fichiers sous UNIX et GNU/Linux:
- fichiers réguliers (exécutables, texte, images, vidéos, etc)
- répertoires
- fichiers de liens symboliques
- sockets UNIX
- /named pipe/ (FIFO)
- fichiers de périphériques de type blocs (disques et périphériques de stockages)
- fichiers de périphériques de type caractère (clavier, souris, terminal, cartes graphiques (oui oui)). Avec les fichiers de type bloc, ils forment le groupe des fichiers de périphériques que l'on trouve en général dans /dev
Tout fichier possède comme information son nom, et son numéro d'/inode/.
Nous allons regarder la commande file qui nous permet de connaître le type d'un fichier:
$ file .bashrc
.bashrc: ASCII text
$ file .config
.config: directory
$ file /dev/sda
/dev/sda: block special (8/0)
On peut aussi facilement déterminer le type d'un fichier en regardant par exemple le résultat de la commande ls -l:
$ ls -al
drwx------ 29 lidstah lidstah 12288 oct. 20 21:25 Downloads
-rw-rw-r-- 1 lidstah lidstah 10136 févr. 14 2020 .emacs
Le premier caractère nous indique le type du fichier. Ici, Downloads est un répertoire (Directory, indiqué par d) et .emacs un fichier (caché) régulier (indiqué par -).
Pour résumer:
| Caractère | Type de fichier |
|---|---|
| d | répertoire |
| - | fichier régulier |
| l | lien symbolique |
| s | socket UNIX |
| p | named pipe (FIFO) |
| c | périphérique caractère |
| b | périphérique bloc |
Le super-utilisateur (born to be root)
root est le super-utilisateur sous GNU/Linux et UNIX. Il dispose de tous les droits, sur tous les fichiers, tous les groupes, tous les utilisateurs. Dès lors il est fortement déconseillé de se /logger/ constamment en root: la moindre erreur peut avoir des effets catastrophiques. Par exemple, rien n'empêche root d'écrire directement dans un fichier de périphérique de type bloc ou caractère, pouvant potentiellement /briquer/ une machine (rien ne vous empêche en tant que root d'écrire n'importe quoi dans l'UEFI d'une machine... la transformant potentiellement en coûteux cale-porte).
Plus sérieusement, lorsqu'en tant qu'utilisateur on désire apporter des modifications au système, par exemple pour modifier un fichier de configuration, il est préférable d'utiliser une /élévation de privilèges/ temporaire via la commande sudo (bien sûr votre utilisateur doit faire partie du groupe correspondant pour avoir ces droits, ou être renseigné manuellement dans le fichier /sudoers/). On peut facilement différencier dans un terminal si on est loggé en tant que root ou en tant qu'utilisateur avec le dernier caractère du /prompt/:
# prompt d'un utilisateur standard (si le prompt $PS1 n'a pas été modifié):
$
# prompt root, un dièse:
#
De même, il est conseillé de ne jamais lancer de service ou logiciel en tant que root. Par exemple, un serveur web sera, suivant les distributions, lancé en tant qu'utilisateur /www-data/, ou /httpd/, MariaDB ou MySQL en tant qu'utilisateur /mysql/, postgreSQL en tant qu'utilisateur /postgres/, etc. Le but étant ici de limiter les dégâts si un attaquant gagne l'accès au système via un de ces logiciels.
Cependant, il peut être nécessaire de se logger temporairement en tant qu'utilisateur root, pour ce faire:
# taper VOTRE mot de passe pour vous logger en root
# avec votre shell de login
$ sudo -i
# ou avec le shell spécifié par la variable d'environnement $SHELL
$ sudo -s
# ou directement en root, avec le mdp root
$ su -
sudo signifie /Summon User DO/
su signifie simplement /Summon User/
Les commandes de base
Présentation
Si vous êtes amenés à travailler sur des serveurs GNU/Linux ou UNIX, vous interagirez avec ces machines principalement en mode texte. Dès lors il est important de bien comprendre les concepts derrière l'interface en ligne de commande (/CLI/) sous ces OS. Toutes les commandes répondent à ce synopsis:
commande [options] arguments
# ex:
$ ls -al /etc
L'utilitaire /man/ vous permet de consulter les pages de manuel d'une commande, par exemple:
# pour consulter la page de manuel de man:
$ man man
Je vous encourage fortement, lorsque vous voyez une commande sur Internet dont vous ne savez pas ce qu'elle fait exactement, à lire la /manpage/ correspondante afin de comprendre ce que la commande, les options et les arguments font avant de copier/coller n'importe quoi depuis Stack Overflow
Commandes de manipulation des fichiers
- LiSter les fichiers d'un répertoire:
$ ls
$ ls /etc
# afficher une liste et les métadonnées des fichiers
$ ls -l /etc
# afficher les fichiers cachés
$ ls -al ~
# du plus récent au plus ancien
$ ls -lt
# du plus ancien au plus récent
$ ls -lrt
- CoPier un fichier:
$ cp fichier repertoire/de/destination
# copier un fichier dans le répertoire courant
$ cp /etc/profile .
# copier tous les fichiers d'un répertoire dans un autre:
$ cp repertoire1/* repertoire2/
# copier récursivement (y compris les sous-répertoires)
$ cp -r repertoire1/* repertoire2/
# man cp ;)
- Déplacer (MoVe) un fichier:
# déplacer/renommer un fichier:
$ mv fichier fichier2
# déplacer les fichiers d'un répertoire dans un autre
# (y compris les sous-répertoires)
$ mv repertoire/* repertoire2/
# man mv 8)
- Supprimer un fichier:
$ rm fichier
# supprimer un répertoire
$ rm -r repertoire
# supprimer plusieurs répertoires
$ rm -r repertoire repertoire2 repertoire3...
# forcer la suppression /!\
$ rm -rf repertoire
# demander une confirmation (faites un alias, cf plus bas)
$ rm -i fichier
$ rm -ir repertoire
# man rm ;)
- Afficher le contenu d'un fichier, conCATéner des fichiers
# afficher le contenu d'un fichier
$ cat fichier
# concaténer le contenu de deux fichiers
# et sauvegarder le résultat dans un 3è
$ cat fichier1 fichier2 > fichier3
- Éditer un fichier: nano, vim, emacs, ed...
Pour commencer, on utilisera nano afin que vous ne soyez pas trop perdus
$ nano fichier
# ou avec élévation de privilèges:
$ sudo nano /etc/hosts
Les commandes séquentielles, regroupement et imbrication de commandes
On peut bien sûr enchaîner les commandes sur une même ligne:
$ ls; who; id
Ou enchaîner une commande si la première a réussi:
$ ls && who
À l'inverse, enchaîner une commande si la première a échoué:
$ ls || who
On peut aussi envoyer le résultat d'une commande dans l'entrée standard d'une autre commande, en utilisant l'opérateur /pipe/ (|) - vous vous en servirez souvent, trèèèèès souvent :
$ ls -al | grep conf
On peut aussi regrouper des commandes en les mettant entre parenthèses:
$ (ls;who) > fichier
Et enfin, on peut aussi imbriquer des commandes en utilisant $() (plus récent) ou `` (/backticks/, historique):
$ echo "Nous sommes à "$(date +%s)" secondes depuis le 1/01/1970"
$ echo "Nous sommes à "`date +%s`" secondes depuis le 1/01/1970"
Avec la syntaxe $(), on peut imbriquer des commandes dans des commandes, i.e:
$ VAR=$($(commande);$(autre commande))
Les alias
On peut aussi créer un alias pour une commande utilisée souvent:
$ alias gp=git pull
Et le conserver en l'ajoutant à son fichier de configuration bash: .bashrc
Redirections des entrées et sorties
Sous UNIX et GNU/Linux (et sous les autres OS du même style comme Plan9), on peut rediriger la sortie d'une commande vers un fichier. Comme tout est fichier, on peut tout à fait faire (en partant du principe que la configuration sonore de l'OS est correcte):
$ cat music.wav > /dev/audio
Ici, /cat/ envoie sa sortie, c'est à dire le contenu de music.wav au fichier de périphérique audio.
On peut aussi concaténer des fichiers, comme montré plus haut.
On peut bien sûr rediriger la /sortie standard/ (stdout) de toute commande vers un fichier, ainsi que sa sortie d'erreur (stderr), ou rediriger l'entrée standard (stdin) d'une commande depuis un fichier. Ici, on redirige le stdout de la commande ls vers un fichier :
$ ls -al > liste
$ cat liste
Maintenant, que se passe-t-il si je fais:
$ echo "coucou" > bonjour
$ cat bonjour
$ echo "comment va?" > bonjour
$ cat bonjour
La sortie de la seconde commande, redirigée dans le fichier "bonjour", a écrasé la sortie de la première commande. Il a donc réécrit le fichier. Si on veut ajouter (/append/) la sortie d'une commande à un fichier déjà existant, on utilisera l'opérateur >>:
$ echo "coucou" > bonjour
$ cat bonjour
$ echo "comment va?" >> bonjour
$ cat bonjour
De même, on peut vouloir rediriger la sortie d'erreur (stderr) d'une commande vers un fichier, par exemple (on ne peut pas créer de répertoire dont le nom est vide, la commande va donc générer une erreur):
$ mkdir '' 2> erreur
$ cat erreur
# bien sur on peut aussi "append" :)
$ find '' 2>>erreur
$ cat erreur
On peut bien évidemment rediriger le contenu d'un fichier sur l'entrée standard d'une commande:
$ head < fichier
# on peut aussi simplement faire:
$ head fichier
Plus rigolo, convertir un fichier en ALL CAPS PARCEQUE MOI AUSSI JE PEUX ECRIRE COMME TRUMP:
$ echo "gnu/linux rules!" > fichier
$ tr a-z A-Z < fichier
GNU/LINUX RULES!
Bien évidemment, je peux aussi vouloir sauvegarder mon oeuvre dans un nouveau fichier:
$ tr a-z A-Z < fichier > fichier2
$ cat fichier2
GNU/LINUX RULES!
On peut - on l'a vu précédemment - rediriger la sortie d'une commande vers l'entrée standard d'une commande, via l'opérateur /pipe/ |. On peut faire des choses assez sympa:
$ tail -100000 /var/log/haproxy.log | awk '{ print $6 }' | sed 's/:.*$//g' \
| sort -n | uniq -c | sort -nr | head -50 > potential_abuse
Les filtres ("Globs")
Bash (le shell par défaut sur la plupart des distributions GNU/Linux) ne supporte pas les expressions régulières POSIX, contrairement à beaucoup de langages de programmation et d'utilitaires du système (grep, sed, awk, vim, etc) ou logiciels (nginx, apache, haproxy, etc). À la place il utilise un mécanisme qu'on appelle /globbing/ afin de lui permettre de proposer des fonctionnalités équivalentes.
Tout d'abord, tout comme pour les regexes, un petit tableau récapitulatif:
| caractère | signification | exemple |
|---|---|---|
| ? | /matche/ n'importe quel caractère tout seul | ls ??.c |
| * | /matche/ zéro ou plusieurs caractère(s) | ls b*.sh |
| A-Z | /matche/ le caractère s'il est dans l'intervalle | ls a-z??.sh |
| ^ | début de ligne | grep '^[a-d]' fichier |
| ! | idem que ^ mais dans le range | grep '[!a-d]' fichier |
| $ | fin de ligne | |
{pat1,pat2,...} |
/matche/ les noms de fichiers correspondant aux patterns | rm \{*.doc,???.xlsx\} |
| |
applique une ou plusieurs conditions au glob pattern | exemple plus bas |
- Matcher plusieurs patterns:
$ ls a*+(.c|.sh|.ksh)
- exemple dans un menu bash via /case/
#!/bin/bash
echo "Quelle opération voulez vous faire?"
read reponse
case $reponse in
1 | R ) echo "Reboot";;
2 | P ) echo "Poweroff";;
*) echo "nope nope nope";;
esac
Autres commandes
Parmi les commandes les plus utiles qu'on peut trouver sous GNU/Linux:
- toutes les commandes d'/iproute2/:
# Afficher les adresses IPs de toutes les interfaces réseau
$ ip address show
# assigner une IP à une interface:
$ sudo ip addr add 10.10.10.1/24 dev interfaceréseau
#supprimer une IP
$ sudo ip addr del 10.10.10.1/24 dev interfaceréseau
#afficher la table de routage
$ ip route show
#ajouter une route
$ sudo ip route add 10.10.10.0/24 via 192.168.42.1 dev eth0
#supprimer une route
$ sudo ip route del 10.10.10.0/24 via 192.168.42.1 dev eth0
#couper une interface
$ sudo ip link set dev eth0 down
#inversement:
$ sudo ip link set dev eth0 up
- les commandes de manipulation de texte - en effet, UNIX et GNU/Linux sont faits pour manipuler des flux de texte:
grep permet de sélectionner toutes les lignes contenant un pattern:
$ ip addr show | grep inet
#sélectionne toutes les lignes commençant par if
$ grep ^if /etc/bash.bashrc
# sélectionner toutes les lignes commençant par if
# dans un répertoire, récursif
$ grep -R ^if /etc/
Je vous invite fortement à lire la /manpage/ de grep ainsi que les tutos en ligne que vous pourrez trouver. Ainsi que les manpages des utilitaires suivants...
/head/ et /tail/ permettent respectivement d'afficher la première et la dernière ligne d'un fichier, ou les /n/ premières ou /n/ dernières lignes d'un fichier:
# les 50 dernières lignes de syslog
$ tail -50 /var/log/syslog
# les 50 premières lignes de syslog
$ head -50 /var/log/syslog
# les lignes 80 à 100 de syslog:
$ head -100 /var/log/syslog | tail -20
tail peut aussi être utilisé pour suivre (/follow/) un fichier au fur et à mesure qu'il se remplit:
$ tail -f /var/log/syslog
cut permet de sélectionner un élément ou plusieurs d'une ligne en fonction d'un séparateur. Par exemple un fichier csv où chaque champ de chaque ligne sont séparés par ";", pour sélectionner le 4è élément:
$ cut -d";" -f4 fichier.csv
# pour sélectionner les champs 1 et 2:
$ cut -d";" -f1,2 fichier.csv
# pour sélectionner les champs à partir du 4ème
$ cut -d";" -f4- fichier.csv
Dans certains cas, si les champs sont séparés "aléatoirement" par des espaces et des tabulations par exemple (fichiers de log, etc), awk permet de facilement contourner ce problème:
# pour sélectionner les champs 1 et 3:
$ awk '{ print $1" "$3 }' fichier.csv
sort permet de réorganiser le contenu d'un fichier suivant des règles définies (par ordre alphabétique, numérique, alphabétique ou numérique inverse, random (mélanger), par numéro de version, etc.
uniq permet de compter les lignes identiques, ou de les omettre, ou de n'afficher que les lignes uniques d'un fichier (ou de son entrée standard, c'est la même chose au final).
Ces deux utilitaires combinés permettent de faire beaucoup de choses sympa:
$ kubectl get svc -A | awk '{ print $5 }' | egrep -v "(EXTER|none)"
192.168.1.230
192.168.1.137
192.168.1.131
192.168.1.226
192.168.1.132
192.168.42.236
192.168.1.227
192.168.42.235
192.168.1.138
192.168.1.223
192.168.1.228
192.168.1.130
192.168.1.224
192.168.1.133
192.168.1.136
192.168.1.135
192.168.1.221
192.168.1.222
Pas très lisible?
$ kubectl get svc -A | awk '{ print $5 }' | egrep -v "(EXTER|none)" | sort -n
192.168.1.130
192.168.1.131
192.168.1.132
192.168.1.133
192.168.1.135
192.168.1.136
192.168.1.137
192.168.1.138
192.168.1.221
192.168.1.222
192.168.1.223
192.168.1.224
192.168.1.226
192.168.1.227
192.168.1.228
192.168.1.230
192.168.42.235
192.168.42.236
Mieux, non?
wc /Word Count/ permet de compter les caractères, mots et lignes d'un fichier:
$ wc .bashrc
124 540 3959 .bashrc
#le fichier .bashrc contient donc 124 lignes, 540 mots et 3959 caractères.
$ wc -l .bashrc
124 .bashrc
$ wc -w .bashrc
540 .bashrc
$ wc -c .bashrc
3959 .bashrc
$ grep CRON /var/log/syslog | wc -l
144
l'utilitaire column permet d'organiser en colonnes "humainement lisibles" son entrée standard (ou un fichier).
Enfin, l'utilitaire sed /Stream EDitor/ permet de modifier, remplacer, supprimer des lignes ou des /patterns/ dans un fichier, ou dans plusieurs fichiers récursivement. Il est un peu trop complexe pour ce cours, ceci dit
Manipulation des processus
kill
La commande /kill/ permet d'envoyer un /signal/ à un processus - et pas nécessairement pour le stopper (le "tuer").
Sa syntaxe est du type:
$ kill -[signal] PID
Et les différents signaux que l'on peut lui envoyer sont:
| Numéro | Nom | Description |
|---|---|---|
| 1 | SIGHUP | Fin de session |
| 2 | SIGINT | Interruption |
| 3 | SIGQUIT | Instruction QUIT |
| 4 | SIGILL | Illegal Instruction |
| 5 | SIGTRAP | Trap |
| 6 | SIGABRT | Annulation |
| 7 | SIGBUS | Bus error |
| 8 | SIGFPE | Exception FPU |
| 9 | SIGKILL | Termine le processus salement |
| 10 | SIGUSR1 | Signal Utilisateur (si prévu) |
| 11 | SIGSEGV | Segmentation fault |
| 12 | SIGUSR2 | Signal Utilisateur 2 |
| 13 | SIGPIPE | PIPE Error |
| 14 | SIGALRM | Alarme Horloge |
| 15 | SIGTERM | Termine proprement le processus |
| 16 | SIGSTKFLT | Erreur de pile |
| 17 | SIGCHLD | Modification du statut d'un processus enfant |
| 18 | SIGCONT | Reprise du processus |
| 19 | SIGSTOP | Demande de suspension forcée |
| 20 | SIGTSTP | Stop depuis le clavier |
| 21 | SIGTTIN | lecture terminal en arrière-plan |
| 22 | SIGTTOU | entrée terminal en arrière-plan |
| 23 | SIGURG | évènement urgent sur socket |
| 24 | SIGXCPU | Temps CPU maximum écoulé |
| 25 | SIGXFSZ | Taille maximale de fichier atteinte |
| 26 | SIGVTALRM | Alarme |
| 27 | SIGPROF | Profilage de l'horloge alarme |
| 28 | SIGWINCH | changement de la taille de fenêtre |
| 29 | SIGPOLL | occurence d'un évènement attendu |
| 30 | SIGIO | I/O possible |
| 31 | SIGSYS | Erreur d'appel système |
| 32 | SIGUNUSED |
Alors, en général, lorsqu'on veut "tuer" un processus, on va d'abord essayer de le tuer proprement, en lui envoyant le signal SIGTERM (pour qu'il puisse "tuer" tous ses "enfants" avant de se tuer (dit comme ça c'est un peu glauque ). Si jamais SIGTERM ne fonctionne pas, on utilisera alors SIGKILL:
$ kill -15 1234
$ kill -9 1234
Bien sûr, on peut utiliser la commande /pgrep/ en l'imbriquant pour tuer un processus en utilisant son nom plutôt que son numéro de PID:
$ kill -15 $(pgrep vim)
top, htop
On peut aussi visualiser en temps réel les processus en cours d'exécution, la RAM et le temps CPU qu'ils consomment, etc, via la commande /top/ (intégrée) ou la commande /htop/ (à installer):
$ top
# q pour quitter
Pour installer htop:
$ sudo apt install htop
$ htop
#q pour quitter
ps
La commande ps nous permet de lister les processus en cours d'exécution par notre utilisateur, ou par tous les utilisateurs du système selon les options que l'on va lui fournir.
$ ps
$ ps aux
# grep est notre ami:
$ ps aux|grep systemd
Bien évidemment je vous invite fortement à lire la /manpage/ de ps
pstree
pstree nous indique les relations entre les processus (qui est parent, qui est enfant, etc) sous forme d'arbre. Vous en avez un exemple en début de cours
nice et renice
nice et renice nous permettent de gérer la /priorité/ d'un processus par rapport aux autres processus. C'est à dire le temps CPU qui lui sera alloué.
Gestion des paquets: Mises à jour, installation et suppression de logiciels avec apt
Contrairement à certains systèmes propriétaires que je ne citerai pas, sous UNIX et GNU/Linux, on évite généralement d'installer des logiciels en provenance de n'importe où. On les installe via un gestionnaire de paquets, qui va aller récupérer nos logiciels ainsi que leurs /dépendances/ (bibliothèques de fonctions ou autres logiciels nécessaires au bon fonctionnement du logiciel que l'on installe) depuis les dépôts de notre distribution, qui stockent les paquets (logiciels et bibliothèques de fonction) de la distribution, et qui les signe cryptographiquement afin d'être sûr que nous téléchargeons les bons paquets depuis les bons serveurs.
Typiquement, les gens sur Internet qui se plaignent que c'est "difficile d'installer les drivers Nvidia" tentent de les installer à la sauce Windows: ils vont aller télécharger les drivers sur le site de Nvidia et essayer de les installer via le script (moisi) fourni. Ce qui est une erreur. Sous Debian ou Ubuntu, on installera les drivers propriétaires Nvidia en activant les dépôts non libres (non-free).
# mettre à jour la base de données des paquets:
$ sudo apt update
# sous centos:
$ sudo yum update
# mettre à jour le système et les paquets installés:
$ sudo apt upgrade
# mettre à jour le système en supprimant les paquets non-utiles:
$ sudo apt dist-upgrade
Typiquement, dans un environnement critique, qui doit rester stable (au hasard: serveur de bases de données) on préfèrera utiliser upgrade, sinon on utilisera (desktop, environnement peu critique (preprod, etc)): dist-upgrade
Bien sûr, on veut aussi parfois supprimer des paquets, dont on ne se sert plus, ou installer de nouveaux paquets. Par exemple, nous allons installer l'éditeur de texte joe, et le supprimer ensuite (je n'ai rien contre /joe/ qui est un très bon éditeur de texte, méconnu):
$ sudo apt install joe
...
$ sudo apt remove joe
On peut aussi vouloir chercher des paquets dont le nom ou la description correspondent à un certain pattern, par exemple PHP:
# pas besoin d'élévation de privilège:
$ apt search php
Le(s) système(s) de fichiers
Introduction
Contrairement à certains systèmes d'exploitation propriétaires, les systèmes d'exploitation GNU/Linux permettent d'utiliser un grand nombre de systèmes de fichiers différents. Par exemple:
- ext2, ext3, ext4: systèmes de fichiers Linux "standard"
- btrfs: système de fichiers offrant des fonctionnalités avancées comme la déduplication, les /snapshots/, etc
- ZFS: système de fichier développé à l'origine par Sun Microsystems, disposant de nombreuses fonctionnalités extrêmement avancées (mais nécessitant des ressources non-négligeables tant en RAM qu'en I/Os et CPU)
- XFS: système de fichiers développé à l'époque par Silicon Graphics. Très adapté aux bases de données.
- FAT12,16,32 système de fichier DOS (Microsoft)
- NTFS (lecture seule par défaut, read/write avec les utilitaires FUSE)
- FFS et OFS: systèmes de fichiers utilisés par AmigaOS
- HFS, HFS+: lecture seule par défaut, FS utilisés par macOS
Arborescence des répertoires
lidstah@deb-RAID0:~$ tree -L 1 /
/
├── bin -> usr/bin
├── boot
├── dev
├── etc
├── home
├── initrd.img -> boot/initrd.img-4.19.0-12-amd64
├── initrd.img.old -> boot/initrd.img-4.19.0-10-amd64
├── lib -> usr/lib
├── lib32 -> usr/lib32
├── lib64 -> usr/lib64
├── libx32 -> usr/libx32
├── lost+found
├── media
├── mnt
├── opt
├── proc
├── root
├── run
├── sbin -> usr/sbin
├── srv
├── sys
├── tmp
├── usr
├── var
├── vmlinuz -> boot/vmlinuz-4.19.0-12-amd64
└── vmlinuz.old -> boot/vmlinuz-4.19.0-10-amd64
| Répertoire | Utilisation |
|---|---|
| bin | Utilitaires système |
| boot | bootloader et kernels |
| dev | périphériques |
| etc | fichiers de configuration |
| home | répertoires utilisateurs |
| lib | bibliothèques de fonctions |
| media | points de montage pour médias amovibles |
| mnt | points de montage |
| opt | logicels optionnels (peu utilisé) |
| proc | processus |
| root | répertoire super-utilisateur |
| run | pids, sockets |
| sbin | Exécutables pour administrateurs |
| srv | Serveurs (ftp, etc. Historique) |
| sys | FS Kernel (manipulation des paramètres du kernel) |
| tmp | fichiers temporaires |
| usr | exécutables, bibliothèques de fonctions installés par l'utilisateur |
| var | logs, données de BDD, mailboxes, etc |
les distributions GNU/Linux et UNIX en général suivent (à peu près) le /Filesystem Hierarchy Standard/ (FHS):
https://fr.wikipedia.org/wiki/Filesystem_Hierarchy_Standard
À la différence de nombreux autres systèmes d'exploitation, les partitions et disques ne sont pas indiqués par un nom spécifique (C:, D:, MacintoshHD, etc) mais leurs fichiers de périphérique sont montés sur des répertoires du système de fichiers.
Par exemple, la partition contenant la racine du système d'exploitation est montée sur /.
La partition contenant le kernel et le bootloader est elle montée sur le répertoire /boot.
Assez souvent, une troisième partition est montée sur le répertoire /home.
Plus précisément, on peut monter n'importe quelle partition de n'importe quel disque où bon nous semble (attention, le répertoire de montage doit être vide). On pourrait par exemple vouloir monter un ensemble de disques configurés en RAID-5 sur /srv afin de stocker nos données FTP ou autres sur ce disque.
On va voir comment faire en ajoutant un disque à notre VM Linux:
mount: "monter" des périphériques de stockage et umount ("démonter")
partitionner et formater un nouveau disque
Tout d'abord, on va vouloir identifier le(s) disque(s) déjà montés sur notre VM:
$ mount | grep "/dev"
udev on /dev type devtmpfs (rw,nosuid,relatime,size=747660k,nr_inodes=186915,mode=755)
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000)
/dev/sda1 on / type ext4 (rw,relatime,errors=remount-ro)
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
mqueue on /dev/mqueue type mqueue (rw,relatime)
hugetlbfs on /dev/hugepages type hugetlbfs (rw,relatime,pagesize=2M)
/dev/sdb1 on /home/raid0 type ext4 (rw,noatime)
$ df -h
Sys. de fichiers Taille Utilisé Dispo Uti% Monté sur
udev 731M 0 731M 0% /dev
tmpfs 149M 460K 149M 1% /run
/dev/sda1 39G 2,8G 34G 8% /
tmpfs 745M 0 745M 0% /dev/shm
tmpfs 5,0M 0 5,0M 0% /run/lock
tmpfs 745M 0 745M 0% /sys/fs/cgroup
/dev/sdb1 1,8T 160G 1,5T 10% /home/raid0
tmpfs 149M 0 149M 0% /run/user/1000
Normalement, vous ne devriez avoir que des partitions du périphérique sda (Sata Disk A) montées sur vos machines (minus les points de montage mémoire comme udev, tmpfs, etc) et typiquement uniquement la partition sda1. On va donc regarder la liste des périphériques de stockage connectés à notre machine:
$ sudo fdisk -l
Disque /dev/sdb : 1,8 TiB, 1904817995776 octets, 3720347648 secteurs
Modèle de disque : QEMU HARDDISK
Unités : secteur de 1 × 512 = 512 octets
Taille de secteur (logique / physique) : 512 octets / 512 octets
taille d'E/S (minimale / optimale) : 512 octets / 512 octets
Type d'étiquette de disque : gpt
Identifiant de disque : C285FA67-D48E-5D49-A3A2-8D7AB8F8DBE0
Périphérique Début Fin Secteurs Taille Type
/dev/sdb1 2048 3720347581 3720345534 1,7T Système de fichiers Linux
Disque /dev/sda : 40 GiB, 42949672960 octets, 83886080 secteurs
Modèle de disque : QEMU HARDDISK
Unités : secteur de 1 × 512 = 512 octets
Taille de secteur (logique / physique) : 512 octets / 512 octets
taille d'E/S (minimale / optimale) : 512 octets / 512 octets
Type d'étiquette de disque : dos
Identifiant de disque : 0x9d80190a
Périphérique Amorçage Début Fin Secteurs Taille Id Type
/dev/sda1 * 2048 81788927 81786880 39G 83 Linux
/dev/sda2 81790974 83884031 2093058 1022M 5 Étendue
/dev/sda5 81790976 83884031 2093056 1022M 82 partition d'échange Linux / Solaris
Disque /dev/sdc : 4 GiB, 4294967296 octets, 8388608 secteurs
Modèle de disque : QEMU HARDDISK
Unités : secteur de 1 × 512 = 512 octets
Taille de secteur (logique / physique) : 512 octets / 512 octets
taille d'E/S (minimale / optimale) : 512 octets / 512 octets
$ sudo dmesg | tail -10
[503471.949683] Btrfs loaded, crc32c=crc32c-generic
[503471.970591] fuse init (API version 7.27)
[3957953.844366] scsi 2:0:0:2: Direct-Access QEMU QEMU HARDDISK 2.5+ PQ: 0 ANSI: 5
[3957953.846326] sd 2:0:0:2: Power-on or device reset occurred
[3957953.849414] sd 2:0:0:2: [sdc] 8388608 512-byte logical blocks: (4.29 GB/4.00 GiB)
[3957953.849497] sd 2:0:0:2: [sdc] Write Protect is off
[3957953.849500] sd 2:0:0:2: [sdc] Mode Sense: 63 00 00 08
[3957953.849624] sd 2:0:0:2: [sdc] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[3957953.852100] sd 2:0:0:2: Attached scsi generic sg3 type 0
[3957953.854567] sd 2:0:0:2: [sdc] Attached SCSI disk
Ici, on voit que mon périphérique sdc n'est pas partitionné, et qu'il vient juste d'être "branché" à chaud.
Je vais donc le partitionner. Pour cela, on va utiliser l'utilitaire /cfdisk/ - on pourrait aussi utiliser fdisk, mais cfdisk est plus /user-friendly/.
$ sudo cfdisk /dev/sdc
Puis on va formater notre partition en EXT4:
$ sudo mkfs.ext4 /dev/sdc1
montage et démontage manuel
Et on va pouvoir monter cette partition, par exemple sur /mnt:
$ sudo mount /dev/sdc1 /mnt
$ df -h
Sys. de fichiers Taille Utilisé Dispo Uti% Monté sur
udev 731M 0 731M 0% /dev
tmpfs 149M 476K 149M 1% /run
/dev/sda1 39G 2,8G 34G 8% /
tmpfs 745M 0 745M 0% /dev/shm
tmpfs 5,0M 0 5,0M 0% /run/lock
tmpfs 745M 0 745M 0% /sys/fs/cgroup
/dev/sdb1 1,8T 160G 1,5T 10% /home/raid0
tmpfs 149M 0 149M 0% /run/user/1000
/dev/sdc1 3,9G 16M 3,7G 1% /mnt
On va maintenant la démonter proprement:
$ sudo umount /mnt
$ df -h
#/mnt ne devrait plus être présent
fstab: persistence du montage des périphériques au boot
On va dire que notre nouvelle partition va nous servir à stocker les données de notre base de données MariaDB/MySQL. Par défaut sous Debian, les données de MariaDB ou MySQL sont stockées dans le répertoire:
/var/lib/mysql
On va déjà vérifier que ce répertoire n'existe pas, et le créer le cas échéant:
$ ls -al /var/lib|grep mysql
#ne devrait rien renvoyer
$ sudo mkdir /var/lib/mysql
Maintenant, ça peut être utile que la partition que nous avons créée soit montée au boot sur ce répertoire, histoire que notre base de données ne se plante pas au démarrage . Pour cela, on va modifier le fichier fstab qui se trouve dans le répertoire /etc:
$ sudo nano /etc/fstab
Surtout, on ne supprime pas les autres entrées de ce fichier. Dans votre cas, cette nouvelle partition doit être sdb1, dans mon cas, c'est sdc1:
# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point> <type> <options> <dump> <pass>
# / was on /dev/sda1 during installation
UUID=c78dabc3-85a3-4697-8d60-52d8de57f591 / ext4 errors=remount-ro 0 1
# swap was on /dev/sda5 during installation
UUID=271218ac-fa47-4067-b0ae-5c315d1ea253 none swap sw 0 0
/dev/sr0 /media/cdrom0 udf,iso9660 user,noauto 0 0
/dev/sdb1 /home/raid0 ext4 async,noatime,acl 0 0
# J'ajoute ma partition sdc1:
/dev/sdc1 /var/lib/mysql ext4 defaults 0 0
Une fois sauvegardé, on peut soit rebooter pour que les modifications soient prises en comptes, soit simplement exécuter:
$ sudo mount -a
$ df -h
Pour parcourir le contenu de fstab à nouveau et monter tout périphérique n'étant pas déjà monté.
Les droits d'accès
Notion d'utilisateur
Tout comme sous Windows, macOS, ou tout autre UNIX, GNU/Linux dispose de la notion d'utilisateur. Un utilisateur peut être un humain utilisateur de la machine, ou un utilisateur créé pour un service (par exemple, l'utilisateur www-data pour les serveurs web apache2, nginx, etc, ou l'utilisateur mysql pour MySQL/MariaDB.). Un utilisateur dispose de droits définis lors de sa création, que l'on peut ensuite modifier si besoin.
Les informations concernant un utilisateur sont accessibles de plusieurs façons:
- La commande id
- Le contenu des fichiers passwd et shadow situés dans le répertoire /etc:
$ id
uid=1000(lidstah) gid=1000(lidstah) groupes=1000(lidstah),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),109(netdev)
$ grep lidstah /etc/passwd
lidstah:x:1000:1000:lidstah,,,:/home/lidstah:/bin/bash
$ grep lidstah /etc/shadow
lidstah:hash_mdp:18111:0:99999:7:::
Regardons plus en détail la structure d'un utilisateur dans le fichier passwd:
| user login | x | user id | group id | username | répertoire $HOME | shell de login |
|---|---|---|---|---|---|---|
| lidstah | x | 1000 | 1000 | lidstah,,, | /home/lidstah | /bin/bash |
Et du fichier shadow:
| username | hash mdp | dernier changement de mdp (en jours depuis le 1/1/1970) | nb jours entre changement de mdp | Warning | Inactif | expire |
|---|---|---|---|---|---|---|
| lidstah | hash_mdp | 18111 | 0 | 99999 |
Notion de groupe
Afin de gérer au mieux les droits de nos utilisateurs, sans avoir à les assigner sur une base individuelle, on utilise des groupes d'utilisateurs, qui leur permette d'accéder à des fichiers ou ressources auxquels leur utilisateur seul n'a pas forcément accès. Lorsqu'on crée un utilisateur, on crée aussi sous Debian un groupe portant le nom de cet utilisateur. Sous d'autres UNIX ou distributions GNU/Linux, un nouvel utilisateur sera peut-être membre du groupe /users/. Un utilisateur peut bien sûr être membre de plusieurs groupes!
Par exemple, un utilisateur membre du groupe /sudo/ possède donc les droits nécessaires pour utiliser la commande sudo.
Catégories d'utilisateurs
Pour simplifier, on peut résumer les catégories d'utilisateurs sous UNIX et GNU/Linux en deux grands groupes:
- Les utilisateurs Système, qui vont être utilisés par des programmes (applications), par exemple Apache2 ou PostgreSQL
- Les utilisateurs Normaux, qui sont prévus pour être utilisés par des humains (i.e, vous et moi)
Notion de propriété
Sous UNIX et GNU/Linux, tout - ou presque - est fichier. Ces fichiers (répertoires, périphériques, etc) appartiennent à un utilisateur et à un groupe précis.
Notion de permissions
Chaque fichier se voit assigné une /triade/ de droits: Les droits pour l'utilisateur auquel il appartient, les droits pour le groupe auquel il appartient, et le droit pour les Autres (c'est à dire n'importe qui d'autre).
lidstah@deb-RAID0:~$ ls -l
total 133592
-rw-r--r-- 1 lidstah lidstah 3392 oct. 1 12:00 iptables.rules
-rw-r--r-- 1 lidstah lidstah 0 sept. 9 19:27 masque
drwxr-xr-x 2 lidstah lidstah 4096 sept. 16 18:40 nc
drwxr-xr-x 2 lidstah lidstah 4096 sept. 12 11:28 regex
-rw-r--r-- 1 lidstah lidstah 136777573 oct. 20 2017 solr-5.5.5.tgz
drwxr-xr-x 2 lidstah lidstah 4096 nov. 24 2019 tor
Par exemple pour le fichier solr-5.5.5.tgz du listing ci-dessus, on peut voir:
| type | Utilisateur | Groupe | Autres | Utilisateur propriétaire | Groupe propriétaire |
|---|---|---|---|---|---|
| - | rw- | r-- | r-- | lidstah | lidstah |
Il s'agit d'un fichier normal, lisible, modifiable, mais pas exécutable pour l'utilisateur auquel il appartient (lidstah), et en lecture seule pour son groupe et les Autres.
Dès lors, pour modifier les droits d'un fichier, il est important de connaître:
- L'utilisateur et le groupe auquel ce fichier appartient
- Les permissions assignées à ce fichier.
NOTE: un répertoire doit toujours être exécutable!
Modification des permissions d'un fichier
- On utilisera chmod, pour modifier les permissions accordées aux groupes de permissions, exemples:
#Changer, pour l'utilisateur courant, les droits du
#fichier en read, write, execute
$ chmod u+rwx fichier
#Changer, pour l'utilisateur courant, les droits du
#fichier en rwx, et enlever tous les droits au
#groupe et aux Autres, deux méthodes:
$ chmod u+rwx,g-rwx,o-rwx fichier
#Ou plus simplement:
$ chmod 700 fichier
#On peut aussi directement affecter les droits avec a
$ chmod a+rw fichier
En effet, chmod permet d'utiliser une notation "humaine" et une notation "octale" pour la définition des droits.
Un petit tableau sur les valeurs octales et leur signification:
| Valeur | Droits |
|---|---|
| 4 | Read |
| 2 | Write |
| 1 | Execute |
| 0 | None |
Et donc, pour les droits rwx: 4+2+1 = 7, rw: 4+2 = 6, read-only (read): 4, read et execute: 4+1 = 5... etc. On va pouvoir rapidement mettre ça en pratique
Je vous incite fortement à lire les /manpages/ correspondantes
Modification du propriétaire d'un fichier
- On utilisera l'utilitaire chown, pour modifier l'utilisateur et le groupe propriétaires du fichier, exemple:
#Changer l'owner et le groupe d'un fichier:
$ chown user:group fichier
#Changer de façon récursive l'utilisateur et le groupe
#d'un répertoire et de son contenu:
$ chown -R user:group repertoire
La gestion des utilisateurs
Gestion des comptes utilisateurs
Créer un compte pour un nouvel utilisateur
Pour créer un nouvel utilisateur (humain), il faut:
- qu'il ait un login
- qu'il ait un répertoire $HOME
- qu'il ait un shell de login
Pour que cet utilisateur soit activé, il faut aussi qu'il ait un mot de passe
Pour cela, on peut utiliser les commandes useradd ou adduser, au choix
# créer l'utilisateur bidule, avec un répertoire /home/bidule
# et bash comme shell de login
$ sudo useradd -ms /bin/bash bidule
# avec adduser:
$ sudo adduser --shell /bin/bash bidule2
# adduser est plus complet, vous serez amené à choisir mot de passe,
# nom, etc de l'utilisateur lors de sa création
Le répertoire utilisateur est construit en se basant sur le contenu du répertoire:
/etc/skel/
ls -al /etc/skel
Tout fichier ou répertoire créé dans le répertoire skel sera copié dans le répertoire $HOME de l'utilisateur que nous créons. Ainsi, il est facile de provisionner des configurations toutes prêtes pour tel ou tel logiciel (éditeur de texte, shell, etc).
Attribuer ou modifier un mot de passe
Alors notre utilisateur "bidule" est créé, cependant, il n'a pas de mot de passe. On peut modifier son mot de passe, ou le mot de passe d'un utilisateur (si on dispose des droits suffisants) avec la commande passwd.
#pour modifier son mot de passe:
$ passwd
# pour modifier le mot de passe de l'utilisateur bidule:
$ sudo passwd bidule
Supprimer le compte d'un utilisateur
Là aussi, deux commandes: userdel et deluser
# -r pour supprimer le répertoire home de l'utilisateur
$ sudo userdel -r bidule
# la même version deluser:
$ sudo deluser --remove-home bidule2
Modifier le compte d'un utilisateur
On peut bien sûr modifier le compte d'un utilisateur: lui donner un nouveau home, l'ajouter à des groupes, le verrouiller, etc. La commande utilisée est usermod. Par exemple, recréons notre utilisateur /bidule/, puis modifions le pour l'ajouter au groupe "sudo":
$ sudo useradd -ms /bin/bash bidule
$ sudo passwd bidule
#ici, on veut l'ajouter (append) au groupe sudo
# pas remplacer les groupes auquel il appartient
# par le groupe sudo, d'où le "-a" pour append
$ sudo usermod -aG sudo bidule
On peut aussi vouloir déplacer son $HOME vers un autre répertoire:
$ sudo usermod -d /home/pwet -m bidule
Bien évidemment, je vous invite à lire la /manpage/ de usermod
Les groupes
Créer un nouveau groupe
C'est très simple, il suffit d'utiliser la commande addgroup:
$ sudo addgroup nom_du_groupe
Supprimer un groupe
De même, pour supprimer un groupe, il suffit d'utiliser la commande delgroup:
$ sudo delgroup nom_du_groupe
Monter un serveur LAMP
Présentation
L'acronyme /LAMP/ signifie Linux, Apache, MySQL, et finalement PHP (mais ça marcherait aussi avec Python ), c'est à dire:
- un OS (GNU/Linux)
- un serveur Web très utilisé (Apache (2))
- une base de données bien connue (MySQL / MariaDB)
- et enfin un langage de programmation orienté Web (PHP).
C'est une des utilisations les plus classiques de ces logiciels. Bien sûr, en (grosse) production, on y ajoutera des services supplémentaires, comme du load-balancing et du cache Web, et on utilisera des machines (physiques ou virtuelles) dédiées pour chaque logiciel, idéalement, redondantes.
Mais, que ce soit pour un petit site Web à faible trafic, pour un intranet de PME, pour une préproduction, ou pour développer un applicatif PHP, une VM "LAMP" nous fournira tout le nécessaire.
On va donc commencer par installer une nouvelle VM (bridgée SVP) Debian GNU/Linux, mais cette fois ci sans interface graphique: lors du choix des p aquets à installer, on décochera (en appuyant sur espace) "Environnement de bureau" et on cochera "serveur SSH" ainsi qu'"Utilitaires de base du système".
Configuration recommandée: 1 vCPU, 1Go RAM, 20Go disque.
On se connectera à cette VM via notre précédente VM "environnement de bureau" (qui doit donc être, si possible, elle aussi bridgée)
Une fois notre nouvelle VM installée, la première chose que nous allons faire est de sécuriser notre accès SSH à cette VM.
Sécurisation de l'accès distant par SSH
ATTENTION: CETTE ETAPE EST VITALE ET CE SUR TOUTE MACHINE ACCESSIBLE A DISTANCE
La première étape, sur notre client, est de générer notre couple de clefs asymétriques. On peut utiliser différents algorithmes comme RSA, ED25519, etc. Dans notre cas nous allons utiliser l'algorithme RSA, 4096 bits:
Sur notre VM cliente (i.e. notre VM "environnement de bureau"):
$ ssh-keygen -t rsa -b 4096
On ne va pas mettre de /passphrase/, et les noms des deux fichiers de notre couple de clefs seront /id_rsa/ (la clef privée qui ne doit jamais être transmise) et /id_rsa.pub/ (la clef publique que vous pouvez communiquer à tout le monde).
Si on avait voulu créer un couple de clefs dont le nom est "maclefperso" (et maclefperso.pub), on aurait utilisé la commande:
$ ssh-keygen -t rsa -b 4096 -f maclefperso
Dans mon cas, j'utilise un couple de clefs différent par client. Nos couples de clefs sont stockés dans ~/.ssh/ par défaut.
Maintenant, on va envoyer notre clef publique à notre VM "LAMP", depuis notre client:
$ ssh-copy-id -i ~/.ssh/id_rsa utilisateur@ip_vm_lamp
Cette clef est concaténée, côté VM LAMP dans le fichier:
~/.ssh/authorized_keys
On va vérifier que tout est OK sur notre VM LAMP:
$ cat .ssh/authorized_keys
On peut donc désormais se connecter à notre VM en utilisant notre couple de clefs, sans rentrer de mot de passe. Depuis notre VM "Desktop":
$ ssh utilisateur@ip_vm_lamp
Nous voilà donc, depuis notre VM Desktop, connectés à notre VM LAMP. On va en profiter pour modifier la configuration du serveur OpenSSH sur notre VM LAMP, en éditant le fichier:
# vous avez bien installé et configuré sudo comme sur notre
# VM Desktop? :)
$ sudo nano /etc/ssh/sshd_config
# On va chercher cette ligne:
PasswordAuthentification Yes
# on la décommente, et on remplace Yes par No:
PasswordAuthentification No
# Dans la foulée, si ce n'est pas déjà fait,
# On désactive l'accès superutilisateur distant:
PermitRootLogin No
# on sauvegarde et on quitte
# puis on relance le service sshd:
$ sudo systemctl restart sshd
Maintenant, on ne peut plus se connecter en SSH à notre VM LAMP qu'avec la bonne clef privée. Et plus avec un login/mot de passe. C'est littéralement la première chose que vous devriez faire sur chaque VM linux que vous créez . Et c'est la première chose qu'on fait en production (enfin, c'est la première chose que nos recettes font en production).
Installer un service sous GNU/Linux et gestions des services (systemd)
Alors, ce qu'on entend par /service/, ici, et qu'on appelle aussi, dans le cas de systemd, une /unité/ systemd, c'est un élément de configuration déterminant les paramètres de lancement de notre applicatif, et permettant de le lancer automatiquement au démarrage, de le lancer manuellement, de le stopper, de le relancer, ou de l'obliger à recharger sa configuration après modification.
Sous Debian GNU/Linux, comme sous beaucoup d'autres distributions Linux (mais aucun UNIX, et pas certaines distributions GNU/Linux comme Devuan, Alpine, Void Linux ou Gentoo), on utilise systemd et donc l'utilitaire systemctl pour la gestion de ces services.
Les commandes de base de systemctl sont:
Lancer un service:
$ sudo systemctl start nom_du_service
Stopper un service:
$ sudo systemctl stop nom_du_service
Recharger la configuration d'un service sans le relancer (pratique pour ne pas couper le service):
$ sudo systemctl reload nom_du_service
Obtenir des informations sur le statut d'un service:
$ sudo systemctl status nom_du_service
Activer un service pour qu'il se lance automatiquement au démarrage de la machine:
$ sudo systemctl enable nom_du_service
Inversement, si on veut empêcher un logiciel de se lancer au démarrage:
$ sudo systemctl disable nom_du_service
Bien sûr, on a beaucoup d'autres commandes (masquage d'unités systemd, etc) disponibles mais elles sortent du sujet de ce cours. Cependant je vous invite fortement à consulter la documentation de systemd, notamment concernant:
- La création d'unités systemd "à la main".
- La gestion des logs systemd (journalctl).
- Les différents états d'une unité systemd (activée ou pas, masquée ou pas, activée par défaut ou pas (/vendor enabled/), etc).
Configuration d'Apache2
Installation
On ne peut plus simple:
$ sudo apt install apache2
Une fois installé, on peut vérifier le bon fonctionnement d'apache2 en se connectant à http://ip_de_notre_VM_LAMP
Vous remarquerez que par défaut, Debian active notre service et le lance. Ce qui n'est pas forcément une bonne idée, un service non configuré pouvant présenter une faille de sécurité.
On va donc, pour le moment, stopper notre serveur apache2 - en production, s'il n'était pas utilisé, on le désactiverait.
# on vérifie s'il tourne ou pas:
$ sudo systemctl status apache2
# on le stoppe:
$ sudo systemctl stop apache2
# on checke qu'il est bien stoppé:
$ sudo systemctl status apache2
Les fichiers de configuration
L'ensemble des fichiers de configuration d'apache2 se trouve dans les répertoires suivants:
# éléments de configuration générale:
/etc/apache2
# configurations disponibles:
/etc/apache2/conf-available
# configurations activées:
/etc/apache2/conf-enabled
# modules disponibles:
/etc/apache2/mods-available
# modules activés:
/etc/apache2/mods-enabled
# vhosts (sites web) disponibles:
/etc/apache2/sites-available/
# vhosts actifs:
/etc/apache2/sites-enabled/
Regardons maintenant les fichiers de configuration dans le répertoire de base:
$ ls /etc/apache2
apache2.conf conf-available conf-enabled envvars magic mods-available mods-enabled ports.conf sites-available sites-enabled
Les fichiers qui nous intéressent sont:
- apache2.conf: configuration générale d'apache2 (format des logs, sécurité par défaut, etc)
- envvars: les variables d'environnement utilisées par apache2 (et donc par l'utilisateur www-data du groupe www-data)
- ports.conf: comme son nom l'indique, c'est ici qu'on configurera les ports sur lesquels apache2 écoute par défaut. On peut modifier ce paramètre individuellement dans les /vhosts/ de nos sites Web.
le fichier "magic" concerne un module supplémentaire pour les types MIME et ne nous intéresse pas dans le cadre de ce cours
Regardons maintenant le contenu du répertoire sites-enabled:
$ ls -al /etc/apache2/sites-enabled
total 8
drwxr-xr-x 2 root root 4096 sept. 16 14:21 .
drwxr-xr-x 8 root root 4096 sept. 16 14:21 ..
lrwxrwxrwx 1 root root 35 sept. 16 14:20 000-default.conf -> ../sites-available/000-default.conf
Ici, on voit que le fichier 000-default.conf (qui contient la configuration du site web par défaut d'apache2) est un lien symbolique vers:
/etc/apache2/sites-available/000-default.conf
Qu'est ce qu'il se passe si je désactive ce site. Tout d'abord, pour désactiver un site web avec apache2, on a deux solutions:
- La solution "crade": supprimer le lien symbolique correspondant au vhost du site à désactiver dans sites-enabled
- La solution propre: utiliser la commande a2dissite ("Apache2 DISable SITE").
Comme on aime bien faire les choses proprement:
# on va relancer apache2 ;)
$ sudo systemctl start apache2
# on désactive la config
$ sudo a2dissite 000-default
# on reload la config d'apache2
$ sudo systemctl reload apache2
à l'inverse, pour réactiver notre site web par défaut, on utilisera la commande a2ensite (ou on créera un lien symbolique manuellement):
$ sudo a2ensite 000-default
$ sudo systemctl reload apache2
De même, pour activer ou désactiver un élément de configuration:
$ sudo a2enconf nom_de_laconfig
$ sudo a2disconf nom_de_laconfig
Et pour activer ou désactiver un module apache2:
$ sudo a2enmod nom_du_module
$ sudo a2dismod nom_du_module
On va en profiter pour activer le module rewrite qui permet de réécrire des URLs, et dont nous allons avoir besoin pour notre installation de Wordpress:
$ sudo a2enmod rewrite
Fonctionnement
Dans notre cas (configuration simple), le seul fichier que nous modifierons sera le vhost de notre installation de Wordpress:
$ sudo nano /etc/apache2/sites-available/wordpress.conf
<VirtualHost *:80>
ServerAdmin yolo@yolopetlaprod.com
DocumentRoot /var/www/wordpress
ServerName _
<Directory /var/www/wordpress>
Options FollowSymlinks
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/wordpress.error.log
CustomLog ${APACHE_LOG_DIR}/wordpress.access.log combined
</VirtualHost>
#on sauvegarde et on quitte :)
Configuration de MariaDB/MySQL
Bien évidemment, pour notre installation de Wordpress, on va avoir besoin d'une base de données, qui stockera nos articles, nos rubriques, nos paramètres utilisateurs, les paramètres de nos plugins, etc... On va utiliser une des plus connues, le /fork/ de MySQL nommé MariaDB.
Installation
L'installation est triviale:
$ sudo apt install mariadb-server mariadb-client
Les fichiers de configuration
Les fichiers de configuration de MariaDB se trouvent dans:
/etc/mysql
Ses fichiers de données se trouvent eux dans:
/var/lib/mysql
Le fichier de configuration principal de MariaDB se trouve dans:
/etc/mysql/mariadb.conf.d/50-server.cnf
On va l'ouvrir avec notre éditeur préféré:
# sans sudo, on ne veut rien modifier pour le moment
$ nano /etc/mysql/mariadb.conf.d/50-server.cnf
Les paramètres importants, actuellement (on ne va pas rentrer dans le /tuning/ des performances de MariaDB, il faudrait un module à lui tout seul pour ça), sont:
- user: l'utilisateur système utilisé par MariaDB, ici, "mysql"
- port: par défaut, le port de MySQL ou MariaDB est le port 3306
- datadir: le répertoire où MariaDB stocke ses données.
- bind-address: par défaut, MySQL et MariaDB n'écoutent qu'en local (127.0.0.1), c'est à dire qu'ils ne sont pas accessible de l'extérieur. Si on voulait que MariaDB écoute sur une adresse IP attribuée à notre machine (par exemple, 172.16.0.100), on remplacerait 127.0.0.1 par cette IP.
Fonctionnement
On va d'abord se connecter (en root, c'est mal) à notre base de données pour créer une base de données que Wordpress pourra utiliser:
$ sudo mysql
# on liste les databases:
MariaDB [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
+--------------------+
3 rows in set (0.000 sec)
#on va maintenant créer notre base de données Wordpress
MariaDB [(none)]> create database wordpress;
# Puis donner les droits à l'utilisateur wordpress
# qu'on va créer dans la foulée:
MariaDB [(none)]> grant all privileges on wordpress.* to \
'wordpress'@'localhost' identified by 'supermotdepasse';
MariaDB [(none)]> quit;
On va maintenant vérifier qu'on peut se connecter en local à la base wordpress avec notre utilisateur wordpress et son supermotdepasse:
$ mysql -uwordpress -p wordpress
Enter password:
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 52
Server version: 10.3.25-MariaDB-0+deb10u1 Debian 10
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [wordpress]> show tables;
Empty set (0.001 sec)
MariaDB [wordpress]> quit;
Configuration de PHP
Installation
Ici, on va avoir besoin, pour notre installation de Wordpress, d'installer les bibliothèques PHP requises, ainsi que le module apache2 PHP8.2, ce qui se fait facilement:
$ sudo apt install apache2 php8.2 libapache2-mod-php8.2 \
php8.2-common php8.2-mbstring php8.2-xmlrpc \
php8.2-soap php8.2-gd php8.2-xml php8.2-intl \
php8.2-mysql php8.2-cli php8.2-ldap php8.2-zip \
php8.2-curl
PHP-FPM
On pourrait utiliser PHP-FPM (asynchrone) au lieu de libapache2-mod-php7.3 afin d'obtenir de meilleures performances. Je ne vais pas trop m'étendre là-dessus car ce n'est pas trop l'objectif du cours.
Configuration de Wordpress
Enfin, on va pouvoir configurer Wordpress! On va tout d'abord récupérer la dernière version de Wordpress sur notre VM LAMP:
$ wget -c https://wordpress.org/latest.tar.gz
On va décompresser notre archive, ce qui va nous permettre de faire un mini tuto sur tar. En effet notre archive est compressée en tar.gz, c'est à dire un fichier d'archive tar compressé en gzip. Un fichier d'archive tar possède un avantage: il permet de conserver les droits, permissions, propriétaires, liens symboliques de ce qui est archivé. Ainsi, ces différents paramètres seront rétablis au décompactage de l'archive tar.
Pour décompresser un fichier tar.gz:
$ tar xvzf fichier.tar.gz
Pour créer une archive à partir d'un répertoire:
$ tar cvzf archive.tar.gz repertoire/
Dans notre cas:
# on veut décompresser latest.tar.gz:
$ tar xvzf latest.tar.gz
On va ensuite vouloir déplacer le répertoire wordpress à l'endroit pointé dans notre vhost, dans mon cas:
$ sudo mv wordpress /var/www/
# je veux aussi lui donner les bons droits,
# le répertoire et son contenu:
$ sudo chown -R www-data:www-data /var/www/wordpress
Il nous reste juste à lancer apache2 pour terminer la configuration de Wordpress depuis un confortable navigateur Web:
$ sudo systemctl start apache2
Puis, se connecter à l'adresse IP de notre VM LAMP depuis notre VM Desktop en utilisant Firefox. Et ne toucher à rien avant que j'y sois aussi