ITSkillsCenter
Développement Web

Staging WordPress propre avec snapshots Incus — workflow agence 2026

12 دقائق للقراءة

📍 Article principal du sujet : Incus 6 LTS — gérer conteneurs système et VMs Linux pour PME ouest-africaine

L’enchaînement développement → staging → production sur un site WordPress se passe rarement bien quand on bricole avec des plugins de duplication, des recherche-remplace d’URLs maladroits ou des bases MariaDB partiellement copiées. Le résultat classique : un staging qui ne reflète pas la prod, des bugs qui n’apparaissent qu’après mise en ligne, et des plugins activés en double qui cassent les permaliens. Avec Incus et ses snapshots ZFS instantanés, on obtient un workflow propre où staging et prod sont des conteneurs siblings, où la promotion vers prod se fait en deux secondes, et où le rollback en cas de pépin se fait par une commande unique. Ce tutoriel monte ce workflow de bout en bout.

Le scénario : agence ou freelance qui héberge un site WordPress sur un Hostinger Cloud VPS avec Incus, et qui veut tester chaque mise à jour de plugin, chaque modif de thème, chaque migration de version PHP avant que le client ne soit impacté. À la fin, vous saurez créer un staging à partir de la prod en cinq secondes, faire vos tests, et soit promouvoir vers la prod, soit jeter le staging.

Pourquoi pas WP Staging ou Duplicator

Les plugins de staging WordPress (WP Staging, Duplicator, BlogVault) fonctionnent par copie de fichiers et de base de données depuis l’instance prod vers un sous-répertoire ou un sous-domaine. Trois limites :

  • Cohérence partielle : la copie BDD se fait sur une instance qui peut être en train d’écrire, donc la photo n’est jamais parfaitement cohérente. Les sites e-commerce avec commandes en cours subissent ce problème en permanence.
  • Pas d’isolation : staging et prod partagent le même PHP-FPM, le même MariaDB. Un crash MariaDB en staging peut prendre la prod avec.
  • Promotion lourde : pour passer du staging à la prod, on copie les changements à la main ou via un autre plugin. Casse-tête si plusieurs personnes ont touché aux deux.

Avec Incus, on remplace tout cela par : un conteneur prod, un snapshot, et un clone du snapshot qui devient le staging. La copie est atomique (instantanée côté ZFS), totalement isolée (deux conteneurs différents avec leurs propres processus), et la promotion peut se faire par bascule de domaine au reverse-proxy en moins d’une seconde.

Prérequis

  • VPS Linux 64 bits, 4 Go RAM minimum (8 Go pour gros site WooCommerce), 60 Go SSD
  • Incus 6 LTS opérationnel avec pool ZFS — voir Installer Incus avec Zabbly
  • Caddy installé sur l’hôte pour le reverse-proxy HTTPS
  • Un site WordPress déjà installé dans un conteneur Incus — voir WordPress multisite par conteneur
  • Niveau attendu : familier WordPress, Linux et Nginx/Apache
  • Temps estimé : 45 à 60 minutes pour le workflow complet, puis quelques secondes par staging créé ensuite

Étape 1 — Conteneur prod existant comme point de départ

On part du principe que vous avez déjà wp-prod qui sert le site sur monclient.example.com. Ce conteneur contient WordPress, MariaDB et Nginx (ou Apache), géré par systemd. Vérifions son état avant de manipuler :

incus list wp-prod
incus exec wp-prod -- systemctl status nginx mariadb php8.2-fpm
incus exec wp-prod -- wp --allow-root --path=/var/www/wp core version
# 6.5.x

Le site fonctionne, on a la version WordPress affichée — c’est notre point de référence stable. Avant tout, on prend un snapshot horodaté qui servira de filet de sécurité ultime.

incus snapshot create wp-prod safety-$(date +%Y%m%d-%H%M)

Cette précaution coûte deux secondes et zéro espace disque (snapshot ZFS instantané). On peut maintenant manipuler sereinement.

Étape 2 — Créer un staging à partir de la prod

