Aller au contenu
Réussir mon BTS SIO

Tape une notion, une commande ou le nom d'une épreuve.

Par exemple

Chapitre 719 minIntermédiaire

Déployer GLPI avec Nginx, PHP-FPM et MariaDB

Par Josselyn C., prof de BTS SIO. Mis à jour le .

À la fin de ce chapitre, tu sauras

  • déployer GLPI avec Nginx, PHP-FPM et MariaDB selon les recommandations de l'éditeur ;
  • isoler l'application avec un compte et un pool dédiés ;
  • relier GLPI à l'annuaire en LDAPS ;
  • mener et documenter la recette d'un déploiement ;
  • mettre à jour GLPI sans toucher aux données.

3 exercices corrigés

Déployer une application web, c'est assembler sur un serveur tout ce qu'elle demande (un serveur web, PHP, une base de données, un certificat, des tâches planifiées, un annuaire pour les comptes) puis la livrer prête à l'emploi, testée et documentée. Ce chapitre déroule le déploiement complet de GLPI 12, l'outil de gestion de parc et d'assistance, sur srv-glpi avec Nginx, PHP-FPM et MariaDB, en réutilisant tout ce que les chapitres 2 à 6 ont installé. C'est le type même de réalisation qu'on présente à l'épreuve E6 SISR. L'utilisation de GLPI (parc, tickets, inventaire) est l'objet du cours GLPI et gestion de parc, qui détaille aussi l'installation avec Apache.

Le cahier des charges

Sorbier remplace son outil de tickets par GLPI. Antoine Mercier fixe les exigences :

ExigenceRéponse techniqueChapitre
Accessible aux salariés à l'adresse https://glpi.ad.sorbier.exampleAlias DNS, Nginx, certificat de Sorbier-AC2, 6
Connexion avec le compte Windows de chaque salariéAnnuaire Active Directory en LDAPS7, 8
Données sur le serveur, base dédiée, compte limitéMariaDB local, compte glpi5
GLPI isolé des autres servicesPool PHP-FPM et compte système dédiés4
Notifications par courrielRelais Postfix local11
Sauvegarde quotidienne, restauration testéemariadb-dump et copie des fichiers vers srv-partages5, 9
Journaux conservés hors du serveurAgent Wazuh, syslog vers srv-journaux12

Le serveur : Debian 13, 2 processeurs virtuels, 4 Go de mémoire, 40 Go de disque, préparé comme au chapitre 1. GLPI 12.0.1, la version courante en novembre 2026, demande au moins PHP 8.3 et MariaDB 10.11 : les versions de Debian 13 (PHP 8.4, MariaDB 11.8) conviennent.

Étape 1 : le DNS et les paquets

Sur un contrôleur de domaine, ajoute l'alias. Les utilisateurs taperont le nom du service, glpi, et non celui du serveur : le jour où GLPI change de machine, seul l'alias change.

