Nous avons mis à jour deux fois une copie d'un GLPI 11.0.11 vers la 12.0.0 : sous Docker avec l'image officielle, et sous Debian 13 avec l'archive .tgz. La migration de la base a pris environ 5 secondes dans les deux cas. Le travail est venu avant et après : MariaDB 10.6 a été refusé, les plugins ont été suspendus, les catégories de la base de connaissances sont devenues des articles que ni les techniciens ni les utilisateurs ne peuvent ouvrir, et le webhook a cessé d'envoyer, pour deux raisons différentes. Ce guide détaille les deux méthodes pas à pas et la correction de chaque problème, dans l'ordre où ils sont apparus.
Vous hésitez encore à faire la mise à jour ? Lisez d'abord GLPI 12 est sorti : ce qui change, prérequis et quand mettre à jour.
Ce que nous avons testé
Nous avons monté un GLPI 11.0.11 jetable avec les données fictives d'Acme : 120 tickets avec suivis et 40 tâches, un SLA, 9 articles de base de connaissances répartis dans 4 catégories aux permissions différentes, un webhook vers un serveur interne et trois plugins de la communauté (Fields, Tag et Data Injection), avec des données. Nous avons fait une sauvegarde et mis à jour vers la 12.0.0. Puis nous avons restauré la même sauvegarde sur un Debian 13 et refait la mise à jour avec l'archive .tgz.