L’opération clé : on copie le conteneur prod vers un nouveau conteneur staging. Sur ZFS, c’est instantané grâce au copy-on-write — les blocs de données ne sont dupliqués que lorsque l’un des deux conteneurs les modifie ensuite.

incus copy wp-prod wp-staging
incus start wp-staging
incus list -c ns,4
# wp-prod    | RUNNING | 10.124.10.42
# wp-staging | RUNNING | 10.124.10.43

Cinq secondes plus tard, le staging tourne, indépendamment, avec exactement la même base de données, les mêmes fichiers, les mêmes plugins. Mais l’URL hardcodée dans la base est encore monclient.example.com — il faut la basculer vers staging.monclient.example.com avant que le staging réponde correctement.

Étape 3 — Réécrire les URLs pour le staging

WP-CLI fait le travail proprement avec une seule commande qui parcourt toutes les tables et remplace les URLs sérialisées intactes (sans casser les options PHP serialize).

incus exec wp-staging -- bash -c "cd /var/www/wp && wp --allow-root search-replace 'monclient.example.com' 'staging.monclient.example.com' --all-tables --skip-columns=guid"
# Success: 4127 replacements made.

Le drapeau –skip-columns=guid est crucial : la colonne GUID dans wp_posts ne doit jamais être modifiée pour ne pas casser les flux RSS et l’historique d’export. –all-tables couvre les tables custom des plugins (WooCommerce, ACF, BuddyPress) qui contiennent souvent des URLs sérialisées.

Pour bonne mesure, on désactive les notifications mail sur le staging (les clients ne doivent pas recevoir de mail de confirmation depuis l’environnement de test) :

incus exec wp-staging -- bash -c "cd /var/www/wp && wp --allow-root config set DISABLE_WP_CRON true --type=constant"
# Désactiver les emails pendant les tests
incus exec wp-staging -- bash -c "cd /var/www/wp && wp --allow-root plugin install wp-mail-logging --activate"

WP Mail Logging capture les mails envoyés sans les délivrer — pratique pour vérifier qu’un workflow déclenche bien une notification, sans spammer le client.

Étape 4 — Exposer le staging via Caddy

Côté hôte, on ajoute une entrée Caddy pour staging.monclient.example.com. Idéalement, on la protège par mot de passe basique pour éviter que Google ne l’indexe et que des clients ne la découvrent par accident.

# Sur l'hôte
cat <<'EOF' >> /etc/caddy/Caddyfile
staging.monclient.example.com {
  basic_auth {
    devs $2a$14$HASH_BCRYPT_ICI
  }
  reverse_proxy 10.124.10.43:80
  encode gzip
  header X-Robots-Tag "noindex, nofollow"
}
EOF
systemctl reload caddy

Le hash bcrypt se génère avec caddy hash-password sur l’hôte. Le header X-Robots-Tag noindex est une seconde ligne de défense au cas où le mot de passe se promène — Google et Bing respectent cette directive même sans authentification.

Étape 5 — Tester sereinement sur le staging

Vous pouvez maintenant aller sur https://staging.monclient.example.com, vous logger avec le mot de passe Caddy, puis avec le compte admin WordPress, et faire toutes les manipulations risquées : mettre à jour un plugin, tester un thème enfant, migrer vers PHP 8.3, refaire la structure des permaliens.

Pendant ce temps, la prod continue de tourner sur le conteneur wp-prod, totalement indépendante. Les commandes que vous donnez au staging n’ont aucun effet sur la prod. Si quelque chose casse irrémédiablement, vous jetez le staging et recommencez.

# Le staging est bousillé par un test ?
incus stop wp-staging
incus delete wp-staging
# 5 secondes plus tard, on en recrée un frais
incus copy wp-prod wp-staging-2
incus start wp-staging-2
incus exec wp-staging-2 -- bash -c "cd /var/www/wp && wp --allow-root search-replace ..."

Étape 6 — Promouvoir le staging vers la prod

