Aller au contenu

Mettre à jour un parc de sites WordPress sur un seul serveur cPanel

Apprenez à mettre à jour tout un parc de sites WordPress sur un même serveur cPanel/WHM, avec une sauvegarde par compte, une vérification par site et une restauration qui ne touche que l'installation brisée.

Ce guide explique comment mettre à jour tous les sites WordPress d’un serveur cPanel/WHM dans une seule fenêtre planifiée, pour l’administrateur ou l’agence qui en gère de vingt à deux cents. Passé ce nombre, ouvrir le tableau de bord de chaque site pour cliquer sur Mettre à jour n’est plus un plan, et ce sont souvent les installations oubliées qui cassent. La recommandation est une chaîne en cinq étapes bâtie sur WP-CLI, l’outil en ligne de commande de WordPress, exécutée une fois par compte plutôt qu’une fois par parc. Vous découvrez chaque installation, triez les sites en vagues, sauvegardez chaque compte, mettez à jour sous l’utilisateur du compte, puis vérifiez ce site avant le suivant. À la fin, vous aurez une fenêtre hebdomadaire reproductible et une restauration que vous pouvez viser sur un seul site sans toucher aux cent quatre-vingt-dix-neuf autres.

Ce que vous allez accomplir

  • Dresser un inventaire complet des installations WordPress du serveur, y compris celles en sous-dossier et sur les domaines additionnels que personne n’a documentées.
  • Trier cet inventaire en vagues de mise à jour, pour qu’une mauvaise version d’extension apparaisse sur un site qui ne vous vaudra pas un appel.
  • Prendre une sauvegarde par compte qui contient vraiment tout ce dont une restauration a besoin.
  • Lancer les mises à jour sous l’utilisateur Linux de chaque compte, pour qu’aucun fichier ne se retrouve possédé par root.
  • Vérifier chaque site avec un test HTTP, un test de sommes de contrôle et un coup d’œil au journal d’erreurs du compte.
  • Ramener un seul site brisé à sa version d’extension précédente sans annuler toute la vague.

Prérequis

Il vous faut un accès shell root ou revendeur sur le serveur WHM, parce que la découverte et le changement d’utilisateur lisent tous les deux à travers /home. Tout ce qui touche un site s’exécute quand même sous l’utilisateur non privilégié du compte, et c’est justement le but de la forme su employée partout ici.

WP-CLI doit être installé pour tout le serveur et exécutable par des utilisateurs ordinaires. Vérifiez avec wp --info depuis un compte normal ; si le binaire se trouve dans un endroit que seul root peut lire, corrigez cela avant de commencer.

Il vous faut aussi un mécanisme de sauvegarde dont vous avez déjà restauré au moins une fois. Sur la plupart des serveurs cPanel, c’est JetBackup, le produit de sauvegarde que ces hébergeurs offrent souvent. Si vous n’avez jamais fait de restauration avec, faites d’abord la restauration de compte JetBackup une fois sur un compte jetable. Une sauvegarde jamais restaurée n’est pas un plan de retour arrière.

Enfin, il vous faut une fenêtre de maintenance annoncée et un moyen de joindre les propriétaires des sites. Ça ressemble à de la paperasse jusqu’à la première fois où un client remarque un changement avant vous.

Comment ça marche

La chaîne compte cinq étapes, et chacune se déroule complètement sur un compte avant que le compte suivant commence. La découverte trouve les installations. L’ordonnancement décide qui passe en premier. La sauvegarde crée l’objet que vous restaurerez. La mise à jour applique les changements du cœur, des extensions et des thèmes. La vérification décide si ce site a réussi.

Chaîne de mise à jour d'un parc WordPress en cinq étapes sur un serveur cPanel, avec une vérification qui envoie un site en échec vers une restauration

L’embranchement au bas du schéma est ce qui rend l’ensemble vivable. Un site qui échoue à la vérification n’est pas « réparé plus tard ». Il est restauré tout de suite, seul, pendant que vous vous souvenez encore de ce qui a changé dessus.

L’ordre compte pour une raison qui n’a rien à voir avec le rangement. Quand une extension publie une version qui plante sous PHP 8.2, cette version plantera de la même façon sur tous les sites qui l’utilisent. Si vos dix premiers sites sont des copies de préproduction et des sites vitrines, vous l’apprenez là. Si vos dix premiers sont des boutiques, vous l’apprenez du client.

Quatre vagues de mise à jour ordonnées des sites de préproduction aux sites qui encaissent, chacune avec son feu vert avant la vague suivante