powershell
Add-DnsServerResourceRecordCName -ZoneName "ad.sorbier.example" -Name "glpi" `
    -HostNameAlias "srv-glpi.ad.sorbier.example"

Sur srv-glpi, installe la pile et les extensions PHP que GLPI exige ou recommande :

bash
sudo apt install nginx mariadb-server php8.4-fpm php8.4-cli \
  php8.4-curl php8.4-gd php8.4-intl php8.4-mysql php8.4-xml php8.4-mbstring \
  php8.4-bcmath php8.4-zip php8.4-bz2 php8.4-ldap

Les autres extensions demandées par GLPI (fileinfo, filter, session, zlib, openssl, ctype, iconv, sodium, exif) sont déjà compilées dans le PHP de Debian, et OPcache est installé avec PHP-FPM.

Étape 2 : la base et son compte

Sécurise MariaDB, puis crée la base glpi, le compte glpi@localhost et charge les fuseaux horaires, comme au chapitre 5 :

bash
sudo mariadb-secure-installation
sudo mariadb <<'SQL'
CREATE DATABASE glpi CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'glpi'@'localhost' IDENTIFIED BY 'Mot-De-Passe-Long-Et-Unique';
GRANT ALL PRIVILEGES ON glpi.* TO 'glpi'@'localhost';
GRANT SELECT ON mysql.time_zone_name TO 'glpi'@'localhost';
SQL
mariadb-tzinfo-to-sql /usr/share/zoneinfo | sudo mariadb mysql

Étape 3 : télécharger GLPI et ranger ses dossiers

bash
cd /tmp
wget https://github.com/glpi-project/glpi/releases/download/12.0.1/glpi-12.0.1.tgz
sudo tar -xzf glpi-12.0.1.tgz -C /var/www/      # crée /var/www/glpi

Comme le recommande la documentation de GLPI, la configuration, les données et les journaux sortent du dossier de l'application, selon les conventions de Linux. Une erreur de configuration du serveur web ne pourra pas les exposer, et une mise à jour remplacera le code sans toucher aux données.

ContenuEmplacementConstante de GLPI
Application (code)/var/www/glpi—
Configuration, dont l'accès à la base et la clé de chiffrement glpicrypt.key/etc/glpiGLPI_CONFIG_DIR
Données : documents joints, cache, sessions/var/lib/glpi/filesGLPI_VAR_DIR
Plugins du marketplace/var/lib/glpi/pluginsGLPI_MARKETPLACE_DIR
Journaux/var/log/glpiGLPI_LOG_DIR
bash
sudo mkdir -p /etc/glpi /var/lib/glpi/files /var/lib/glpi/plugins /var/log/glpi
sudo cp -a /var/www/glpi/config/. /etc/glpi/
sudo cp -a /var/www/glpi/files/. /var/lib/glpi/files/

Deux petits fichiers indiquent à GLPI où chercher. /var/www/glpi/inc/downstream.php :

php
<?php
define('GLPI_CONFIG_DIR', '/etc/glpi/');

if (file_exists(GLPI_CONFIG_DIR . '/local_define.php')) {
    require_once GLPI_CONFIG_DIR . '/local_define.php';
}

et /etc/glpi/local_define.php :

php
<?php
define('GLPI_VAR_DIR', '/var/lib/glpi/files');
define('GLPI_MARKETPLACE_DIR', '/var/lib/glpi/plugins');
define('GLPI_LOG_DIR', '/var/log/glpi');

Le cours GLPI donne les mêmes étapes avec Apache, où l'application tourne sous www-data. Ici, GLPI aura son propre compte, glpi, utilisé par son pool PHP-FPM :

bash
sudo adduser --system --group --no-create-home --home /var/lib/glpi glpi
sudo chown -R root:root /var/www/glpi
sudo chown -R glpi:glpi /etc/glpi /var/lib/glpi /var/log/glpi
sudo chmod 750 /etc/glpi

Le code appartient à root : ni Nginx ni GLPI ne peuvent le modifier. Seul le compte glpi écrit dans la configuration, les données et les journaux, et lui seul lit la configuration (droits 750), qui contient le mot de passe de la base.

Étape 4 : le pool PHP-FPM de GLPI

/etc/php/8.4/fpm/pool.d/glpi.conf :

ini
[glpi]
user = glpi
group = glpi

listen = /run/php/php8.4-fpm-glpi.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

pm = dynamic
pm.max_children = 20
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 6
pm.max_requests = 500

; Réglages de sécurité des sessions demandés par GLPI
php_admin_flag[session.cookie_httponly] = on
php_admin_flag[session.cookie_secure] = on
php_admin_value[session.cookie_samesite] = Lax

php_admin_value[memory_limit] = 256M
php_admin_value[upload_max_filesize] = 20M
php_admin_value[post_max_size] = 20M
php_admin_flag[display_errors] = off
php_admin_value[error_log] = /var/log/glpi/php-errors.log
bash
sudo php-fpm8.4 -t && sudo systemctl reload php8.4-fpm
ls -l /run/php/php8.4-fpm-glpi.sock

pm.max_children = 20 reste sous le maximum de 25 calculé au chapitre 4 pour srv-glpi, avec une marge pour les pics de mémoire. Les réglages de session sont dans le pool plutôt que dans php.ini : ils ne concernent que GLPI, et l'application ne peut pas les modifier.

Étape 5 : le server block Nginx

GLPI publie une configuration officielle pour Nginx. Elle repose sur une idée forte : la racine du site est le dossier public, qui ne contient que index.php et des ressources statiques. Toutes les adresses de l'application passent par ce seul script, le routeur de GLPI ; le reste du code, la configuration et les données ne sont jamais accessibles par une adresse web.

/etc/nginx/sites-available/glpi :

nginx
server {
    listen 80;
    listen [::]:80;
    server_name glpi.ad.sorbier.example srv-glpi.ad.sorbier.example;
    return 301 https://glpi.ad.sorbier.example$request_uri;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;
    server_name glpi.ad.sorbier.example;

    ssl_certificate     /etc/ssl/glpi/glpi.crt;
    ssl_certificate_key /etc/ssl/glpi/glpi.key;
    add_header Strict-Transport-Security "max-age=31536000" always;

    root /var/www/glpi/public;
    client_max_body_size 20m;

    access_log /var/log/nginx/glpi.access.log;
    error_log  /var/log/nginx/glpi.error.log;

    location / {
        try_files $uri /index.php$is_args$args;
    }

    location ~ ^/index\.php$ {
        fastcgi_pass unix:/run/php/php8.4-fpm-glpi.sock;
        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}
BlocRôle
Premier serverToute requête en HTTP, ou adressée au nom du serveur, est redirigée vers l'adresse officielle en HTTPS
root /var/www/glpi/publicSeul le dossier public est servi
try_files $uri /index.php$is_args$argsUne ressource statique existante est servie par Nginx ; toute autre adresse va au routeur, avec ses paramètres
location ~ ^/index\.php$Seul index.php est transmis à PHP-FPM, et non n'importe quel fichier .php
client_max_body_size 20mLes pièces jointes des tickets, en cohérence avec upload_max_filesize du pool

Le certificat est celui obtenu de l'autorité interne au chapitre 6, pour les noms glpi.ad.sorbier.example et srv-glpi.ad.sorbier.example.

bash
sudo ln -s /etc/nginx/sites-available/glpi /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t && sudo systemctl reload nginx

Étape 6 : installer GLPI en ligne de commande

L'assistant web fonctionne (ouvre https://glpi.ad.sorbier.example et suis les écrans), mais la console est plus rapide, se documente mieux et se rejoue à l'identique. Elle se lance avec le compte de l'application, pour que les fichiers créés lui appartiennent ; depuis GLPI 11, elle refuse de tourner en root.

bash
cd /var/www/glpi
sudo -u glpi php bin/console system:check_requirements
sudo -u glpi php bin/console db:install -L fr_FR -H localhost -d glpi -u glpi -p
# -p sans valeur : la console demande le mot de passe, sans l'écrire dans l'historique du shell
sudo -u glpi php bin/console database:enable_timezones
sudo rm /var/www/glpi/install/install.php

system:check_requirements affiche chaque prérequis avec son état : tout doit être validé, sauf peut-être des recommandations facultatives. Si une extension manque, installe le paquet php8.4-… correspondant et recharge PHP-FPM. Supprimer install/install.php empêche quiconque de relancer une installation par-dessus ta base.

Étape 7 : les tâches planifiées

GLPI a des actions automatiques : envoi des notifications, alertes de contrats, calcul des délais, nettoyage. Elles doivent être lancées chaque minute par le système, avec le compte de l'application :

bash
sudo crontab -u glpi -e
text
* * * * * /usr/bin/php /var/www/glpi/front/cron.php

Puis, dans GLPI, Configuration > Actions automatiques : passe les actions en mode CLI. Sans cette tâche, aucune notification ne part (cours GLPI).

Étape 8 : relier GLPI à l'annuaire en LDAPS

Les salariés se connectent avec leur compte du domaine. GLPI interroge l'annuaire en LDAPS (LDAP chiffré en TLS, port 636) avec un compte de service en lecture seule, svc-glpi, créé dans l'annuaire avec un mot de passe long et sans aucun droit d'administration.

Deux conditions préalables : les contrôleurs de domaine présentent un certificat pour LDAPS (délivré par Sorbier-AC), et srv-glpi fait confiance à cette autorité (update-ca-certificates, chapitre 6). Teste avant de toucher à GLPI, avec les outils du paquet ldap-utils :

bash
sudo apt install ldap-utils
ldapwhoami -H ldaps://srv-ad.ad.sorbier.example -D "svc-glpi@ad.sorbier.example" -W
# u:SORBIER\svc-glpi
ldapsearch -H ldaps://srv-ad.ad.sorbier.example -D "svc-glpi@ad.sorbier.example" -W \
  -b "OU=Sorbier,DC=ad,DC=sorbier,DC=example" "(sAMAccountName=jlefevre)" cn mail

Si ldapwhoami répond Can't contact LDAP server, la cause est presque toujours le certificat (autorité inconnue, ou nom du contrôleur absent de son certificat) ou le pare-feu (TCP 636 de srv-glpi vers les contrôleurs). La bibliothèque LDAP de Debian, que PHP utilise aussi, lit le magasin de confiance du système (TLS_CACERT /etc/ssl/certs/ca-certificates.crt dans /etc/ldap/ldap.conf) : une fois ldapwhoami réussi, GLPI y arrivera.

La configuration dans GLPI se fait dans Configuration > Authentification > Annuaires LDAP, avec le bouton de préconfiguration Active Directory : serveur ldaps://srv-ad.ad.sorbier.example, port 636, base OU=Sorbier,DC=ad,DC=sorbier,DC=example, compte svc-glpi@ad.sorbier.example, champ de l'identifiant samaccountname, puis un second serveur, srv-ad2, en réplique. Le détail des champs, l'import des comptes et les règles d'habilitation sont dans le cours GLPI.

Étape 9 : la recette

Une installation n'est terminée que quand chaque exigence est vérifiée et prouvée. La recette de srv-glpi :

TestCommande ou actionRésultat attendu
Redirection vers HTTPScurl -sI http://glpi.ad.sorbier.example301 vers https://glpi.ad.sorbier.example/
Certificat valide sur un poste du domaineOuvrir l'adresse dans Edge sur un poste du VLAN 10Cadenas, aucun avertissement, émetteur Sorbier-AC
Code et configuration inaccessiblescurl -sI https://glpi.ad.sorbier.example/config/config_db.php et …/inc/downstream.php404 (ou page du routeur), jamais le contenu d'un fichier
Prérequis de GLPIsudo -u glpi php bin/console system:check_requirementsTous validés
Connexion avec un compte du domaineSe connecter en jlefevreAccès à l'interface simplifiée
Comptes par défautSe connecter en glpi / glpiRefusé : compte désactivé ou mot de passe changé
Actions automatiquesConfiguration > Actions automatiquesDernière exécution datée de moins de deux minutes
Isolementps -o user,cmd -C php-fpm8.4Processus du pool glpi sous le compte glpi
Base non exposéess -tlnp | grep 3306Écoute sur 127.0.0.1 seulement (ou l'adresse prévue au chapitre 5)
SauvegardeRestaurer la dernière sauvegarde dans une base de testBase complète, GLPI démarre sur la copie

N'oublie pas les gestes de sécurité de la première connexion, que GLPI rappelle par des bandeaux : désactiver ou changer les mots de passe des comptes glpi, tech, normal et post-only, renseigner l'URL de l'application (https://glpi.ad.sorbier.example) dans Configuration > Générale, activer la double authentification pour les administrateurs.

Mettre GLPI à jour

GLPI publie régulièrement des versions correctives, souvent pour des failles de sécurité (la 12.0.1 corrige notamment un contournement de l'authentification externe). Grâce au rangement de l'étape 3, une mise à jour remplace le dossier de l'application sans toucher aux données :

bash
# 1. Sauvegarde de la base et de la configuration
sudo mariadb-dump --single-transaction glpi | gzip > /var/backups/glpi-avant-maj.sql.gz
sudo tar -czf /var/backups/glpi-etc-avant-maj.tgz /etc/glpi
# 2. Remplacement du code
sudo mv /var/www/glpi /var/www/glpi-ancien
sudo tar -xzf glpi-12.0.2.tgz -C /var/www/
sudo cp /var/www/glpi-ancien/inc/downstream.php /var/www/glpi/inc/
sudo rm /var/www/glpi/install/install.php
# 3. Mise à jour du schéma de la base
cd /var/www/glpi && sudo -u glpi php bin/console db:update

12.0.2 est ici un exemple : prends la dernière version publiée sur la page du projet. La procédure complète (mode maintenance, plugins, retour arrière) est dans le cours GLPI.

Exercices

Exercice 1 sur 3 Le code source téléchargé Réussi À revoir

Un collègue a écrit le server block de GLPI en mettant root /var/www/glpi; au lieu de root /var/www/glpi/public;, avec un bloc location ~ \.php$ générique vers PHP-FPM. L'application semble fonctionner. Explique deux risques de cette configuration et la correction.

Voir la réponseMasquer la réponse de l'exercice 1

Risques.

  1. Tous les dossiers de l'application deviennent accessibles par une adresse web : /files/, /config/, /vendor/, /install/install.php si le fichier existe encore. Selon les fichiers présents, on peut télécharger des documents joints, des journaux, ou exécuter un script qui n'était pas prévu pour être appelé directement.
  2. N'importe quel fichier .php de l'arborescence est exécutable par une adresse, y compris des scripts d'outils de développement fournis dans vendor/. C'est exactement ce que la racine public et le routeur unique de GLPI évitent.

Correction. root /var/www/glpi/public;, le try_files $uri /index.php$is_args$args; du bloc /, et un seul bloc PHP, location ~ ^/index\.php$. Puis vérifier que curl -sI https://glpi.ad.sorbier.example/config/ ne renvoie plus rien d'autre que la réponse du routeur. Le rangement de l'étape 3 (configuration dans /etc/glpi, données dans /var/lib/glpi) est une seconde barrière : même avec une racine mal réglée, ces fichiers ne sont pas sous /var/www.

Tu avais trouvé ?

Exercice 2 sur 3 La console en root Réussi À revoir

Pressé, un technicien lance sudo php bin/console cache:clear au lieu de sudo -u glpi php bin/console cache:clear sur une ancienne version de GLPI qui l'acceptait encore. Depuis, des pages de GLPI affichent des erreurs. Explique pourquoi et comment corriger.

Voir la réponseMasquer la réponse de l'exercice 2

Lancée en root, la console a recréé des fichiers de cache (et peut-être de journaux) qui appartiennent à root. Les processus du pool, qui tournent sous glpi, ne peuvent plus les modifier ni les supprimer : les pages qui en ont besoin échouent.

Correction : rendre au compte glpi la propriété de ses dossiers, puis vider le cache avec le bon compte.

bash
sudo chown -R glpi:glpi /var/lib/glpi /var/log/glpi /etc/glpi
cd /var/www/glpi && sudo -u glpi php bin/console cache:clear

C'est la raison pour laquelle les versions récentes de la console refusent de tourner en root.

Tu avais trouvé ?

Exercice 3 sur 3 Préparer la recette Réussi À revoir

La commission d'E6 te demande de prouver, pendant l'oral, que GLPI chiffre la connexion à l'annuaire. Quelles preuves peux-tu montrer, sur le serveur et sur le réseau ?

Voir la réponseMasquer la réponse de l'exercice 3
  • La configuration : dans Configuration > Authentification > Annuaires LDAP, le serveur est ldaps://srv-ad.ad.sorbier.example, port 636.
  • Le test en ligne de commande : ldapwhoami -H ldaps://srv-ad.ad.sorbier.example -D "svc-glpi@ad.sorbier.example" -W répond u:SORBIER\svc-glpi ; la même commande avec un certificat inconnu (en retirant la racine du magasin, sur une maquette) échoue, ce qui prouve que le certificat est vérifié.
  • Les connexions établies : ss -tnp | grep 636 pendant une connexion d'utilisateur montre une connexion de srv-glpi vers 192.168.10.177:636, et aucune vers le port 389.
  • Une capture de trames : sudo tcpdump -i ens18 -nn host 192.168.10.177 and port 636 -w ldaps.pcap pendant une connexion, ouverte ensuite dans Wireshark : on voit une poignée de main TLS puis des données chiffrées (Application Data), sans aucun nom de compte ni mot de passe lisible. À comparer avec une capture sur le port 389 en maquette, où le mot de passe apparaît en clair dans la requête bindRequest.

Tu avais trouvé ?

Chapitre terminé !

Fais les 3 exercices avant de passer à la suite : c'est en t'entraînant que tout se fixe.

chapitres
–
de série
–
du cours
–
Chapitre suivant : Joindre un serveur Debian au domaine Active Directory avec realmd et SSSDRevoir le sommaire du cours