C’est quoi une stack LEMP ?
LEMP est un acronyme pour
- Linux
- Nginx (se prononce Engine X)
- MariaDB ou MySQL
- PHP
Une stack est un ensemble de logiciels ’empilés’ les uns sur les autres. Ici, le logiciel le plus proche de la machine, le système d’exploitation GNU/Linux est le premier élément de cette pile. Vient ensuite Nginx qui est un serveur web. Nginx se base sur le réseau et le système de fichiers gérés par Linux pour répondre aux requêtes HTTP du client (le visiteur de votre site). Quand il rencontre un script PHP, Nginx passe la main à l’interpréteur PHP via le protocole FastCGI. PHP lui même fait appel à MariaDB pour le stockage de données structurées. Cet ensemble de logiciels se empilés forme la stack LEMP.
Dans ce tutoriel, nous allons utiliser Ansible pour installer et configurer cette stack automatiquement sur Debian 11.
Installation de Nginx
Comme l’installation de la stack LEMP est succinte, nous allons utiliser un playbook Ansible qui contiendra tout le code. Dans un article suivant, nous verrons découper ce playbook en rôles quand sa complexité devient trop grande.
--- - name: Installation et configuration d'une stack LEMP hosts: serveur_debian_test become: yes tasks: - name: Installation du serveur web Nginx apt: name: nginx update_cache: yes
La première tâche que nous venons d’ajouter au playbook installe Nginx avec apt. Nous n’avons pas encore configuré PHP sur notre serveur, car il dépend de la configuration PHP-FastCGI que nous allons réaliser. Voyons la configuration du serveur par défaut /etc/nginx/sites-enabled/default installée avec le paquet Nginx:
server { listen 80 default_server; listen [::]:80 default_server; root /var/www/html; index index.html index.htm index.nginx-debian.html; server_name _; location / { try_files $uri $uri/ =404; } # pass PHP scripts to FastCGI server # #location ~ \.php$ { # include snippets/fastcgi-php.conf; # # # With php-fpm (or other unix sockets): # fastcgi_pass unix:/run/php/php7.4-fpm.sock; # # With php-cgi (or other tcp sockets): # fastcgi_pass 127.0.0.1:9000; #} }
La racine de ce site par défaut est située /var/www/html. Nous allons utiliser cette configuration par la suite. La configuration par défaut comporte aussi une prise en charge des urls finissant par .php. Nous allons décommenter ces lignes une fois que le serveur PHP FastCGI sera installé et disponible pour que Nginx sous-traite l’exécution des scripts PHP par le serveur PHP-FastCGI.
Installation de PHP et du serveur FastCGI
--- - name: Installation et configuration d'une stack LEMP hosts: conteneur_test become: yes tasks: - name: Installation du serveur web Nginx apt: name: nginx update_cache: yes - name: Installation de l'interpréteur PHP et de ses modules apt: name: - php # interpréteur PHP - php-fpm # serveur FastCGI pour PHP - php-mysql # Paquet pour utiliser MySQL ou MariaDB avec PHP
De la même façon, une configuration par défaut du serveur FastCGI a été installée avec le paquet php-fpm dans le fichier /etc/php/7.4/fpm/pool.d/www.conf. Le serveur par défaut est configuré pour lancer PHP en tant qu’utilisateur www-data et écoutera les requêtes sur le socket unix situé /run/php/php7.4-fpm.sock d’après les lignes suivantes de la configuration:
listen = /run/php/php7.4-fpm.sock user = www-data group = www-data
On va maintenant lancer le serveur PHP FastCGI:
- name: Lancement du serveur PHP FastCGI service: name: php7.4-fpm state: started
Configuration de Nginx pour utiliser PHP
Le serveur FastCGI qui va nous permettre de lancer notre script PHP est maintenant prêt. On peut décommenter la configuration de PHP-FastCGI dans le serveur Nginx par défaut, et activer l’utilisation de PHP-FastCGI pour le traitement des scripts PHP. On obtient la configuration suivante:
server { listen 80 default_server; listen [::]:80 default_server; root /var/www/html; # Add index.php to the list if you are using PHP index index.html index.htm index.php index.nginx-debian.html; server_name _; location / { # First attempt to serve request as file, then # as directory, then fall back to displaying a 404. try_files $uri $uri/ =404; } # pass PHP scripts to FastCGI server # location ~ \.php$ { include snippets/fastcgi-php.conf; # With php-fpm (or other unix sockets): fastcgi_pass unix:/run/php/php7.4-fpm.sock; # With php-cgi (or other tcp sockets): # fastcgi_pass 127.0.0.1:9000; } }
On stocke cette configuration dans le fichier default dans le même répertoire que le playbook Ansible.
On ajoute le démarrage du serveur Nginx ainsi que la copie de la configuration du serveur par défaut au playbook:
- name: Configuration du serveur Nginx copy: src: default dest: /etc/nginx/sites-available/default - name: Lancement du serveur Nginx service: name: nginx state: started
Installation de MariaDB
Il ne reste plus qu’à installer la base de données MariaDB pour compléter notre stack.
Nous allons également créer un superutilisateur dont le nom et le mot de passe seront stockés dans les variables mariadb.root_user et mariadb.root_password pour pouvoir accéder à la base de données via PHP.
--- - name: Installation et configuration d'une stack LEMP hosts: conteneur_test become: yes vars: mariadb: root_user: tutoriel root_password: tutoriel database: tutoriel_lemp
En plus de l’installation de la base, on va installer le SDK Python de MySQL/MariaDB. Cette librairie permet de communiquer avec ces bases de données en utilisant Python. Dans notre cas, on va avec cette librairie et le rôle community.mysql.mysql_user créer un utilisateur MariaDB. Ensuite, on créera la base de données utilisée lors de ce tutoriel.
La collection de rôles Ansible community.mysql n’est pas installée par défaut. Nous allons l’ajouter à l’aide d’Ansible galaxy:
ansible-galaxy collection install community.mysql
Voici le code à ajouter au playbook:
- name: Installation de la base de données MariaDB apt: name: mariadb-server - name: Lancement de la base de données service: name: mariadb state: started enabled: yes - name: Installation du SDK de la base de données pip: name: PyMySQL - name: Création d'un utilisateur avec tous les privilèges community.mysql.mysql_user: name: "{{ mariadb.root_user }}" password: "{{ mariadb.root_password }}" plugin: mysql_native_password priv: '*.*:ALL,GRANT' state: present login_unix_socket: /var/run/mysqld/mysqld.sock - name: Sauvegarde de l'identifiant de cet utilisateur template: src: my.cnf.j2 dest: /root/.my.cnf owner: root group: root mode: '0600' - name: Création d'une base de données community.mysql.mysql_db: name: "{{ mariadb.database }}" state: present
Script PHP de démo
On va ajouter un script PHP qui va se connecter à la base et compter le nombre de visites de ce script pour tester la stack. Voici le script que nous allons utiliser:
<?php // Connection à la base de données $pdo = new PDO( 'mysql:host=localhost;dbname={{ mariadb.database }}', '{{ mariadb.root_user }}', '{{ mariadb.root_password }}' ); // Incrémentation du compteur de visites $pdo->query("CREATE TABLE IF NOT EXISTS `visites`(id int PRIMARY KEY AUTO_INCREMENT, at DATETIME DEFAULT CURRENT_TIMESTAMP())"); $pdo->query("INSERT INTO `visites` VALUES ()"); // Récupération du nombre total de visites $statement = $pdo->query("SELECT COUNT(*) as total_visites FROM `visites`"); $row = $statement->fetch(PDO::FETCH_ASSOC); echo 'Nombre de visites total de /test.php: '. $row['total_visites']; ?>
Ce script PHP contient des variables Jinja2 comme {{ mariadb.database }} qui vont permettre de paramétriser l’utilisateur/mot de passe ainsi que la base de données utilisée par PHP. Pour refléter cela, nous allons mettre deux extensions au fichier PHP contenant des variables Jinja: test.php.j2. Le module template permet à Ansible de transformer la template de script PHP en script PHP puis de le copier vers le serveur distant (ici dans le fichier /var/www/html/test.php).
On place ce script à la racine de notre serveur de test, et on ajoute le programme cURL qui va nous permettre de faire des requêtes HTTP au serveur
- name: Ajout du script PHP de test à la racine template: src: test.php.j2 dest: /var/www/html/test.php owner: www-data group: www-data mode: '0644' - name: Installation de cURL apt: name: curl
Il est maintenant possible d’utiliser cURL à l’intérieur du conteneur de test afin de récupérer la page /test.php en HTTP, voici le résultat:
docker exec conteneur_test curl -s http://localhost/test.php # Résultat (ici, 17 visites au total): # Nombre de visites total de /test.php: 17
Conclusion
Vous pouvez retrouver les sources du projet complet sur ce site. Lancez la construction du conteneur de test avec ./conteneur-test.sh. Puis exécutez le playbook avec ansible-playbook -i hosts playbook.yml. Ansible devra bien sûr être préalablement installé sur votre machine.
La configuration de la stack LEMP de cette article devra être
améliorée pour correspondre à vos besoins. J’espère que cette première
approche vous a permis d’avoir un aperçu de la conception d’une stack
LEMP.
Installer et configurer une stack LEMP avec Ansible