Un détail mécanique soutient toute la procédure. WP-CLI accepte de s’exécuter en root si vous passez --allow-root, et ça fonctionne, une fois. Tout fichier qu’il crée ou remplace appartient alors à root plutôt qu’à l’utilisateur du compte cPanel. La prochaine mise à jour automatique et la prochaine installation d’extension depuis le tableau de bord buteront sur des erreurs de permission. PHP-FPM aussi, le gestionnaire de processus qui exécute PHP sous l’utilisateur propre à chaque compte. C’est donc l’utilisateur du compte qui lance la commande, chaque fois.

Étape par étape

  1. Découvrez chaque installation WordPress du serveur. Une installation WordPress contient toujours un répertoire wp-includes, ce qui en fait un marqueur plus fiable qu’une liste de domaines. Ceci les trouve, y compris celles en sous-dossier et dans les racines de site (le dossier qu’un domaine sert) créées par les domaines additionnels :

    find /home/*/public_html -maxdepth 3 -name wp-includes -type d -printf '%h\n' | sort

    Vous obtenez une racine de site par ligne :

    /home/acmecorp/public_html
    /home/acmecorp/public_html/shop
    /home/bakerysite/public_html
    /home/bakerysite/public_html/blog.bakery.ca

    Montez -maxdepth à 4 ou 5 si vos comptes imbriquent les domaines plus profondément. Chacun de ces chemins est exactement ce que vous passerez à WP-CLI comme --path=.

  2. Transformez cette liste en inventaire compte-et-chemin. WP-CLI a besoin du chemin, et su a besoin du nom de compte. Le nom de compte est le deuxième segment du chemin sous /home :

    find /home/*/public_html -maxdepth 3 -name wp-includes -type d -printf '%h\n' \
      | sort | awk -F/ '{print $3"\t"$0}' > /root/wp-inventory.tsv
    acmecorp	/home/acmecorp/public_html
    acmecorp	/home/acmecorp/public_html/shop
    bakerysite	/home/bakerysite/public_html

    Retirez maintenant les installations mortes. Un répertoire avec wp-includes mais sans wp-config.php est une copie abandonnée, et la mettre à jour gaspille une fenêtre :

    while IFS=$'\t' read -r user path; do
      [ -f "$path/wp-config.php" ] && printf '%s\t%s\n' "$user" "$path"
    done < /root/wp-inventory.tsv > /root/wp-live.tsv

    Si votre serveur a WP Toolkit, le module de gestion WordPress livré avec cPanel, il tient son propre inventaire des installations qu’il gère et peut vous les lister. Servez-vous-en comme deuxième avis plutôt que comme seule source. Il liste ce qu’il connaît, et l’installation oubliée dans un sous-dossier est souvent précisément ce qu’il ne connaît pas. Consultez la documentation cPanel courante pour la forme exacte de la commande sur votre version, plutôt que de deviner les options.

  3. Triez l’inventaire en vagues et écrivez-les. Découpez /root/wp-live.tsv en quatre fichiers, wave1.tsv à wave4.tsv, en suivant le schéma ci-dessus. Préproduction et sites internes d’abord, sites clients à faible trafic ensuite, sites achalandés sans transaction en troisième, tout ce qui encaisse en dernier. La règle pour trancher : si une heure d’arrêt coûte de l’argent ou des réservations au propriétaire, le site va dans la vague 4.

    À l’intérieur d’un même site, faites le cœur en premier, puis les extensions, puis les thèmes. Le cœur change les interfaces de programmation que les extensions appellent, et une extension mise à jour contre un vieux cœur puis laissée là est la combinaison qui surprend.

  4. Sauvegardez le compte avant d’y toucher. Une restauration a besoin de trois choses : la base de données, les fichiers des extensions et les numéros de version d’avant. S’il en manque une, la restauration devient une devinette. Lancez le tout sous l’utilisateur du compte :

    su -s /bin/bash - acmecorp -c "cd /home/acmecorp/public_html && \
      wp db export ~/pre-update-2026-09-10.sql && \
      wp plugin list --fields=name,version --format=csv > ~/pre-update-2026-09-10-plugins.csv && \
      tar -czf ~/pre-update-2026-09-10-plugins.tar.gz wp-content/plugins"
    Success: Exported to '/home/acmecorp/pre-update-2026-09-10.sql'.

    Le -s /bin/bash compte sur cPanel. Beaucoup de comptes ont leur shell de connexion réglé à jailshell ou noshell, et su - <user> seul vous déposera à un endroit inattendu ou refusera carrément. Forcer bash le temps de la commande contourne cela sans modifier le réglage de shell du compte.

    Ce fichier CSV d’extensions est celui dont vous serez content à l’étape 6. C’est le seul relevé de la version qu’avait chaque extension avant la passe.

  5. Faites un essai à blanc, puis la vraie mise à jour. Regardez le cœur en premier :

    su -s /bin/bash - acmecorp -c "wp --path=/home/acmecorp/public_html core check-update"
    +---------+-------------+-------------------------------------------------------------+
    | version | update_type | package_url                                                 |
    +---------+-------------+-------------------------------------------------------------+
    | 6.8.2   | minor       | https://downloads.wordpress.org/release/wordpress-6.8.2.zip |
    +---------+-------------+-------------------------------------------------------------+

    Success: WordPress is at the latest version. veut dire qu’il n’y a rien à faire pour le cœur. S’il y a une mise à jour, appliquez-la puis lancez la migration de la base, une étape distincte que wp core update ne fait pas pour vous :

    su -s /bin/bash - acmecorp -c "wp --path=/home/acmecorp/public_html core update && \
      wp --path=/home/acmecorp/public_html core update-db"

    Prévisualisez ensuite le travail sur les extensions avant de vous y engager :

    su -s /bin/bash - acmecorp -c "wp --path=/home/acmecorp/public_html plugin update --all --dry-run"
    Available plugin updates:
    +---------------------+----------+-----------+----------------+
    | name                | status   | update    | update_version |
    +---------------------+----------+-----------+----------------+
    | wordpress-seo       | active   | available | 24.4           |
    | contact-form-7      | active   | available | 6.0.6          |
    +---------------------+----------+-----------+----------------+

    Lisez cette liste avant de la lancer pour vrai. Un saut de version majeure sur l’extension qui tient la caisse du site est une décision, pas une routine. Quand la liste vous semble raisonnable, retirez --dry-run et répétez pour les thèmes :

    su -s /bin/bash - acmecorp -c "wp --path=/home/acmecorp/public_html plugin update --all && \
      wp --path=/home/acmecorp/public_html theme update --all"
  6. Vérifiez le site avant de passer au compte suivant. Trois tests, dans cet ordre. D’abord, est-ce que le site répond :

    curl -sSo /dev/null -w '%{http_code}\n' --max-time 20 https://acmecorp.example/
    200

    Autre chose qu’un 200 ou qu’un 301 attendu arrête la vague. Ensuite, est-ce que les fichiers du cœur correspondent encore à ce que WordPress.org a publié, ce qui attrape une décompression à moitié faite :

    su -s /bin/bash - acmecorp -c "wp --path=/home/acmecorp/public_html core verify-checksums"
    Success: WordPress installation verifies against checksums.

    Enfin, lisez le journal d’erreurs PHP du compte, que cPanel écrit dans la racine du site :

    tail -n 30 /home/acmecorp/public_html/error_log

    Vous cherchez des entrées PHP Fatal error horodatées après la mise à jour. Une erreur fatale là avec un 200 à la porte d’entrée veut souvent dire qu’un gabarit de page a cassé pendant que l’accueil s’affiche encore.

  7. Ne restaurez que le site brisé. Retrouvez la version qu’avait l’extension dans le CSV sauvegardé à l’étape 4 :

    grep contact-form-7 /home/acmecorp/pre-update-2026-09-10-plugins.csv
    contact-form-7,6.0.5

    Réinstallez ensuite cette version exacte. --force est nécessaire parce que la version installée est maintenant plus haute que celle demandée :

    su -s /bin/bash - acmecorp -c "wp --path=/home/acmecorp/public_html \
      plugin install contact-form-7 --version=6.0.5 --force"
    Success: Installed 1 of 1 plugins.

    Réinstaller des fichiers n’annule pas une migration de base que la nouvelle version a déjà faite. Si l’extension a modifié ses propres tables, importez plutôt la copie de la base, en acceptant de perdre le contenu publié depuis l’exportation. Pour une erreur HTTP 500 qui survit aux deux, l’isolement de la panne dans HTTP 500 après une mise à jour d’extension prend le relais.

  8. Lancez la vague en boucle, vous devant le clavier. Ceci traite une vague, affiche une ligne par site et ne s’arrête sur rien :

    while IFS=$'\t' read -r user path; do
      url=$(su -s /bin/bash - "$user" -c "wp --path='$path' option get siteurl" 2>/dev/null)
      su -s /bin/bash - "$user" -c "wp --path='$path' db export ~/pre-update.sql --quiet" \
        || { printf '%s\t%s\tSKIP no-dump\n' "$user" "$path"; continue; }
      su -s /bin/bash - "$user" -c "wp --path='$path' plugin update --all" >/dev/null 2>&1
      code=$(curl -sSo /dev/null -w '%{http_code}' --max-time 20 "$url")
      printf '%s\t%s\t%s\n' "$user" "$url" "$code"
    done < /root/wave2.tsv
    bakerysite	https://bakery.example	200
    clientfoo	https://clientfoo.example	500
    clientbar		SKIP no-dump

    Soyez honnête sur ce que ça ne fait pas. Ça vérifie un code de statut et rien d’autre, donc un site qui répond 200 avec une page blanche passe le test. Ça ne lit aucun journal d’erreurs, ne vérifie aucune somme de contrôle et ne s’arrête pas quand un site échoue. C’est une façon de voir la vague au complet rapidement, puis vous allez regarder le 500 vous-même. Surveiller l’affichage pendant qu’il défile fait partie du travail, et c’est pourquoi c’est une boucle que vous lancez et non une tâche cron que vous planifiez.

