[TUTO] Installation d'un serveur « LAMP » (Linux-Apache-MySQL-PHP) pour le développement sur Debian GNU/Linux 11 « Bullseye »

Installation d’un serveur « LAMP » (Linux-Apache-MySQL-PHP) pour le développement sur Debian GNU/Linux 11 « Bullseye » v1.1

Conventions:

  • « $ » est une commande exécutée en environnement utilisateur non-root

  • « # » est une commande exécutée en environnement utilisateur « root » (remplaçable par un « sudo » si vous préférez)

  • je pars du principe que l’installation se fait sur un système fraîchement installé, avec les options par défaut et que vous n’êtes pas allergique au terminal

Dans ce tuto, pas de bla-bla inutile, les blagues les plus courtes sont les meilleures, c’est parti!

Comme d’habitude on commence par avoir un OS à jour:

# apt-get update && apt-get upgrade

(et on valide les mises à jour s’il y en a – ancienne méthode pour les vieux)

  • OU BIEN -

# apt update && apt full-upgrade

(et on valide toujours les mises à jour s’il y en a – nouvelle méthode pour les djeuns )

Le « L » (Linux):

Si vous êtes arrivés là, c’est que c’est déjà fait (voir « Conventions » plus haut)

Le « M » (MySQL):

On installe :

# apt-get install default-mysql-server default-mysql-client

  • OU BIEN -

# apt install mariadb-server

(ça marche aussi car en fait « default-mysql-server » c’est « mariadb-server » sous Bullseye)

On check :

# systemctl status mysql

  • OU BIEN -

# systemctl status mariadb

Ça doit indiquer en vert « active (running) », si c’est pas le cas :

# systemctl start mysql

  • OU BIEN -

# systemctl start mariadb

On sécurise un peu :

# mysql_secure_installation

On entre le mot de passe « root » pour MySQL (donc pas celui du système !) et on le confirme (et surtout on le note ou on le retient!)

On répond « Y » aux questions

On autorise les connexions réseau :

# nano /etc/mysql/mariadb.conf.d/50-server.cnf

→ F6 : on cherche « bind-address » : on remplace « 127.0.0.1 » par « 0.0.0.0 »

→ F6 : on cherche « skip-network » et si on le trouve, on le supprime la ligne

→ on enregistre (ctrl+o et Enter) et on quitte (ctrl+x)

# systemctl restart mysql

  • OU BIEN -

# systemctl restart mariadb

On se logge :

# mysql -u root -p

et on tape le mot de passe « root » pour mysql (et on valide !)

On crée la base « app1 » :

CREATE DATABASE app1 ;

On crée l’utilisateur et l’accès à la base :

GRANT ALL ON app1. TO ‘user’@’domaine.org’ IDENTIFIED BY ‘userpassword’ ;*

(remplacer « user » par un nom d’utilisateur de votre choix mais toujours le même (exemple : DarkGagan), « userpassword » par un mot de passe pour cet utilisateur de la base de données (pas celui de votre login système!) et « domaine.org » par celui qui n’existe pas de votre choix)

On actualise :

FLUSH PRIVILEGES ;

On quitte :

\q

Le « A » (Apache) :

On installe :

# apt-get install apache2 libapache2-mod-php

On check :

# systemctl status apache2

Ça doit indiquer en vert « active (running) », si c’est pas le cas :

# systemctl start apache2

Le « P » (PHP) :

On installe :

# apt-get install php php-common

On check la version :

$ ls /etc/php/ ou $ php -v

(on note ou on retient la version, ici « 7.4 »)

On installe des modules :

# apt-get install php-cli php-curl php-dev php-gd php-gmp php-imagick php-imap php-intl php-json php-mbstring php-mysql php-soap php-sqlite3 php-xml php-xmlrpc php-zip php7.4-opcache

# systemctl restart apache2

Les modules d’Apache :

La liste de ceux disponibles :

$ ls /etc/apache2/mods-available/

On en active ? :

# /sbin/a2enmod rewrite

# /sbin/a2enmod deflate

# /sbin/a2enmod headers

# systemctl restart apache2

Lesquels sont actifs ? :

# /sbin/a2query -m

On en désactive ? :

# /sbin/a2dismod nommodule

La config’ de PHP :

# nano /etc/php/$(ls /etc/php/)/apache2/php.ini

→ F6 : on cherche « upload_max_filesize » : on modifie à « 32M »

→ F6 : on cherche « post_max_size » : on modifie à « 48M »

→ F6 : on cherche « memory_limit » : on modifie à « 256M » (512 si vous avez 8 Go RAM ou +)

→ F6 : on cherche « max_execution_time » : on modifie à « 600 »

→ F6 : on cherche « max_input_vars » : on décommente

→ F6 : on cherche « max_input_time » : on modifie à « 1000 »