Le test est concluant, vous voulez basculer la version testée vers la prod. Trois stratégies possibles, par ordre croissant de propreté :

Option A — Bascule par rebascule de domaine (la plus simple)

# Réécrire les URLs du staging vers le domaine prod
incus exec wp-staging -- bash -c "cd /var/www/wp && wp --allow-root search-replace 'staging.monclient.example.com' 'monclient.example.com' --all-tables --skip-columns=guid"

# Sur l'hôte, basculer Caddy
sed -i 's/wp-prod IP 10.124.10.42/wp-staging IP 10.124.10.43/' /etc/caddy/Caddyfile
systemctl reload caddy

# Renommer les conteneurs pour cohérence
incus stop wp-prod
incus rename wp-prod wp-prod-old-$(date +%Y%m%d)
incus rename wp-staging wp-prod
incus start wp-prod

Coupure de service : moins d’une seconde (le temps du caddy reload). Le client ne s’aperçoit de rien. L’ancienne prod reste sous le nom wp-prod-old-YYYYMMDD pendant quelques jours, le temps de valider que la nouvelle prod tient bien la charge réelle, avant suppression.

Option B — Réplication par export-import (la plus sûre pour les BDD critiques)

# Exporter le filesystem WordPress et la BDD du staging
incus exec wp-staging -- bash -c "cd /var/www/wp && wp --allow-root db export /tmp/staging-db.sql"
incus file pull wp-staging/tmp/staging-db.sql /tmp/

# Importer dans la prod (avec rewrite URL au passage)
incus file push /tmp/staging-db.sql wp-prod/tmp/
incus exec wp-prod -- bash -c "cd /var/www/wp && wp --allow-root db import /tmp/staging-db.sql"
incus exec wp-prod -- bash -c "cd /var/www/wp && wp --allow-root search-replace 'staging.monclient.example.com' 'monclient.example.com' --all-tables --skip-columns=guid"

# Synchroniser les fichiers ajoutés (uploads, plugins, thèmes)
incus exec wp-staging -- tar czf /tmp/wp-content.tar.gz -C /var/www/wp wp-content
incus file pull wp-staging/tmp/wp-content.tar.gz /tmp/
incus file push /tmp/wp-content.tar.gz wp-prod/tmp/
incus exec wp-prod -- tar xzf /tmp/wp-content.tar.gz -C /var/www/wp/

Plus propre, plus long (1-3 minutes selon la taille). On garde la prod en service pendant la copie, et la bascule finale est juste un wp cache flush — la prod consomme la nouvelle BDD en restant accessible.

Option C — Blue/Green via Caddy avec health-check

Configuration Caddy avec deux backends et un health-check qui dirige vers le bon. Plus complexe à maintenir, intéressant uniquement pour les sites e-commerce à très haute disponibilité.

Étape 7 — Conserver l’historique des bascules

Au fil des semaines, on accumule des conteneurs wp-prod-old-20260115, wp-prod-old-20260131, etc. Au lieu de les laisser traîner, on les exporte vers le stockage S3 distant (voir Backup distant chiffré) puis on les supprime.

# Avant suppression, exporter pour archivage
incus snapshot create wp-prod-old-20260115 final-archive
incus export wp-prod-old-20260115 /backups/wp-prod-old-20260115.tar.gz --snapshot=final-archive
rclone copy /backups/wp-prod-old-20260115.tar.gz bunny:backups-itskills/wordpress-history/
incus delete wp-prod-old-20260115

L’archive horodatée reste accessible pour des cas exotiques (audit, forensic, demande client de revenir trois mois en arrière), tout en libérant l’espace local du VPS.

Étape 8 — Snapshots de routine pendant les opérations à risque

Au-delà du staging, le snapshot Incus est aussi votre filet de sécurité quotidien sur la prod. Avant chaque opération ponctuelle (mise à jour majeure WordPress, ajout d’un plugin custom, intervention BDD), on snapshote :

# Avant
incus snapshot create wp-prod avant-update-woo-9
# Faire l'opération...
# Si KO :
incus snapshot restore wp-prod avant-update-woo-9
# La prod revient comme elle était il y a 30 secondes