| Élément | Résultat |
|---|---|
| Migration de la base (de 455 à 460 tables, de 47 à 49,5 Mo) | Environ 5 secondes, sans erreur, avec les deux méthodes |
| Tickets, suivis, tâches, valeurs des champs Fields et étiquettes | Tous conservés |
| Plugins (versions pour GLPI 11) | Suspendus puis désactivés : une nouvelle version est requise |
| Catégories de la base de connaissances | Devenues des articles sans permission (erreur 403 pour le technicien et l'utilisateur) |
| Webhook créé sous GLPI 11 | N'envoie plus : méthode « post » en minuscules et réseau interne bloqué |
Avant de commencer : les prérequis
| Élément | GLPI 11 | GLPI 12 |
|---|---|---|
| PHP | 8.2 à 8.5 | 8.3 à 8.5 |
| MariaDB | 10.6 ou plus récent | 10.11 ou plus récent |
| MySQL | 8.0 ou plus récent | 8.0 ou plus récent |
Deux points mis en évidence par le test :
- PHP 8.2 ne donne pas un avertissement, il donne une erreur de syntaxe. La console de GLPI 12 n'arrive même pas à la vérification des prérequis : elle s'arrête sur un « Parse error » dans un fichier de GLPI lui-même. Debian 12 et Ubuntu 22.04 sont livrés avec PHP 8.2 ou plus ancien. Debian 13 (PHP 8.4) et Ubuntu 24.04 (PHP 8.3) conviennent avec les paquets standard. L'image Docker officielle embarque déjà PHP 8.5.
- Vérifiez la base avant toute chose. Lancez
php bin/console system:check_requirementsavec le nouveau code pointé sur votre base. Sur notre MariaDB 10.6, la réponse a été claire : version non prise en charge, minimum 10.11.
Étape 0 : la sauvegarde (base, fichiers et clé)
Faites trois copies avant de toucher à quoi que ce soit : la base, le dossier des fichiers et le dossier de configuration. Le dossier de configuration contient glpicrypt.key. Sans lui, les mots de passe stockés par GLPI (collecteur de mails, LDAP, proxy, secrets des webhooks) ne peuvent plus être déchiffrés.
mariadb-dump --single-transaction --routines -u root -p glpi | gzip > glpi11-$(date +%F).sql.gz
tar czf glpi11-arquivos-$(date +%F).tgz /etc/glpi /var/lib/glpi/files /var/www/glpi/marketplace
Sous Docker avec l'image officielle, tout se trouve dans le volume monté sur /var/glpi (config, files, marketplace et logs) : copiez le volume entier. Dans notre test, le dump a pris 5 secondes et la copie du volume 8,5.
Méthode 1 : Docker avec l'image officielle
L'image officielle (glpi/glpi) met à jour la base toute seule quand elle démarre avec une nouvelle version. Il suffit de changer le tag et de démarrer le conteneur : aucune confirmation n'est demandée. C'est pourquoi la sauvegarde se fait avant le changement de tag, jamais après. Si vous préférez lancer la mise à jour à la main, démarrez avec GLPI_SKIP_AUTOUPDATE=true et utilisez la commande de la méthode 2.
1. Mettez à jour MariaDB si nécessaire. Avec MariaDB 10.6, le conteneur GLPI 12 s'est arrêté avec le code 128. Le journal a signalé des prérequis manquants, puis a écrit une phrase qui fait peur : « GLPI is not installed... Starting installation ». Il n'a rien installé. La base est restée intacte, en version 11.0.11, avec les 120 tickets. Il n'a simplement pas passé la vérification des prérequis. Le passage de MariaDB 10.6 à 10.11 a pris 22 secondes grâce à la variable de mise à jour automatique de l'image MariaDB. Démarrez d'abord la base seule (docker compose up -d db) et vérifiez le journal avant de continuer :
services:
db:
image: mariadb:10.11 # avant : 10.6
environment:
MARIADB_AUTO_UPGRADE: "1" # lance mariadb-upgrade au démarrage
glpi:
image: glpi/glpi:12.0.0 # avant : 11.0.11 (étape 2)
volumes:
- glpi-data:/var/glpi
2. Changez le tag et démarrez. docker compose up -d. Le journal affiche « GLPI is installed, and auto-update is enabled. Starting update... », puis le message de bienvenue. Dans le test, il s'est écoulé 17 secondes entre le up et le message de bienvenue dans le journal.
3. Vérifiez. docker compose exec glpi bin/console db:check doit répondre « Database schema is OK ».
Méthode 2 : Linux avec l'archive .tgz
Les commandes ci-dessous suivent l'arborescence de notre guide d'installation de GLPI 11 sous Debian et Ubuntu : code dans /var/www/glpi, configuration dans /etc/glpi et fichiers dans /var/lib/glpi/files.
cd /var/www/glpi && sudo -u www-data php bin/console maintenance:enable
cd /var/www && mv glpi glpi-11-antigo
wget https://github.com/glpi-project/glpi/releases/download/12.0.0/glpi-12.0.0.tgz
tar xzf glpi-12.0.0.tgz
cp glpi-11-antigo/inc/downstream.php glpi/inc/ # s'il existe
cp glpi-11-antigo/config/local_define.php glpi/config/ 2>/dev/null # s'il existe
cp -a glpi-11-antigo/marketplace/. glpi/marketplace/
chown -R www-data:www-data glpi
cd glpi
sudo -u www-data php bin/console system:check_requirements
sudo -u www-data php bin/console database:update
sudo -u www-data php bin/console maintenance:disable
Le fichier que tout le monde oublie : inc/downstream.php. C'est lui qui indique à GLPI que la configuration se trouve dans /etc/glpi. Il est rangé dans le dossier du code, donc il disparaît quand vous remplacez ce dossier. Dans le test, sans lui, database:update a répondu « Unable to connect to database ». Le message ne donne pas la vraie cause : GLPI a cherché la configuration au mauvais endroit. Une fois le fichier recopié, la mise à jour est passée tout de suite. Il en va de même pour config/local_define.php, si vous l'utilisez.
Si votre GLPI garde config et files dans /var/www/glpi, copiez aussi config/ et files/ depuis l'ancien dossier. C'était le cas sous Debian 13 (PHP 8.4) : la migration a pris 5 secondes et le db:check est ressorti propre.
Si la mise à jour de la base échoue
Sur le forum GLPI, le 3 novembre, une mise à jour de la 11.0.8 vers la 12.0.1 sous Debian 13 a bloqué : fichiers copiés, propriétaire et droits ajustés, puis maintenance:disable a renvoyé une erreur et la mise à jour de la base a échoué. Nous n'avons pas reproduit ce cas. Une réponse dans le fil a indiqué une cause probable, et le code de la migration confirme qu'elle est possible : en 11, la table qui relie les articles aux catégories de la base de connaissances accepte plusieurs fois le même couple article/catégorie ; la table qui la remplace en 12 ne l'accepte pas. Un seul lien en double suffit à arrêter la migration. Restaurez la sauvegarde de la 11 (la migration a pu s'arrêter en cours de route) et cherchez les doublons :
SELECT knowbaseitems_id, knowbaseitemcategories_id, COUNT(*) AS n
FROM glpi_knowbaseitems_knowbaseitemcategories
GROUP BY knowbaseitems_id, knowbaseitemcategories_id
HAVING n > 1;
Si une ligne ressort, supprimez les copies en gardant un lien par couple. L'article reste dans sa catégorie :
DELETE l1 FROM glpi_knowbaseitems_knowbaseitemcategories l1
JOIN glpi_knowbaseitems_knowbaseitemcategories l2
ON l1.knowbaseitems_id = l2.knowbaseitems_id
AND l1.knowbaseitemcategories_id = l2.knowbaseitemcategories_id
AND l1.id > l2.id;
Si la requête ne renvoie rien, la cause est ailleurs. Vérifiez que le dossier des fichiers et celui de la configuration (dans notre organisation, /var/lib/glpi/files et /etc/glpi) appartiennent à www-data, lancez system:check_requirements et lisez php-errors.log dans le dossier _log des fichiers ainsi que le journal d'erreurs du serveur web. Lancez database:update en ligne de commande, qui affiche l'erreur à l'écran, et seulement ensuite maintenance:disable.
Après la migration : ce qui a cassé et comment le corriger
1. Les plugins sont suspendus (et la commande de liste ne le montre pas)
Après la mise à jour, GLPI 12 suspend l'exécution de tous les plugins. plugin:list a continué d'afficher les trois comme « Enabled ». Mais le paramètre plugins_execution_mode valait « suspended_by_update », et aucun plugin ne s'exécutait. Pour les réactiver :
php bin/console plugin:resume_execution
À la réactivation, GLPI a vérifié les versions et a désactivé les trois (« Installed / not activated »). Les versions pour la 11 acceptent au maximum GLPI 11.0.99, et les versions pour la 12 exigent au minimum la 12.0.0. Autrement dit : impossible de mettre à jour ces plugins avant GLPI. D'abord GLPI, ensuite les plugins :
| Plugin | Version sous GLPI 11 | Version sous GLPI 12 |
|---|---|---|
| Fields (champs supplémentaires) | 1.24.6 | 1.25.0 |
| Tag | 2.14.8 | 2.15.0 |
| Data Injection | 2.15.12 | 2.16.0 |
Pour chacun : remplacez le dossier dans marketplace/ par la nouvelle version, puis lancez plugin:install et plugin:activate. Les données sont restées : les 5 valeurs du champ « Centre de coûts » de Fields et les 10 étiquettes de Tag étaient toujours là. Avant de fixer la date, vérifiez que tous vos plugins ont déjà une version pour la 12 (comment choisir ses plugins sans bloquer la mise à jour).
2. Les catégories de la base de connaissances deviennent des articles sans visibilité
GLPI 12 n'a plus de catégories dans la base de connaissances : les 4 catégories sont devenues 4 articles « parents », et un article racine (« Home ») a été créé au-dessus d'eux. Les 9 articles ont gardé leurs permissions. Mais les 4 articles qui étaient des catégories se sont retrouvés sans aucune règle de visibilité. Nous avons testé via l'API avec un technicien et un utilisateur Self-Service : tous les deux ont reçu une erreur 403 en ouvrant « Procédures », « Réseau », « Wi-Fi » et « FAQ utilisateur ». Chacun a continué à ouvrir uniquement les articles qu'il voyait déjà.
Correction : ouvrez chaque ancienne catégorie et donnez-lui le public qu'avait le dossier (entité, profil ou groupe). Sous GLPI 12, un article hérite de la visibilité des articles situés au-dessus de lui. Dans le test, ouvrir l'ancienne catégorie « FAQ utilisateur » à l'entité Acme a permis au technicien d'ouvrir le dossier et les deux articles qu'il contient, qui renvoyaient auparavant une erreur 403. Pour l'utilisateur Self-Service, il y a une étape de plus : il ne voit que les articles marqués FAQ, et les anciennes catégories arrivent sans cette marque. Avec la visibilité et la marque FAQ, le dossier est apparu pour lui aussi. Faites-le avant d'ouvrir le système aux utilisateurs.
3. Le webhook s'est arrêté : méthode « post » en minuscules
Le webhook créé sous GLPI 11 est entré dans la file d'attente et a échoué. Le journal webhook.log a donné la cause : Invalid HTTP method "post", only uppercase letters are accepted. GLPI enregistre la méthode en minuscules, et le client HTTP de la 12 n'accepte que les majuscules. Cela touche tous les webhooks, y compris ceux créés sous la 12. Le problème est signalé sur le GitHub de GLPI (issue 25883), avec un correctif proposé. Lors de notre test, le 16 octobre, le correctif n'était encore ni dans la 12.0.0 ni dans la version de développement de la 12.0.1.
En attendant le correctif, le contournement consiste à passer la méthode en majuscules directement dans la base (après une sauvegarde) :
UPDATE glpi_webhooks SET http_method = UPPER(http_method);
UPDATE glpi_queuedwebhooks SET http_method = UPPER(http_method);
Si quelqu'un enregistre à nouveau le webhook depuis l'interface, le champ repasse en minuscules. Relancez alors la commande, et suivez les notes de version des 12.0.x : une fois le correctif intégré, le contournement ne sera plus nécessaire.
4. Ensuite, le blocage du réseau interne
Avec la méthode corrigée, l'erreur a changé : Host "glpiup-hook" is blocked. GLPI 12 bloque par défaut les appels du serveur vers les réseaux privés (10.x, 172.16-31.x, 192.168.x). Cela concerne les webhooks, les calendriers externes, les flux RSS et la connexion à GLPI Network. Par défaut, seuls les appels vers l'agent d'inventaire et l'authentification externe restent autorisés. Si votre webhook pointe vers un n8n, un ERP ou une API du réseau interne, il va s'arrêter.
Pour n'autoriser que le nécessaire, créez le fichier config/local_define.php dans le dossier du code de GLPI :
<?php
define('GLPI_SERVERSIDE_URL_ALLOWED_PRIVATE_NETWORKS_CONTEXTS', [
\Agent::class, // par défaut
\Auth::class, // par défaut
\Webhook::class, // autorise les webhooks vers le réseau interne
]);
Le piège de Docker : GLPI lit ce fichier dans /var/www/glpi/config/, qui se trouve dans l'image, et non dans le volume /var/glpi/config. Placé dans le volume, le fichier n'a eu aucun effet. Monté en tant que fichier, il a fonctionné :
volumes:
- glpi-data:/var/glpi
- ./local_define.php:/var/www/glpi/config/local_define.php:ro
Après cela, les deux webhooks en file d'attente ont été livrés avec le statut 200. Pour configurer un webhook de zéro, voir les webhooks natifs de GLPI 11.
5. L'avertissement sur les documents
La migration a laissé un seul avertissement dans le journal warning_during_migration_to_12.0.0.log : « Rights have been given for document, you should review ACLs after update ». GLPI a accordé de nouveaux droits sur les documents. Vérifiez-les dans Administration > Profils, onglet Gestion > Documents, en particulier sur les profils des utilisateurs finaux.
Checklist de la mise à jour
| Quand | Que faire |
|---|---|
| Avant | Vérifier PHP (8.3+) et la base (MariaDB 10.11+ ou MySQL 8.0+) avec system:check_requirements |
| Avant | Lister les plugins et confirmer que chacun a une version pour la 12 |
| Avant | Lister les webhooks et les intégrations qui pointent vers des adresses internes |
| Avant | Chercher les liens en double entre articles et catégories de la base de connaissances |
| Avant | Sauvegarder la base, les fichiers et le dossier de configuration (avec glpicrypt.key) |
| Pendant | Mode maintenance, remplacement du code (ou du tag), database:update |
| Pendant | Avec le .tgz : copier inc/downstream.php et config/local_define.php depuis l'ancien dossier |
| Après | db:check, plugin:resume_execution et mise à jour de chaque plugin |
| Après | Donner une visibilité aux anciennes catégories de la base de connaissances (et la marque FAQ, pour le Self-Service) |
| Après | Corriger la méthode des webhooks et autoriser le réseau interne, si besoin |
| Après | Revoir les droits sur les documents dans les profils |
| Après | Ouvrir un ticket de test, déclencher un webhook, se connecter en tant qu'utilisateur final |
Et les modules NexTool ?
Le plugin NexTool et ses 37 modules fonctionnent sous GLPI 11 et sous GLPI 12 avec la même version. C'est pourquoi, contrairement aux plugins ci-dessus, vous pouvez les mettre à jour avant, encore sous la 11, dans NexTool > Modules > Tout mettre à jour. Après la migration, ils sont suspendus comme les autres plugins : lancez plugin:resume_execution et vérifiez la liste dans NexTool > Modules. Le tableau module par module se trouve dans NexTool sous GLPI 12 : compatibilité. Si vous souhaitez de l'aide pour planifier ou réaliser la mise à jour, parlons-en.
Test réalisé par NexTool le 16 octobre 2026, sur une copie jetable avec des données fictives : image officielle glpi/glpi 11.0.11 vers 12.0.0 (PHP 8.5), MariaDB 10.6 vers 10.11, et archive .tgz sous Debian 13 (PHP 8.4). L'environnement a été supprimé à la fin. GLPI est une marque déposée de Teclib'. NexTool n'est pas affiliée à Teclib'.
Commentaires
Les commentaires de cet article proviennent de GitHub (giscus). En les chargeant, votre navigateur se connecte à GitHub, qui reçoit votre adresse IP et peut enregistrer ses propres cookies.
Pour les charger automatiquement, activez les cookies fonctionnels