→ F6 : on cherche « error_reporting » : on modifie à « E_ALL | E_STRICT »

→ F6 : on cherche « display_errors » : on modifie à « on » et on décommente

→ F6 : on cherche « date.timezone » : on modifie selon votre fuseau horaire et on décommente

→ F6 : on cherche « phar.readonly » : on modifie à « Off » et on décommente

→ on enregistre (ctrl+o et Enter) et on quitte (ctrl+x)

La config’ d’Apache :

# nano /etc/apache2/envvars

→ F6 : on cherche « www-data » : on remplace par votre user non-root système

(à « APACHE_RUN_USER » et « APACHE_RUN_GROUP »)

→ on enregistre (ctrl+o et Enter) et on quitte (ctrl+x)

# systemctl restart apache2

# /sbin/a2dissite 000-default

# /sbin/a2dissite default-ssl

# systemctl reload apache2

Le dossier de stockage des sites :

On le crée :

$ mkdir /home/${USER}/votrenomdedossierdestockage

(évidemment, vous remplacez « votrenomdedossierdestockage » par ce que vous voulez mais vous notez ou retenez et utilisez toujours le même)

On crée aussi le sous-dossier des journaux :

$ mkdir /home/${USER}/votrenomdedossierdestockage/apache2logs

On attribue les droits :

# chmod -R 755 /home/${USER}/votrenomdedossierdestockage

On crée la page de démo pour l’hôte virtuel à venir :

$ cp var www/html/index.html /home/${USER}/votrenomdedossierdestockage

L’hôte virtuel :

On le crée :

# cp /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/user.conf

(« user » est le même que dans « GRANT ALL ON app1.* TO ‘user’@’domaine.org’ IDENTIFIED BY ‘userpassword’ ; » plus haut)

# nano /etc/apache2/sites-available/user.conf

(on modifie les lignes existantes et on ajoute celles qui n’y sont pas, en respactant l’indentation)

→ ServerAdmin user@domaine.org

(idem pour « domaine.org », le même que plus haut)

→ DocumentRoot /home/votreloginsystème/votrenomdedossierdestockage

(remplacer « votreloginsystème » par… votre login système, pas « root »)

→ ServerName domaine.org

(idem pour « domaine.org », le même que plus haut)

→ ServerAlias www.domaine.org

(idem pour « domaine.org », le même que plus haut)

→ <Directory /home/votreloginsystème/votrenomdedossierdestockage>

(idem remplacer votre login système et votre dossier de stockage de vos futurs sites)

→ Options Indexes FollowSymLinks

→ Require all granted

→ AllowOverride All

→ ErrorLog /home/votreloginsystème/votrenomdedossierdestockage/apache2logs/error.log

→ CustomLog /home/votreloginsystème/votrenomdedossierdestockage/apache2logs/access.log combined

→ on enregistre (ctrl+o et Enter) et on quitte (ctrl+x)

On l’active :

# /sbin/a2ensite user.conf

(on remplace « user » par le même définit plus haut)

# systemctl reload apache2

On check :

# /sbin/a2query -s

(doit indiquer « user », le même définit plus haut)

On chope l’IP du serveur local :

# ip address

(repérer « inet 192.168.x.y/24… » et noter ou retenir le « 192.168.x.y »)

On le fait reconnaître par le système :

# nano /etc/hosts

(on ajoute les lignes ci-après)

→ 192.168.x.y domaine.org

(on remplace par les données définies plus haut)

→ 192.168.x.y www.domaine.org

(on remplace par les données définies plus haut)

→ on enregistre (ctrl+o et Enter) et on quitte (ctrl+x)

# systemctl reload apache2

La fin du cambouis :

On redémarre le PC.

Crash-test :

On crée dans /home/votreloginsystème/votrenomdedossierdestockage/ 2 fichiers (avec geany, mousepad, kwrite, gedit, etc… bref, un éditeur de texte) :

  • phpinfo.php :
<?php phpinfo() ; ?>

(on enregistre et on quitte)

  • testdb.php :

< ?php

$host = ‘’domaine.org’’ ; [définit plus haut]

$user = ‘’user’’ ; [définit plus haut]

$pass = ‘’userpassword’’ ; [définit plus haut]

$db = ‘’app1’’ ;

try {

$conn = new PDO(‘’mysql:host=$host;dbname=$db ‘’,$user,$pass) ;

$conn-> setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION) ;

echo ‘’Connected successfully’’ ;

} catch(PDOException $e) {

echo ‘’Connection failed : ‘’.$e-> getMessage() ;

}

?>

(on enregistre et on quitte)

On teste :

Dans un navigateur (Chromium ou Firefox, les plus répandus), taper dans la barre d’adresse :

→ http://[www.]domaine.org/

(doit afficher la page Apache « It works ! »)