La restauration prend deux secondes côté Incus. Le client peut ne jamais s’apercevoir qu’il y a eu un incident, à condition que vous reagissiez vite. C’est l’argument différenciant majeur face à une infrastructure WordPress classique sans snapshots.

Erreurs fréquentes

Erreur Cause Solution
Liens cassés sur le staging après search-replace Tables custom oubliées Toujours –all-tables ; pour ACF, utiliser le plugin Better Search Replace qui gère les sérialisations spéciales
Staging visible sur Google Caddy basic_auth oublié ou mal configuré Vérifier le hash bcrypt et le header X-Robots-Tag
Mails de test envoyés aux vrais clients Plugin de capture mail non activé Toujours wp-mail-logging ou WP Mail SMTP debug mode sur le staging
BDD MariaDB corrompue après restauration de snapshot Snapshot pris pendant écriture intensive Faire un wp db check et wp db repair ; sinon, prendre les snapshots quand le service est moins sollicité
Conteneur staging démarre mais site blanc Permissions cassées sur wp-content/uploads incus exec wp-staging -- chown -R www-data:www-data /var/www/wp

Adaptation au contexte ouest-africain

Pour une agence WordPress de Dakar ou Abidjan qui gère 30 sites clients, le workflow staging Incus change la sérénité opérationnelle. Sur les 30 sites, environ un tiers reçoit des mises à jour WordPress, plugins ou thèmes par semaine — soit dix opérations à risque hebdomadaires. Sans staging propre, chacune est une roulette russe ; avec staging Incus, chacune se valide dans un environnement parfaitement isomorphe en quelques minutes, sans risque pour la prod.

Le bonus business : pouvoir vendre le staging comme service. Pour les clients premium qui veulent voir un nouveau design avant publication, ou tester un nouveau plugin avant de payer la licence, on facture 5 000 à 10 000 FCFA par cycle de staging. À 5 cycles par mois sur 10 clients premium, cela fait 250 000 à 500 000 FCFA mensuels supplémentaires pour zéro coût d’infrastructure additionnel.

Pour les équipes en télétravail, le staging Incus accessible par URL HTTPS protégée mot de passe permet à plusieurs développeurs de tester le même environnement depuis leurs postes différents, sans avoir à monter Docker en local sur des laptops modestes (8 Go RAM courants à Dakar). Le serveur fait le travail, les laptops servent de fenêtre.

Tutoriels frères

Pour aller plus loin

FAQ

Combien de stagings simultanés sur un VPS 4 Go ?
Deux à trois si la prod est légère, un seul si la prod est WooCommerce volumineux. Pour gérer plusieurs stagings en parallèle, viser 8 Go RAM ou plus.

Le staging consomme-t-il vraiment peu de disque grâce à ZFS ?
À la création : oui, 0 octet supplémentaire. Au fur et à mesure des modifications dans le staging, les blocs divergent et l’occupation grimpe — typiquement 100-500 Mo par staging actif sur quelques jours.

WP-CLI search-replace casse-t-il les widgets et le customizer ?
Non si –skip-columns=guid est utilisé. Les widgets et le customizer stockent leurs données en sérialisé PHP que WP-CLI désérialise puis re-sérialise correctement.

Faut-il purger le cache après bascule ?
Oui, wp cache flush dans le conteneur prod, et purge du cache navigateur via Caddy si vous avez activé le caching côté reverse-proxy.

Comment automatiser la création de staging à chaque release ?
Un script create-staging.sh qui prend en argument le conteneur prod, fait le copy, le rename, le search-replace et la mise à jour Caddy. Lancé via la CI/CD à chaque tag git.

Besoin d'un site web ?

Confiez-nous la Création de Votre Site Web

Site vitrine, e-commerce ou application web — nous transformons votre vision en réalité digitale. Accompagnement personnalisé de A à Z.

À partir de 250.000 FCFA
Parlons de Votre Projet
Publicité