Valider que ça fonctionne

Comptez les sites. Le nombre de lignes affichées par la boucle doit égaler le nombre de lignes du fichier de vague, et chacune doit montrer un code de statut. Une ligne manquante veut dire qu’un site a dépassé le délai de vingt secondes, et c’est un résultat lui aussi.

Relancez la commande de découverte de l’étape 1 une fois la fenêtre fermée et comparez-la à l’inventaire de départ. De nouveaux chemins veulent dire que quelqu’un a installé WordPress pendant votre fenêtre, ou qu’une installation sautée attend toujours.

Testez deux sites à la main, un de la vague 2 et un de la vague 4. Connectez-vous à wp-admin, chargez une page autre que l’accueil et soumettez un formulaire. Les tests automatisés confirment que le serveur a répondu ; une personne confirme que le site fonctionne.

Dépannage

su: Authentication failure ou la commande atterrit dans une cage. Le shell du compte est réglé à noshell dans WHM. La forme su -s /bin/bash - <user> remplace le shell le temps d’une commande, et c’est celle utilisée partout dans ce guide. Si ça échoue encore, vérifiez si le compte est suspendu.

Error: This does not seem to be a WordPress installation. La valeur --path= pointe vers un répertoire sans wp-load.php, souvent parce que l’installation se trouve un niveau plus bas que la découverte l’a deviné. Relancez l’étape 1 avec un -maxdepth plus grand.

