La séquence de travaux ci-dessous vise à déployer un serveur WEB sous Linux (Debian), basé le serveur HTTP Apache et associé à un moteur de script (PHP) et une base de données (mySQL/mariaDB). L’ensemble compose ce qu’on appelle un serveur LAMP (Linux Apache MySQL PHP) et permet de déployer des applications web complètes.
Grâce à l’environnement que nous allons mettre en place, nous déploierons un CMS Wordpress et un outil d’administration en ligne de base de données : phpMyAdmin.
NB : dans le but de ne pas alourdir ce TP déjà bien chargé, le serveur WEB que nous allons mettre en place n’intègre pas de couche cryptographique ; mais il est important de rappeler qu’un serveur en production doit être configuré afin de répondre aux critères actuels de sécurité et d’optimisation (certificats, règles et protocoles crypto, http/2, …)
On utilise l’environnement du mini-lab virtuel personnel pour réaliser cette maquette :
Concernant le serveur web (debian-core) :
ssh pascal@192.168.1.10
sudo nano /etc/hostname
sudo nano /etc/hosts
qui doit au final ressembler à ceci :
127.0.0.1 localhost
127.0.1.1 debian-lamp
# The following lines are desirable for IPv6 capable hosts
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
NB : tant qu'on n'a pas relancé le serveur, il y une incohérence entre le hostname actuel (
debian
) et la résolution de l'ip127.0.1.1
(debian-lamp
), qui génère notamment un message d'erreur à chaque commandesudo
.
Il faut à ce point redémarrer le serveur :
sudo reboot
le redémarrage du serveur a coupé la session ssh et rendu la main du terminal à notre VM debian-gui (cliente) ; profitons-en pour lancer une mise à jour et installer des outils wget, curl et dnsutils :
sudo apt update && sudo apt upgrade && sudo apt -y install curl wget dnsutils
Puis on se reconnecte au serveur fraîchement relancé :
ssh pascal@192.168.1.10
On lance une mise à jour et l'installation des utilitaires wget et tree :
sudo apt update && sudo apt upgrade && sudo apt -y install wget tree
Le logiciel libre Apache HTTP Server (Apache) est un serveur HTTP créé et maintenu au sein de la fondation Apache. Jusqu'en avril 2019, ce fut le serveur HTTP le plus populaire du World Wide Web. Il est distribué selon les termes de la licence Apache. La première version date de 1995, mais une réécriture complète a produit la version 2, toujours en cours aujourd’hui. La fondation Apache (Apache Software Foundation ou ASF) a été créée en 1999 à partir du groupe Apache (Apache Group) à l'origine du serveur en 1995. Depuis, de nombreux autres logiciels utiles au World Wide Web sont développés à côté du serveur HTTP.
(source : wikipedia)
Sur notre serveur tout neuf, on installe tout simplement apache avec :
sudo apt install apache2
On peut dès lors tester le fonctionnement depuis le navigateur de la machine GUI :
Ou encore depuis le terminal (toujours sur la VM cliente) :
curl -I 192.168.1.10
NB : la commande curl avec cette option ne renvoie que l’entête de la réponse HTTP, pas le contenu de la page.
On peut obtenir l’état du service apache2 avec cette commande habituelle (depuis le terminal connecté au serveur) :
systemctl status apache2
Pour arrêter le service :
sudo systemctl stop apache2
On voit alors qu’il ne répond plus (si on rafraichit la page web depuis le navigateur) :
Vérifiez aussi ce que donne la vérification du statut.
Relaçons le service :
sudo systemctl restart apache2
Voici quelques autres commandes relatives au fonctionnement du service :
Empêcher Apache de démarrer automatiquement :
sudo systemctl disable apache2
Réactiver le démarrage automatique :
sudo systemctl enable apache2
Pour relancer apache2 :
sudo systemctl restart apache2
Pour recharger la configuration d'apache2 (assez proche de restart) :
sudo systemctl reload apache2
L’installation d'Apache2 vient avec une configuration de base, qui s’appuie sur la structure du répertoire /etc/apache2, dont on peut voir l’arborescence au premier niveau en tapant cette commande :
tree -L 1 /etc/apache2
Ce qui donne :
/etc/apache2
├── apache2.conf
├── conf-available
├── conf-enabled
├── envvars
├── magic
├── mods-available
├── mods-enabled
├── ports.conf
├── sites-available
└── sites-enabled
Le fichier de configuration principal est /etc/apache2/apache2.conf
, dont on affiche le contenu ci-dessous. A l’aide de grep
, on supprime de l’affichage les lignes de commentaire (les lignes qui commencent par le caractère #
) :
cat /etc/apache2/apache2.conf | grep ^[^#]
Nous obtenons :
DefaultRuntimeDir ${APACHE_RUN_DIR}
PidFile ${APACHE_PID_FILE}
Timeout 300
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 5
User ${APACHE_RUN_USER}
Group ${APACHE_RUN_GROUP}
HostnameLookups Off
ErrorLog ${APACHE_LOG_DIR}/error.log
LogLevel warn
IncludeOptional mods-enabled/*.load
IncludeOptional mods-enabled/*.conf
Include ports.conf
<Directory />
Options FollowSymLinks
AllowOverride None
Require all denied
</Directory>
<Directory /usr/share>
AllowOverride None
Require all granted
</Directory>
<Directory /var/www/>
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
AccessFileName .htaccess
<FilesMatch "^\.ht">
Require all denied
</FilesMatch>
LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %O" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent
IncludeOptional conf-enabled/*.conf
IncludeOptional sites-enabled/*.conf
On voit que des paramètres sont déterminés à partir de variables d’environnement. Celles-ci sont définies dans le fichier /etc/apache2/envvars
Par exemple, ligne 7, l’utilisateur associé au processus serveur est défini par : User ${APACHE_RUN_USER}
Dans le fichier envvars
, on peut voir la ligne suivante :
export APACHE_RUN_USER=www-data
Le login de l’utilisateur associé est donc www-data
.
Les ports d’écoute sont quant à eux définis dans le fichier ports.conf
On repère également que des éléments complémentaires vont être chargés à ces endroits :
conf-enabled/*.conf
: fichiers de configuration d’autres services activés (liens symboliques depuis le dossier de ceux qui sont disponibles : conf-available)mod-enabled/*.{load,conf}
: fichiers de configuration des modules d'Apache activéssites-enabled/*.conf
: fichiers de configuration des sites activés. Apache peut servir simultanément plusieurs sites, via la configuration d'hôtes virtuels (virtualhosts)Pour voir les modules d'Apache chargés :
sudo apache2ctl -M
Pour voir la version d'Apache utilisée :
sudo apache2ctl -v
Pour tester l'ensemble de la configuration d'Apache :
sudo apache2ctl -t
Pour tester la configuration des hôtes virtuels (sites) :
sudo apache2ctl -t -D DUMP_VHOSTS
NB : Normalement les fichiers de configuration globale apache2.conf
, envvars
et ports.conf
n'ont pas à être modifiés. Toute configuration spécifique devrait se faire dans les sous répertoires : xxx-available
.
Pour en savoir plus sur les directives de configuration d’Apache : https://httpd.apache.org/docs/2.4/fr/mod/core.html
Et plus généralement, la documentation de référence Apache est ici : https://httpd.apache.org/docs/2.4/fr/
La page d’accueil par défaut post-installation nous invite à modifier le fichier /var/www/html/index.html
:
Ceci correspond au virtualhost par défaut, dont on trouve la configuration dans /etc/apache2/sites-enabled
, le fichier de configuration étant : 000-default.conf
; ce fichier est lui-même un lien symbolique vers l’emplacement /etc/apache2/sites-available
.
D'abord, on se rend dans le répertoire :
cd /etc/apache2/sites-enabled
On liste les fichiers, et on voit le lien symbolique de 000-default.conf
:
ls -lht
Regardons son contenu, en supprimant les commentaires (grâce à l'outil grep) :
cat 000-default.conf | grep -v ^[[:space:]]*#
Ce qui doit donner :
<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
Le fichier de configuration indique un minimum de choses :
<VirtualHost *.80>
: écoute sur toute adresse IP du serveur (*), sur le port 80.ServerAdmin
: définit l'adresse de contact que le serveur va inclure dans tout message d'erreur qu'il envoie au client.DocumentRoot
: définit le répertoire de base (racine) à partir duquel le serveur http va servir les fichiers.ErrorLog, CustomLog
: emplacements des fichiers de log d’erreur et connexion (en savoir plus sur les logs : https://httpd.apache.org/docs/2.4/fr/logs.html )Rendez-vous dans le répertoire racine (root) du virtualhost : /var/www/html
,
cd /var/www/html
On peut voir que le fichier index.html
appartient à root :
ls -l
Pour le modifier, ne donc pas oublier le sudo :
sudo nano index.html
Même si on peut s’amuser à personnaliser un peu ce fichier index, il n’est cependant pas d’usage de modifier le virtualhost par défaut.
Pour créer un premier site web spécifique, on va configurer un nouveau serveur virtuel.
Apache recommande de créer un fichier de configuration dans lequel est défini un hôte virtuel pour chaque site ou application web dans le répertoire /etc/apache2/sites-available/
.
Chaque hôte virtuel peut être appelé en fonction d'un nom de domaine ou sous-domaine, c'est la configuration la plus courante. Mais on peut également définir un numéro de port particulier, ou une adresse IP particulière (si le serveur en possède plusieurs) pour laquelle on affichera tel ou tel contenu web.
Chaque hôte virtuel ayant son fichier de configuration dédié, pour s'y repérer on peut le nommer par le nom de domaine auquel il correspond, suivi de l'extension .conf
.
Pour un nom de domaine example.com
on créera donc un fichier /etc/apache2/sites-available/example.com.conf
.
Afin de personnaliser vos travaux, vous pouvez utilise par la suite votre propre nom à la place de
example
Créons donc notre fichier de configuration virtualhost :
sudo nano /etc/apache2/sites-available/example.com.conf
Qui contiendra le texte suivant :
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
DocumentRoot "/var/www/example"
<Directory "/var/www/example">
Options +FollowSymLinks
AllowOverride all
Require all granted
</Directory>
ErrorLog /var/log/apache2/error.example.com.log
CustomLog /var/log/apache2/access.example.com.log combined
</VirtualHost>
Quelques commentaires sur ce fichier de configuration :
Directive | Description |
---|---|
<VirtualHost *:80> |
On accepte les connexions sur n'importe quelle IP du serveur (* ) sur le port 80 . |
ServerName example.com |
Cet hôte virtuel sera seulement appelé pour le nom de domaine example.com … |
ServerAlias www.example.com |
… ainsi que pour le sous-domaine www.example.com . On peut spécifier ici d'autres noms de domaine en les séparant par un espace. On peut aussi utiliser *.example.com pour inclure tous les sous-domaines. |
DocumentRoot "/var/www/example" |
On placera les fichiers du site dans le répertoire /var/www/example . |
<Directory "/var/www/example"> |
On spécifie dans cette section des règles pour le répertoire /var/www/example sous cet hôte virtuel, qui sont : |
Options +FollowSymLinks |
Apache suivra les liens symboliques qu'il trouvera dans ce répertoire (et ses descendants). |
AllowOverride all |
On pourra inclure une configuration personnalisée via un fichier .htaccess . |
Require all granted |
Tous les visiteurs pourront accéder au contenu de ce répertoire. Voir la documentation officielle pour modifier ce comportement. Pour des raisons de sécurité on peut par exemple limiter l'accès au serveur à seulement une ou certaines adresses IP sources avec une directive du type Require ip 192.168.1.103 . |
ErrorLog /var/log/apache2/error.example.com.log |
Il est pratique d'avoir des logs séparés pour chaque hôte virtuel, afin de ne pas mélanger toutes les informations; |
CustomLog /var/log/apache2/access.example.com.log combined |
Ici on sépare les log d'erreur et de connexion, l'option combined permet de fournir des informations plus détaillées pour chaque entrée. |
Voici quelques autres éléments à connaître au sujet d'Apache :
Apache nous permet de définir des configurations complémentaires ou différentes pour certains répertoires en plaçant des fichiers nommés .htaccess
directement avec les autres fichiers du contenu web. (Le .
au début du nom du fichier rend ce fichier caché par défaut.)
Les directives de chaque fichier .htaccess
s'appliquent au répertoire dans lequel il se trouve, ainsi que tous ses descendants (sous-répertoires).
C'est la directive AllowOverride
, spécifiée dans une section <Directory>
de l'hôte virtuel qui définit si les fichiers .htaccess
doivent être pris en compte ou pas, pour ce répertoire et ses descendants. Elle peut prendre la valeur All
ou None
.
Ces fichiers sont très pratiques pour redéfinir des paramètres sur un serveur mutualisé à l'administration duquel on n'a pas accès, ou pour définir dynamiquement des règles spécifiques à certaines solutions web (comme la réécriture d'URL).
L'index est le contenu affiché par défaut par Apache lorsqu'on appelle un répertoire sans spécifier de nom de page web particulière.
L'index est défini par la directive DirectoryIndex
qui détermine quels fichiers Apache doit traiter par défaut. Chaque nom de fichier est séparé par un espace et listé par ordre de priorité.
Par défaut, DirectoryIndex
a la valeur index.html index.cgi index.pl index.php index.xhtml index.htm
.
Si Apache ne trouve aucun des fichiers mentionnés par DirectoryIndex
, il essaie de récupérer une liste du contenu du répertoire, afin que le navigateur l'affiche de la même manière qu'un gestionnaire de fichiers.
On peut activer ou désactiver l’affichage de cette liste avec respectivement les directives Options +Indexes
ou Options -Indexes
. Pour des raisons de sécurité, il est généralement préférable de laisser cette option désactivée. Dans ce cas, et faute de fichier index
, c'est une erreur 403 qui s'affiche, car l'utilisateur n'a pas la permission de lister le contenu du répertoire.
Toutes ces directives peuvent être définies dans une section <Directory>
ou dans un fichier .htaccess
.
Après avoir l'avoir créée, il faut activer notre configuration avec la commande sudo a2ensite [nom_du_fichier_sans_son_extension]
.
Ce qui donne pour notre exemple :
sudo a2ensite example.com
Comme on y est invité, on recharge la configuration d'Apache :
sudo systemctl reload apache2
On teste la configuration d'Apache :
sudo apache2ctl -t
Nous obtenons évidemment un message qui nous indique au moins que le répertoire root de notre site n’existe pas (ligne1) :
AH00112: Warning: DocumentRoot [/var/www/example] does not exist
AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 127.0.1.1. Set the 'ServerName' directive globally to suppress this message
Syntax OK
Créons donc le répertoire root du site :
sudo mkdir /var/www/example
Nous nous positionons dessus :
cd /var/www/example
Et nous éditons un fichier index.html persdonnalisé :
sudo nano index.html
Je vous propose par exemple ce petit code html :
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bienvenue sur mon serveur Apache2 !</title>
<style>
body {
font-family: 'Arial', sans-serif;
text-align: center;
background-color: #ffeb3b;
color: #333;
margin: 0;
padding: 0;
}
h1 {
color: #00796b;
font-size: 3em;
margin-top: 50px;
}
p {
font-size: 1.2em;
}
.fun {
font-size: 1.5em;
color: #f44336;
font-weight: bold;
}
.button {
background-color: #2196f3;
color: white;
border: none;
padding: 15px 30px;
text-align: center;
font-size: 1.1em;
margin-top: 30px;
cursor: pointer;
border-radius: 10px;
transition: background-color 0.3s;
}
.button:hover {
background-color: #0d47a1;
}
footer {
position: fixed;
bottom: 10px;
left: 50%;
transform: translateX(-50%);
font-size: 0.9em;
color: #555;
}
</style>
</head>
<body>
<h1>Bienvenue sur mon serveur Apache2 !</h1>
<p>Vous êtes à un pas de découvrir quelque chose de fun et cool.</p>
<p class="fun">C'est facile, c'est simple, et c'est amusant !</p>
<button class="button" onclick="alert('Tu as cliqué sur le bouton magique ! 🎉')">Clique ici pour la magie !</button>
<footer>
<p>© 2025 Mon super serveur Apache2. Tous droits réservés.</p>
</footer>
</body>
</html>
Si nous testons le serveur depuis un navigateur web, avec l’adresse ip, nous sommes un peu déçus :
C’est le serveur par défaut qui répond. En effet, notre serveur ne répond que si la requête http fait référence à example.com
. Mais là aussi, on peut être déçu :
En effet, example.com
est résolu via le DNS de la machine GUI par une IP publique. Vérifions depuis le terminal de la machine client (debian-gui) :
dig example.com
La réponse du DNS 1.1.1.1 :
; <<>> DiG 9.18.28-1~deb12u2-Debian <<>> example.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 58438
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;example.com. IN A
;; ANSWER SECTION:
example.com. 382 IN A 93.184.215.14
;; Query time: 111 msec
;; SERVER: 1.1.1.1#53(1.1.1.1) (UDP)
;; WHEN: Sat Jan 04 18:13:58 CET 2025
;; MSG SIZE rcvd: 56
En ligne 13, on voit que example.com
est résolu par l'IP 93.184.215.14
On peut contourner ceci, notamment dans une phase de test ou d’exemple, comme notre cas, en modifiant sur la machine cliente le fichier /etc/hosts
, qui contient des résolutions DNS locales :
sudo nano /etc/hosts
Et on y ajoute une ligne (ligne 3) pour la résolution de example.com
vers notre serveur :
127.0.0.1 localhost
127.0.1.1 debian-gui
192.168.1.10 example.com
# The following lines are desirable for IPv6 capable hosts
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
On vérifie avec un ping (car dig ne va pas solliciter le fichier hosts) :
ping -c 3 example.com
La réponse :
PING example.com (192.168.1.10) 56(84) bytes of data.
64 bytes from example.com (192.168.1.10): icmp_seq=1 ttl=64 time=1.11 ms
64 bytes from example.com (192.168.1.10): icmp_seq=2 ttl=64 time=0.890 ms
64 bytes from example.com (192.168.1.10): icmp_seq=3 ttl=64 time=1.43 ms
--- example.com ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 0.890/1.143/1.426/0.219 ms
Nous indique bien que cette fois example.com
est résolu par l'IP de notre serveur local.
Après rafraîchissement de la page web, la magie opère :
NB : les navigateurs web ont souvent un cache DNS intégré ; pour être sûr qu’il consulte bien le système pour la résolution du nom, utilisez la navigation privée.
Grâce aux langages de script (JavaScript, Ajax, JQuery, Angular, ...) il est possible d’apporter des éléments de programmation au sein des pages html. Contrairement aux langages comme PHP qui sont exécutés par le serveur pour renvoyer une page html passive, les scripts sont exécutés sur la machine cliente, par le navigateur web lui-même. On parle de code (ou de programmation) "front-end".
Voici par exemple une variante du fichier index qui utilise jQuery pour animer la page :
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bienvenue sur mon serveur Apache2 !</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<style>
body {
font-family: 'Arial', sans-serif;
text-align: center;
background-color: #ffeb3b;
color: #333;
margin: 0;
padding: 0;
}
h1 {
color: #00796b;
font-size: 3em;
margin-top: 50px;
opacity: 0; /* Initialement invisible */
transform: scale(0.5); /* Initialement plus petit */
}
p {
font-size: 1.2em;
}
.fun {
font-size: 1.5em;
color: #f44336;
font-weight: bold;
}
.button {
background-color: #2196f3;
color: white;
border: none;
padding: 15px 30px;
text-align: center;
font-size: 1.1em;
margin-top: 30px;
cursor: pointer;
border-radius: 10px;
transition: background-color 0.3s;
}
.button:hover {
background-color: #0d47a1;
}
footer {
position: fixed;
bottom: 10px;
left: 50%;
transform: translateX(-50%);
font-size: 0.9em;
color: #555;
}
</style>
</head>
<body>
<h1>Bienvenue sur mon serveur Apache2 !</h1>
<p>Vous êtes à un pas de découvrir quelque chose de fun et cool.</p>
<p class="fun">C'est facile, c'est simple, et c'est amusant !</p>
<button class="button" id="magicButton">Clique ici pour la magie !</button>
<footer>
<p>© 2025 Mon super serveur Apache2. Tous droits réservés.</p>
</footer>
<script>
$(document).ready(function() {
// Animation du titre (zoom et fondu)
$("h1").animate({
opacity: 1, // Rendre visible
transform: "scale(1)" // Rétablir la taille normale
}, 1500); // Durée de 1.5 secondes
// Animation du bouton au survol
$(".button").hover(function() {
$(this).animate({fontSize: "1.2em"}, 300);
}, function() {
$(this).animate({fontSize: "1.1em"}, 300);
});
// Animation sur clic (modification du texte avec animation)
$("#magicButton").click(function() {
$(this).animate({opacity: 0.5}, 500).animate({opacity: 1}, 500);
$(".fun").slideToggle();
});
});
</script>
</body>
</html>
Ce qu’il est possible de faire avec le langage HTML associé aux feuilles de style CSS et au langage Javascript (et ses dérivés comme JQuery) est assez impressionnant, et permet de forger des interfaces utilisateur de grande qualité.
Inspirez-vous et formez-vous par exemple grâce à la W3school : https://www.w3schools.com
Les pages HTML sont normalement destinées à être "servies tel quel" au navigateur client : le contenu du fichier est transféré directement au client par le protocole HTTP.
Afin de pouvoir produire des pages HTML au contenu dynamique, c’est-à-dire en fonction de données dont dispose le serveur, on peut insérer dans la page une séquence dans un langage de script, par exemple PHP. Dans ce cas, le contenu n’est pas envoyé au client, mais à un moteur de script côté serveur ; c’est le résultat (la sortie) de ce script qui sera envoyé au client. On parle ici de programmation back-end, c’est-à-dire côté serveur, par opposition à ce que s’exécute du côté client (front-end).
Le mieux est d’illustrer cela par un exemple. Mais il nous faut d’abord ajouter un moteur de script du côté de notre serveur.
PHP est l’acronyme récursif de "PHP : Hypertext Preprocessor". C’est un langage de programmation libre, principalement utilisé pour produire des pages Web dynamiques via un serveur HTTP, mais pouvant également fonctionner comme n'importe quel langage interprété de façon locale. PHP est un langage impératif orienté objet.
PHP a permis de créer un grand nombre de sites web célèbres, comme Facebook, Wikipédia, etc. Il est considéré comme une des bases de la création de sites web dits dynamiques mais également des applications web.
(sources : wikipedia)
Il existe plusieurs façons de permettre à Apache de faire appel à un moteur PHP. On peut aussi lui donner la possibilité de faire appel à Python par exemple (c’est moins courant).
Nous allons ici installer le paquet php-fpm (sur le serveur, bien sûr) par cette commande :
sudo apt install php-fpm
Le gestionnaire de paquet Debian installe la dernière version disponible de PHP. Pour connaître à tout moment la version installée :
php -v
PHP est installé avec un certain nombre de modules de base (qui ajoutent des fonctions au langage PHP en général), pour les connaître :
php -m
Au moment de l’installation de php-fpm, comme apache2 est installé sur notre serveur, nous avons aperçu un message nous invitant à activer PHP pour apache, par ces deux commandes :
sudo a2enmod proxy_fcgi setenvif
sudo a2enconf php8.2-fpm
NB : il faut éventuellement remplacer 8.2 par la version effective de php sur le système (obtenue avec
php -v
, en ne prenant que les deux premiers termes ; par exemple php version 8.2.7 => php8.2-fpm)
Il faut enfin relancer le serveur apache :
sudo systemctl reload apache2
Les fichiers HTML qui contiennent des scripts PHP doivent comporter l’extension .php
et non .html
; c’est le cas notamment pour le fichier index.
Rendez-vous sur notre "document root" :
cd /var/www/example
Supprimons le fichier index.html :
sudo rm index.html
Puis nous allons donc créer un premier fichier php (toujours à la racine de notre site example.com
) :
sudo nano index.php
qui contient :
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Ma page PHP</title>
</head>
<body>
<p>Ce texte est statique</p>
<?php
$a = 'dynamique';
echo "Ce texte est $a";
?>
</body>
</html>
Dans la balise <body>
, on trouve un "échappement" PHP : entre les balises <?php
et ?>
, le code présent sera transmis au serveur PHP, et la sortie du script sera transmise au client :
Essayons maintenant l’interactivité au sein de notre site web. Recréons notre page d’accueil index.html :
sudo nano index.html
Avec ce contenu :
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Formulaire avec Action</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f9f9f9;
color: #333;
margin: 0;
height: 100vh; /* Remplir toute la hauteur de la fenêtre */
display: flex;
justify-content: center; /* Centrer horizontalement */
align-items: center; /* Centrer verticalement */
}
h1 {
color: #00796b;
}
form {
background-color: #ffffff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
display: inline-block;
width: 100%;
max-width: 400px; /* Limiter la largeur du formulaire */
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
input[type="text"] {
width: 100%;
padding: 10px;
margin: 10px 0;
border-radius: 4px;
border: 1px solid #ccc;
}
input[type="submit"] {
padding: 10px 20px;
background-color: #00796b;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
width: 100%;
}
input[type="submit"]:hover {
background-color: #004d40;
}
</style>
</head>
<body>
<form action="action_page.php" method="post">
<h1>Formulaire de Contact</h1>
<label for="nom">Votre nom :</label>
<input type="text" id="nom" name="nom" value="Mickey Mouse" required>
<label for="email">Votre email :</label>
<input type="text" id="email" name="email" value="mickey.mouse@yahoo.fr" required>
<input type="submit" value="Envoyer">
</form>
</body>
</html>
Il contient entre les balises <body>
un formulaire qui collecte des données auprès de l'utilisateur, et les envoie (via une requête HTTP en mode POST) à un script action_page.php
chargé de traiter ces données.
On crée donc ce fichier nommé action_page.php
au même emplacement :
sudo nano action_page.php
Qui contient :
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Réponse du Formulaire</title>
<style>
body {
font-family: 'Arial', sans-serif;
background-color: #f0f8ff;
color: #333;
text-align: center;
padding: 50px;
margin: 0;
}
h1 {
color: #00796b;
}
.response-box {
background-color: #ffffff;
padding: 20px;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
display: inline-block;
max-width: 500px;
width: 100%;
margin-top: 20px;
text-align: left;
}
.response-box p {
font-size: 1.2em;
line-height: 1.6;
margin: 10px 0;
}
.highlight {
color: #00796b;
font-weight: bold;
}
.footer {
font-size: 0.9em;
color: #555;
margin-top: 30px;
}
.footer a {
color: #00796b;
text-decoration: none;
}
.footer a:hover {
text-decoration: underline;
}
</style>
</head>
<body>
<h1>Merci de nous avoir contacté !</h1>
<div class="response-box">
<p>Bienvenue, <span class="highlight"><?php echo $_POST["nom"]; ?></span> !</p>
<p>Votre adresse email est : <span class="highlight"><?php echo $_POST["email"]; ?></span></p>
<?php
$nom = $_POST["nom"];
$long = strlen($nom);
?>
<p>Votre nom comporte <span class="highlight"><?php echo $long; ?></span> caractères.</p>
</div>
<div class="footer">
<p>Retour à la <a href="index.html">page d'accueil</a></p>
</div>
</body>
</html>
Entre les balises <body>
du fichier le code PHP récupère et traite les données $_POST["nom"]
et $_POST["email"]
pour générer un fichier HTML dynamique.
Notons que l’utilisateur final (le client) ne verra que le résultat de ce script, et pas le script lui-même. Pour s’en rendre compte, visualisez le code source de la page web avec votre navigateur.
Le formulaire dans index.html…
Et le résultat :
La plupart des applications web, comme les CMS (Content Management System) Wordpress, font appel à Apache et PHP notamment pour s’exécuter. Mais elles ont besoin (en général) d’un dernier service associé que nous allons aborder maintenant, il s’agit d’un serveur de base de données.
MySQL est un système de gestion de bases de données relationnelles (SGBDR). Il est distribué sous une double licence GPL et propriétaire. Il fait partie des logiciels de gestion de base de données les plus utilisés au monde, autant par le grand public (applications web principalement) que par des professionnels, en concurrence avec Oracle, PostgreSQL et Microsoft SQL Server. Son nom vient du prénom de la fille du cocréateur Michael Widenius, « My ». SQL fait référence au Structured Query Language, le langage de requête utilisé. MySQL a été acheté le 16 janvier 2008 par Sun Microsystems lui-même acquis ensuite par Oracle Corporation.
Depuis mai 2009, son créateur Michael Widenius a créé MariaDB (Maria est le prénom de sa deuxième fille) pour continuer son développement en tant que projet Open Source.
(source : wikipedia)
Comme tout service répandu, l’installation de mariaDB sur le serveur se fait de la plus simple des façons :
sudo apt install mariadb-server
Ensuite, et c’est important, nous lançons la procédure d’installation sécurisée (qui consiste à mettre un mot de passe sur l’utilisateur root du serveur Mysql, désactiver la connexion distante du root et supprimer les bases de test). Attention à vos réponses ! dans les options entre crochets, celle en majuscules est la réponse par défaut (c’est-à-dire la réponse effective si vous tapez juste la touche Entrée) :
sudo mysql_secure_installation
Dans notre contexte, les réponses à donner sont dans l'ordre : Entrée, n, n, y, y, y, y.
Nous allons ensuite créer une première base de données. Une base de données est identifiée par un nom ; elle est généralement associée à un ou plusieurs utilisateurs qui auront différents privilèges dessus.
On entre dans la console mysql en mode super-user :
sudo mysql -u root
Dans cette console, on saisit des commandes en langage SQL pour gérer des bases de données et les objets associés (tables, colonnes, données, …).
Par exemple ici, nous créons donc notre première base de données que nous appellerons example_db :
CREATE DATABASE example_db;
Nous lui associons l’utilisateur example (avec le mot de passe root) qui aura tous les privilèges sur tous les composants de la base de données, lorsqu’il se connecte depuis la machine locale (localhost) :
GRANT ALL ON example_db.* TO 'example'@'localhost' IDENTIFIED BY 'root';
enfin nous rendons effectifs ces réglages :
FLUSH PRIVILEGES;
et nous quittons le shell :
exit;
Nous avons désormais tous les services pour que notre serveur LAMP (Linux Apache MySQL PHP) soit opérationnel.
Nous pouvons donc notamment y installer un outil complet tel que Wordpress, qui s’appuie sur ce genre de configuration pour fonctionner.
WordPress est un système de gestion de contenu (content management system (CMS) en anglais) gratuit, libre et open-source. Ce logiciel écrit en PHP repose sur une base de données MySQL et est distribué par l'entreprise américaine Automattic. Les fonctionnalités de WordPress lui permettent de créer et gérer différents types de sites Web : site vitrine, site de vente en ligne, site applicatif, blogue, ou encore portfolio. Il est distribué selon les termes de la licence GNU GPL version 2. Le logiciel est aussi à l'origine du service WordPress.com.
En octobre 2019, WordPress est utilisé par 34,7 % des sites web dans le monde, ses concurrents directs sont à 2,7 % (Joomla) et à 1,7 % (Drupal) tandis que 43,6 % des sites n'utilisent pas de système de gestion de contenu.
Nous allons installer un module WordPress dans l’arborescence de notre site web. Rendez-vous sur le répertoire racine créé précédemment :
cd /var/www/example
On télécharge le dernier package en date de WordPress :
sudo wget https://wordpress.org/latest.tar.gz
et on le décompresse :
sudo tar -xvzf latest.tar.gz
ls -l
On obtient un nouveau sous-répertoire wordpress
; nous en transférons la propriété à l’utilisateur spécifique du système dédié au service web : www-data
(afin qu’il puisse modifier son contenu) :
sudo chown -R www-data:www-data wordpress
Désormais, vous pouvez accéder à votre site WordPress depuis votre navigateur, sous le répertoire wordpress :
Le script d’installation de WordPress nous indique que l’extension PHP MySQL est manquante sur notre système. Installons ce module complémentaire :
sudo apt -y install php-mysql
La première chose qui sera demandée (après la langue) est la connexion à la base de données, telle que nous l’avons définie juste avant :
Puis il faut donner un titre principal au site et définir les identifiants de connexion à la console d’administration du site.
Prenez le temps de découvrir par vous-même le fonctionnement de cet outil (interface d’administration, personnalisation du site, choix de thèmes, extensions, écriture d’articles ou de pages, …)
upload_max_filesize
dans le fichier /etc/php/8.2/fpm/php.ini
(utilisez CTRL+W dans nano pour rechercher du texte).sudo systemctl restart php8.2-fpm
/var/www/example/wordpress
) - prenons le domaine example.fr
:sudo nano /etc/apache2/sites-available/example.fr.conf
Qui contiendra le texte suivant :
<VirtualHost *:80>
ServerName example.fr
ServerAlias www.example.fr
DocumentRoot "/var/www/example/wordpress"
<Directory "/var/www/example/wordpress">
Options +FollowSymLinks
AllowOverride all
Require all granted
</Directory>
ErrorLog /var/log/apache2/error.example.fr.log
CustomLog /var/log/apache2/access.example.fr.log combined
</VirtualHost>
Analysez les différences, notamment sur le DocumentRoot
On active ce nouveau serveur virtuel :
sudo a2ensite example.fr
Comme on y est invité, on recharge la configuration d'Apache :
sudo systemctl reload apache2
On teste la configuration d'Apache :
sudo apache2ctl -t
Il faut également sur la machine client ajouter l'entrée DNS :
sudo nano /etc/hosts
On ajoute une ligne (ligne 4) pour la résolution de example.fr
vers l'IP de notre serveur :
127.0.0.1 localhost
127.0.1.1 debian-gui
192.168.1.10 example.com
192.168.1.10 example.fr
# The following lines are desirable for IPv6 capable hosts
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
Attention à la cohérence des liens dans le site, qui doivent tous être référencés selon la racine. Il faut pour cela modifier les paramètres du site dans la console d’administration WordPress (onglet "général") :
Il faut également republier la personnalisation du thème pour que se propagent ces nouveaux réglages.
Une fois que ces ajustements sont faits, il est alors possible de désactiver le précédent virtualhost :
sudo a2dissite example.com
sudo systemctl reload apache2
Et seul demeure maintenant le site example.fr
:
Afin de gérer les bases de données depuis l’interface du serveur, on va utiliser l’outil phpMyAdmin.
phpMyAdmin (PMA) est une application Web de gestion pour les systèmes de gestion de base de données MySQL réalisée principalement en PHP et distribuée sous licence GNU GPL. Il s'agit de l'une des plus célèbres interfaces pour gérer une base de données MySQL sur un serveur PHP. De nombreux hébergeurs, gratuits comme payants, le proposent ce qui évite à l'utilisateur d'avoir à l'installer.
Cette interface pratique permet d'exécuter, très facilement et sans grandes connaissances en bases de données, des requêtes comme les créations de table de données, insertions, mises à jour, suppressions et modifications de structure de la base de données, ainsi que l'attribution et la révocation de droits et l'import/export. Ce système permet de sauvegarder commodément une base de données sous forme de fichier .sql et d'y transférer ses données, même sans connaître SQL.
Pour en savoir plus, et connaître notamment la dernière version active : https://www.phpmyadmin.net/
(Source : wikipedia.org)
Tout d'abord on réactive notre premier virtualhost :
sudo a2ensite example.com
sudo systemctl reload apache2
cd /var/www/example
On télécharge le package all-languages.tar.gz
dans le dossier racine de notre site. Pour cela, récupérez le lien complet de la version ici : https://www.phpmyadmin.net/downloads/ (ou bien vérifiez la version et modifiez au besoin ci-dessous)
La version utilisée pour ce TP est 5.2.1, ce qui donne :
sudo wget https://files.phpmyadmin.net/phpMyAdmin/5.2.1/phpMyAdmin-5.2.1-all-languages.tar.gz
La dernière version 5.2.2 pose un problème connu au niveau de l'export des bases de données, ce dont nous aurons besoin plus loin. Il faut donc bien utiliser ici la version 5.2.1 !
On extrait le dossier archivé :
sudo tar -xvzf phpMyAdmin-5.2.1-all-languages.tar.gz
On renomme le dossier créé avec un nom plus simple (phpMyAdmin) :
sudo mv phpMyAdmin-5.2.1-all-languages phpMyAdmin
On se connecte au shell SQL :
sudo mysql -u root
On crée pour phpMyAdmin un utilisateur avec tous privilèges sur toutes les bases de données (login pma, mot de passe pmapass) :
GRANT ALL PRIVILEGES ON *.* TO 'pma'@'localhost' IDENTIFIED BY 'pmapass';
Mise à jour :
FLUSH PRIVILEGES;
et on quitte :
EXIT;
Rendez-vous maintenant sur votre navigateur, pour accéder à la page web de phpMyAdmin (attention à la casse) :
Connectez-vous avec les identifiants définis (pma, pmapass) : on peut désormais gérer (avec de grands pouvoirs !) les différentes bases de données du notre serveur :
Cependant des erreurs demeurent, selon les messages en bas de la page :
sudo apt install php-mbstring
puis rafrâichir la page.
/var/www/html/phpMyAdmin
appartient à root
et non par à www-data
; on corrige ainsi :cd /var/www/example
sudo chown -R www-data:www-data phpMyAdmin
On rafraîchit la page, ce problème a normalement disparu.
On a de nouveau quelques avertissements sur des extensions absentes. Installons-les :
sudo apt -y install php-bz2 php-zip
Et rafraîchissons la page :
Depuis cette page, afin de générer le fichier de configuration, sélectionner le français par défaut, les autres paramètres peuvent être laissés par défaut.
D’autres onglets (barre de menu latérale) permettent une configuration plus fine, mais nous pouvons laisser les paramètres par défaut, pour notre cas actuel.
Le bouton télécharger vous permet de récupérer le fichier de configuration config.inc.php
sur la machine cliente.
Nous allons utiliser SSH pour transférer ce fichier sur le serveur, avec la commande scp intégrée, qui doit être lancée depuis un terminal de la machine cliente, selon ce schéma :
scp chemin/local/fichier-envoi user@192.168.1.x:chemin/de/réception/
Ce qui donne ici :
scp /home/$(whoami)/Téléchargements/config.inc.php pascal@192.168.1.10:~/
Le fichier de configuration est transféré de préférence dans le répertoire home
du compte ssh du serveur (~), pour des raisons de droits d’accès. On ne pourrait pas le copier directement à l’emplacement définitif.
Pour ce faire, on le déplace depuis le serveur cette fois (avec sudo
) au bon endroit :
sudo mv ~/config.inc.php /var/www/example/phpMyAdmin
puis on réattribue la propriété du fichier à l’utilisateur www-data
:
sudo chown www-data:www-data /var/www/example/phpMyAdmin/config.inc.php
Une fois le fichier de configuration en bonne place, la page phpMyAdmin de doit plus présenter de problème (après reconnexion) :
Dans le prochain TP, nous allons déployer un serveur web basé sur NGINX, sur lequel nous allons restaurer les sites web que nous venons de créer. Il nous faut donc sauvegarder les bases de données et le contenu des dossiers web.
Grâce à phpMyAdmin, on effectue un dump de chacune des bases de données example_db et phpmyadmin, via l’outil exporter
Attention à ajouter l’option pour inclure la création de la base de données (pour voir les options, il faut choisir l’export personnalisé) :
En cliquant sur le bouton exporter, on télécharge un fichier dump de la base de données. Faire ceci pour les deux bases mentionnées ci-dessus.
Nous allons maintenant archiver et compacter tout le répertoire de notre site (/var/www/example
), en prenant soin de supprimer d'abord les fichiers téléchargés pour les installations :
cd ~
sudo rm /var/www/example/*.tar.gz
sudo tar -cvzf example.tar.gz /var/www/example
Puis depuis le client, on lance la récupèration de l’archive :
scp pascal@192.168.1.10:~/example.tar.gz ~/Téléchargements
Désormais, nous disposons d’une sauvegarde de nos sites sur la machine cliente (GUI), dans le dossiers Téléchargements :