Credit : Logo officiel
Migrer un site WordPress sans temps d'arret
Migrer un site WordPress sans temps d'arret
Le mois dernier, j'ai migre un site WooCommerce de 12 Go (8 Go de fichiers + 4 Go de base de donnees) avec environ 400 commandes par jour. Le client voulait basculer d'un mutualise sature vers un VPS IONOS Performance, sans aucune coupure visible. Resultat : downtime mesure a zero seconde, aucune commande perdue, zero ticket SAV. La methode est rodee, et je te la donne en detail.
L'idee fondamentale tient en une phrase : on prepare le nouveau serveur en parallele, on synchronise les fichiers et la base plusieurs fois, on bascule le DNS apres avoir teste, et on garde l'ancien actif tant que la propagation DNS n'est pas finie. Pas de magie, juste de la rigueur.
Preparer la migration : la checklist J-7
Une semaine avant la bascule, je fais ces verifications systematiquement :
- Inventaire de la stack actuelle : version WordPress, version PHP, version MySQL/MariaDB, plugins payants avec leurs licences, theme custom, certificats SSL, redirections htaccess.
- Estimation du volume :
du -sh /var/www/wordpresspour les fichiers etdu -sh /var/lib/mysql/wordpress_dbpour la base. - Plan de rollback : qu'est-ce qu'on fait si la bascule echoue ? Reponse : on remet l'ancien IP dans le DNS, le TTL court permet de revenir en 5 minutes.
- Baisser le TTL : a J-2, on passe le TTL des enregistrements A/AAAA a 300 secondes (5 minutes) chez IONOS. Ca evite que les resolveurs gardent l'ancienne IP en cache pendant 24h apres la bascule.
- Communication : prevenir l'equipe de modos/redaction qu'ils ne doivent pas publier le jour J pour eviter de perdre du contenu entre deux synchros.
Pieges classiques a auditer avant
Avant la moindre rsync, je verifie ces details qui font perdre des heures si oublies :
- Cron WordPress externe : si l'ancien hebergeur execute
wp-cron.phpvia un cron systeme externe (et non via le HTTP interne), il faut reproduire le cron sur le nouveau serveur sinon les emails programmes, les sauvegardes et les imports planifies s'arretent silencieusement. - Plugins de cache fichier : W3TC ou WP Super Cache stockent des chemins absolus dans leur conf. Desactive-les avant migration.
- Uploads massifs en NFS ou S3 : verifie le mode de stockage des medias. Un site qui pointe sur un bucket S3 externe n'a pas besoin de copier
/wp-content/uploads, ca peut faire gagner beaucoup de temps. - Caracteristiques PHP figees dans le code : certains themes appellent
set_time_limit(0)ou supposent undisable_functionsparticulier. Repli sur l'ancienne conf si necessaire.
Etape 1 : Preparer le nouveau serveur
Sur le nouveau VPS IONOS Debian 12, on installe la stack LEMP a jour :
apt update && apt upgrade -y
apt install nginx mariadb-server php8.3-fpm php8.3-mysql php8.3-xml \
php8.3-mbstring php8.3-curl php8.3-zip php8.3-gd php8.3-imagick \
php8.3-intl php8.3-bcmath redis-server -y
mysql_secure_installation
WP-CLI :
curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
chmod +x wp-cli.phar && mv wp-cli.phar /usr/local/bin/wp
Creation de la base et de l'utilisateur dedie :
mysql -e "CREATE DATABASE wordpress_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
mysql -e "CREATE USER 'wp_user'@'localhost' IDENTIFIED BY 'MotDePasseSolide!2026';"
mysql -e "GRANT ALL ON wordpress_db.* TO 'wp_user'@'localhost'; FLUSH PRIVILEGES;"
Replique le php.ini (memory_limit, upload_max_filesize, post_max_size) en accord avec l'ancien environnement. C'est la qu'on perd des heures de debug si on oublie : un site qui tournait avec memory_limit = 512M et qui se retrouve a 128M plante a la premiere sauvegarde de page.
; /etc/php/8.3/fpm/php.ini
memory_limit = 512M
upload_max_filesize = 64M
post_max_size = 64M
max_execution_time = 300
max_input_vars = 3000
Vhost Nginx initial
Cree /etc/nginx/sites-available/monsite.fr :
server {
listen 80;
listen [::]:80;
server_name monsite.fr www.monsite.fr;
root /var/www/wordpress;
index index.php;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
location ~ /\.ht { deny all; }
}
Le SSL on le posera apres la bascule DNS via Certbot, parce que Let's Encrypt valide le challenge HTTP via le domaine, donc tant que le DNS n'a pas bascule, on ne peut pas emettre le certificat sur le nouveau serveur. Si tu veux un certificat avant, utilise un challenge DNS-01 ou un wildcard.
Etape 2 : Synchroniser les fichiers avec rsync
Premiere synchro complete depuis l'ancien serveur :
rsync -avz --progress -e "ssh -p 22 -i ~/.ssh/id_ed25519" \
/var/www/wordpress/ \
admin@nouveau-serveur.ionos.fr:/var/www/wordpress/
-a preserve permissions, dates, liens symboliques. -v verbeux. -z compresse a la volee, utile sur lien lent. Cette synchro peut prendre 10 minutes a 2 heures selon la taille et le debit.
Les synchros suivantes (qu'on lance une ou deux fois par jour jusqu'a la bascule finale) sont incrementales et donc rapides :
rsync -avz --delete -e "ssh -p 22" \
/var/www/wordpress/ \
admin@nouveau-serveur.ionos.fr:/var/www/wordpress/
Le --delete supprime sur la destination les fichiers qui n'existent plus sur la source : indispensable pour avoir un miroir exact, mais redoutable si tu te trompes de chemin. Verifie deux fois avant d'appuyer sur entree.
Permissions correctes apres rsync
Sur le nouveau serveur :
chown -R www-data:www-data /var/www/wordpress
find /var/www/wordpress -type d -exec chmod 755 {} \;
find /var/www/wordpress -type f -exec chmod 644 {} \;
chmod 600 /var/www/wordpress/wp-config.php
Etape 3 : Exporter et importer la base
Sur l'ancien serveur :
cd /var/www/wordpress
wp db export /tmp/migration.sql --add-drop-table --default-character-set=utf8mb4
scp /tmp/migration.sql admin@nouveau-serveur.ionos.fr:/tmp/
Sur le nouveau, edite d'abord /var/www/wordpress/wp-config.php avec les nouveaux identifiants de base, puis :
cd /var/www/wordpress
wp db import /tmp/migration.sql
wp cache flush
Pour les tres grosses bases
A partir de 2 a 3 Go, mysqldump devient lent. mydumper parallelise l'export et est 5 a 10 fois plus rapide :
apt install mydumper -y
mydumper -h localhost -u root -p MOT_DE_PASSE -B wordpress_db -o /tmp/dump --threads=4 --compress
rsync -avz /tmp/dump/ admin@nouveau-serveur:/tmp/dump/
# Sur le nouveau
myloader -h localhost -u root -p MOT_DE_PASSE -B wordpress_db -d /tmp/dump --threads=4
Base avec replication maitre/esclave
Si le site est sous une replication MySQL (cas plus rare en WordPress mais pas inexistant pour les boutiques a fort trafic), on prepare le nouveau serveur en esclave de l'ancien pendant la phase de transition. Sur le nouveau :
CHANGE MASTER TO MASTER_HOST='ancien-serveur.fr',
MASTER_USER='repl_user',
MASTER_PASSWORD='secret',
MASTER_LOG_FILE='mysql-bin.000123',
MASTER_LOG_POS=4567;
START SLAVE;
Le nouveau encaisse en continu les modifications de l'ancien. Au moment de la bascule, on stoppe l'ecriture cote ancien (mode maintenance), on attend le Seconds_Behind_Master = 0, on promote le nouveau, on bascule le DNS. Downtime sub-seconde mesurable. C'est plus complexe a mettre en place, reserve aux migrations critiques.
Etape 4 : Mettre a jour les URLs si necessaire
Si tu changes de domaine ou que tu passes en HTTPS :
wp search-replace 'http://ancien-domaine.fr' 'https://nouveau-domaine.fr' \
--all-tables --precise --skip-columns=guid
wp search-replace 'ancien-domaine.fr' 'nouveau-domaine.fr' \
--all-tables --precise --skip-columns=guid
--precise gere correctement les chaines serializees PHP (objets WordPress et metadonnees). C'est crucial : un sed brutal va casser les serializations et tu te retrouves avec des widgets blancs et des metadonnees corrompues.
Verifications :
wp option get siteurl
wp option get home
wp option pluck wp_options home
Methode alternative : Duplicator Pro
Si tu preferes le graphique ou que tu n'as pas d'acces SSH a l'ancien hebergement (mutualise) :
- Installer Duplicator Pro sur l'ancien site.
- Creer un package complet (archive + installer.php).
- Telecharger les deux fichiers et les uploader sur le nouveau serveur dans
/var/www/wordpress. - Modifier le
/etc/hostsde ta machine pour pointer le domaine sur la nouvelle IP. - Acceder a
https://monsite.fr/installer.phpet suivre l'assistant. - Duplicator s'occupe de l'import SQL et du search-replace.
Perso, je prefere rsync + WP-CLI pour les sites au-dessus de 5 Go : plus rapide, plus de controle, et les synchros incrementales pendant la phase de bascule sont imbattables. Duplicator est tres bon pour les sites de quelques centaines de Mo ou quand l'acces SSH cote source est inexistant.
Etape 5 : Tester avant la bascule DNS
Modifie ton /etc/hosts local pour pointer vers le nouveau serveur :
echo "203.0.113.50 monsite.fr www.monsite.fr" | sudo tee -a /etc/hosts
Navigue le site comme un utilisateur :
- Page d'accueil, articles, pages internes.
- Formulaire de contact (envoi reel d'un email).
- Connexion admin et back-office.
- Si WooCommerce : ajout au panier, processus de checkout en mode test, integration Stripe ou PayPal Sandbox.
- Recherche interne, fil RSS, sitemap.xml, robots.txt.
Cote serveur, regarde les logs en temps reel :
tail -f /var/log/nginx/error.log /var/log/php8.3-fpm.log
Si tout est vert pendant 30 minutes de tests, c'est bon signe.
Tests automatises avec WP-CLI
Pour les sites un peu massifs, je lance une serie de checks scriptes :
wp core verify-checksums --path=/var/www/wordpress
wp plugin verify-checksums --all --path=/var/www/wordpress
wp option list --search='*url*' --path=/var/www/wordpress
wp user list --field=user_email --path=/var/www/wordpress | head
wp post list --post_type=product --posts_per_page=5 --path=/var/www/wordpress
Les deux premiers verifient l'integrite des fichiers core et des plugins (super utile pour reperer un fichier corrompu pendant le rsync). Les autres font des smoke tests sur les donnees pour s'assurer que la base est complete.
Etape 6 : Synchro finale et bascule DNS
Le jour J, prevois une fenetre tranquille (nuit, week-end). Ordre des operations :
wp maintenance-mode activate --path=/var/www/wordpress
rsync -avz --delete -e ssh /var/www/wordpress/ admin@nouveau-serveur:/var/www/wordpress/
wp db export --path=/var/www/wordpress | \
ssh admin@nouveau-serveur 'cat > /tmp/final.sql && cd /var/www/wordpress && wp db import /tmp/final.sql'
wp maintenance-mode deactivate --path=/var/www/wordpress
Puis chez IONOS DNS Manager :
- A : nouvelle IPv4.
- AAAA : nouvelle IPv6 si applicable.
- TTL : 300 secondes (a remettre a 3600 quelques jours apres la bascule).
Le TTL c'est le piege classique. Si tu n'as pas baisse a 300 a J-2, les resolveurs DNS continuent de servir l'ancienne IP pendant des heures apres la bascule. Resultat : 50% de tes visiteurs vont sur l'ancien serveur, 50% sur le nouveau, et tes commandes WooCommerce arrivent dans deux bases differentes. Cauchemar a reconcilier.
Maintenir l'ancien serveur actif
Ne coupe pas l'ancien serveur tout de suite. Garde-le en lecture seule (ou complet) pendant 48 a 72 heures, le temps que la propagation DNS soit complete sur tous les resolveurs de la planete. Surveille les logs des deux serveurs : si l'ancien n'a plus aucune requete pendant 24h, tu peux le couper en toute tranquillite.
Une astuce que j'utilise : sur l'ancien, je modifie le vhost Nginx pour rediriger toutes les requetes vers le nouveau pendant la fenetre de propagation, en s'appuyant sur le Host et redirigeant en 302 (pas 301, sinon les navigateurs cachent la redirection). Comme ca meme les visiteurs qui arrivent sur l'ancien voient le nouveau site.
Verification post-migration
dig +short monsite.fr @8.8.8.8
dig +short monsite.fr @1.1.1.1
dig +short monsite.fr @9.9.9.9
curl -I https://monsite.fr
curl -vI https://monsite.fr 2>&1 | grep -E 'subject:|expire date'
certbot --nginx -d monsite.fr -d www.monsite.fr
Flush des caches :
wp cache flush --path=/var/www/wordpress
wp transient delete --all --path=/var/www/wordpress
systemctl reload php8.3-fpm nginx
Supprime la ligne dans /etc/hosts local. Demande aux clients (et a Google Search Console) de reverifier la propriete du domaine si necessaire.
Comparaison de comportement avant/apres
Un truc que je fais sur les boutiques sensibles : avant de couper l'ancien serveur, je sauvegarde une vingtaine de pages cles avec wget --recursive --level=2 --no-host-directories --directory-prefix=avant, puis pareil sur le nouveau dans apres/. Un simple diff -r avant/ apres/ me dit si du contenu a saute, si des chemins d'images ont change, si des balises meta ont disparu. C'est rustique mais imparable pour detecter les regressions invisibles a l'oeil nu sur 500 pages.
wget --recursive --level=2 --no-host-directories --directory-prefix=avant https://monsite.fr
# bascule DNS
wget --recursive --level=2 --no-host-directories --directory-prefix=apres https://monsite.fr
diff -r avant/ apres/ | head -50
Audit SEO post-bascule
Dans les jours qui suivent, je surveille systematiquement :
- Search Console : evolution de l'indexation, presence d'erreurs de crawl, augmentation eventuelle des 404.
- Sitemap.xml soumis a nouveau pour acceler la reindexation.
- Trafic sur Matomo ou Plausible : un drop brutal trois jours apres la bascule indique un probleme DNS chez certains resolveurs ou un blocage CDN.
- GTmetrix / PageSpeed sur les principales URL : valider que les performances sont au moins egales a l'ancienne stack.
Erreurs courantes et leur fix
- Boucle de redirection apres la bascule : tu as oublie de mettre a jour
siteurlethome, ou alors un plugin de cache contient encore les anciennes URLs.wp option update homeetwp option update siteurlpuis vide tous les caches (Object Cache, Cloudflare si actif, opcache). - Images cassees : URLs absolues codees en dur dans les contenus avec l'ancien protocole http. Refais un
wp search-replaceciblanthttp://monsite.frvershttps://monsite.fr. - Widgets vides apres migration :
sedutilise au lieu dewp search-replace. Les serializations PHP sont cassees. Reimporte le dump original et refais la replace avec WP-CLI. - Erreur 504 Gateway Timeout sur le back-office :
fastcgi_read_timeouttrop bas dans le vhost Nginx. Mets-le a 300 ou 600 secondes pendant les operations lourdes. - Plugins de cache qui n'ont pas suivi : W3TC, WP Super Cache et consorts gardent des chemins absolus. Desactive-les avant la migration et reactive-les apres avec une config fraiche.
- Erreur 'Error establishing a database connection' : verifie
wp-config.php(DB_HOST, DB_USER, DB_PASSWORD), puis le mot de passe MySQL en te connectant manuellement avecmysql -u wp_user -p wordpress_db. - Crons WordPress ne tournent plus :
DISABLE_WP_CRONest atruedans wp-config et le cron systeme externe n'a pas ete recree. Ajoute dans/etc/cron.d/wordpressune ligne qui appellewp cron event run --due-nowtoutes les 5 minutes.
Pour aller plus loin
La migration n'est qu'une etape. Pour fiabiliser et performer ensuite :
- Optimiser les performances de WordPress — premiere chose a faire apres la migration sur un VPS dedie.
- Securiser WordPress, guide complet anti-hack — profite de la migration pour passer toute la securite en revue.
- Migrer WordPress avec BackWPup — alternative complete pour qui ne fait pas de SSH.
- Changer de domaine WordPress avec WP-CLI — focus sur le cas precis du changement de nom de domaine.
- Configurer Redis comme cache WordPress — pour exploiter pleinement la nouvelle stack.
- Resoudre les boucles de redirection SSL avec Cloudflare — piege classique post-migration.
La migration n'est plus un evenement stressant
Une fois que tu as la methode, migrer un WordPress devient une operation banale, repetable, et sans surprise. Le secret c'est de ne pas vouloir tout faire d'un coup le jour J : prepare le nouveau serveur des le debut, fais des synchros regulieres, teste en avance via /etc/hosts, et baisse le TTL a J-2. La bascule devient alors une formalite de cinq minutes, et tes visiteurs n'auront jamais vu ton site indisponible.
EDIT 2026 : pour les sites de plusieurs Go de base, regarde du cote de mydumper/myloader qui sont beaucoup plus rapides que mysqldump pour l'export/import. Et si tu fais souvent des migrations, automatise tout ca dans un playbook Ansible : tu economiseras des heures sur le long terme. Pour les boutiques WooCommerce avec tres fort trafic, la replication MySQL temporaire entre l'ancien et le nouveau serveur reste la methode reine pour atteindre un downtime mesure en millisecondes.