WP-CLI tourne sous la mauvaise version de PHP. WP-CLI utilise le premier php trouvé dans le PATH du shell, et il ne lit pas le réglage MultiPHP du compte. Ça fait mal sur un parc où les comptes tournent sous des versions différentes. Une mise à jour qui réussit sous PHP 8.3 dans votre shell peut planter sous le PHP 8.1 que le site sert vraiment. La vérification préalable est couverte dans mettre à jour WordPress via WP-CLI sur cPanel.

Des fichiers appartiennent à root après une passe antérieure. Quelqu’un a utilisé --allow-root. Corrigez la propriété sur tout le compte, puis ne recommencez plus :

chown -R acmecorp:acmecorp /home/acmecorp/public_html

Les sites continuent de se mettre à jour entre vos fenêtres. Les mises à jour automatiques de WordPress sont encore actives quelque part. Elles changeront des versions d’extensions que votre sauvegarde ne reflète plus. Les désactiver à l’échelle du parc est couvert dans désactiver la mise à jour automatique des extensions et des thèmes.

Quand ce n’est pas la bonne approche

Si l’un de ces sites est déployé depuis git ou géré par Composer, wp plugin update n’est pas le bon outil pour lui. Il écrit des fichiers que la chaîne de déploiement ignore, et le prochain déploiement les annule sans bruit. Sortez ces comptes de l’inventaire et mettez-les à jour par leur dépôt.

Si le parc s’étend sur plusieurs serveurs, une boucle shell par serveur cesse de tenir la route vers la troisième machine. C’est le moment de passer à un outil de gestion de configuration ou à un service de mises à jour infogérées. L’inventaire vit alors à un seul endroit et les résultats reviennent à un seul tableau de bord.

Et si un site n’a pas de copie de préproduction alors qu’une version majeure du cœur attend, ne le mettez dans aucune vague. Clonez-le, faites la montée de version sur le clone, et planifiez-la à part. Cette procédure rend une mise à jour de routine défendable ; elle ne rend pas sûre une montée de version majeure non testée. Une mise à jour automatique antérieure a déjà laissé une installation à moitié faite ? Commencez par récupérer après une mise à jour automatique ratée avant de remettre ce compte dans une vague.

Gardez deux références ouvertes pendant le travail. La référence des commandes WP-CLI donne le comportement exact des options selon votre version, et la documentation cPanel couvre le shell de compte et MultiPHP.

Un WordPress qui rapporte vraiment mérite un opérateur — Stack Harbor opère cette pile sous WordPress Entreprise ; réservez une consultation d’infrastructure.