→ http://[www.]domaine.org

(doit afficher la page d’informations sur la version de PHP installée)

→ http://[www.]domaine.org

(doit afficher le message « Connected successfully »)

On efface les tests s’ils ont été fonctionnels :

$ rm /home/votreloginsystème/votrenomdedossierdestockage/testdb.php

# mysql -u root -p

et on tape le mot de passe « root » pour mysql (et on valide !)

SHOW DATABASES ;

(vérifier si la base de données « app1 » est présente)

DROP DATABASE app1 ;

(efface la base de données « app1 »)

SELECT User,Host FROM mysql.user ;

(vérifier si « user » existe sur « localhost »)

DROP USER ‘user’@’localhost’’ ;

(pour effacer « user » définit plus haut du « localhost »)

That’s all folks :

« Et Voilà », vous êtes prêts à coder vos sites dans votre dossier « votrenomdedossierdestockage » avec votre « user » et son « userpassword » et les visualiser avec votre « domaine.org ».

Ce tuto a été réalisé en cross-reading de plusieurs autres :

Merci à leurs auteur(e)s pour le travail effectué.

Merci aussi à @anon70622873 sur debian-fr.org pour ses relectures et propositions de corrections.

NOTE: le *.pdf de ce tuto est disponible ici: Tuto_LAMP_Bullseye_v11_by_DarkGagan ou bien sur demande :wink:
Si vous avez des commentaires ou voulez proposer des améliorations etc… n’hésitez pas, je peaufinerai.

Je propose une relecture critique point par point.

Avoir un système à jour :
# apt update && apt full-upgrade

Installer le serveur MariaDB (qui est le serveur MySQL par défaut sous Debian) :
# apt install mariadb-server

Vérifier son bon fonctionnement :
$ systemctl status mariadb

NON !
Depuis plusieurs versions l’utilisateur « root » de MariaDB s’authentifie via son compte UNIX et non par mot de passe (plugin unix_socket et non mysql_native_password). C’est très pratique, notamment pour les scripts de sauvegarde ou de maintenance et c’est très sécurisé. Si on a besoin d’un utilisateur MySQL pour administrer toutes les bases on le crée avec un mot de passe très fort et on lui attribue tous les privilèges sur toutes les bases.

NON !
On ne fait cela que si l’on a besoin d’accéder au serveur MySQL depuis une autre machine du réseau . Et encore généralement on ne met que l’interface locale sur une adresse privée en écoute. Ce n’est absolument pas sécurisé car tout le trafic entre le client et le serveur circule en clair.

Non, comme on a pas utilisé mysql-secure-installation, on se connecte direcerment à laconsole mysql en tant quèe « root » avec :
sudo mysql

Pour le reste OK, me si il me semble que flush privileges est devenu inutile.

Pour l’installation d’Apache et PHP autant le faire en une seule commande :
apt install apache2 php libapache2-mod-php
Ceci si on veut utiliser le module mod_php d’Apache pour interpréter le PHP. Una alternative plus puissante et plus performante (en prod) est php-fpm.

NON.
Avec cette commande tu ne vérifie que la version de l’interpréteur PHP en ligne de commande (php-cli). Pour vérifier la version utilisée par le serveur web, on peut créer un fichier info.php contenant :

<?php
phpinfo();

et l’appeler avec un navigateur web.

Il y a encore des erreurs et des imprécisions dans la suite mais j’ai la flemme :wink:

@anon70622873

OK, c’est plus récent

J’ai mis « default-mysql-server » mais ça marche aussi

pour avoir testé, avec « mysql » au lieu de « mariadb » ça fonctionne aussi et je trouve que ça déroute moins, j’ajoute quand même

Là je préfère « rajouter des mots de passe » et séparer le compte unix de mariadb

Je fais ça pour ensuite définir son « domaine » local (genre « monsupertruc.org/monsite2/mapageentest.html ») au lieu de taper "localhost/nianiania/mapage.html. Pour du développement, la sécurité n’est pas la première priorité mais déjà d’avoir un truc qui tourne et de faire des tests, c’est pour ça que j’abaisse un peu les barrières, on reste sur un réseau local

J’ai séparé pour juste suivre le « LAMP ». Ok même pas dans le même ordre mais j’ai voulu « une lettre, un paragraphe » :wink:

C’est la méthode utilisée à la fin mais là je cherchais un moyen simple pour avoir la version de type « 7.3 », « 8.1 » etc, pas « 7.4.1592.15556afvfd » (je déconne c’est bidon là, pour l’exemple)

Je modifie le premier post pour le tuto complet, pour pas avoir 36 fois le même pavé ^^

Merci pour les remarques, n’hésitez pas si d’autres choses ne vont pas, sont manquantes, etc… le but c’est de construire un truc bien :wink: