Tous les projets WordPress ne bénéficient pas d’un VPS avec accès SSH complet. Une part non négligeable tourne encore sur de l’hébergement mutualisé classique, où seul le FTP ou le SFTP est disponible, sans possibilité d’exécuter des commandes shell arbitraires côté serveur. Cette contrainte ne condamne pas pour autant à un déploiement manuel par glisser-déposer : un pipeline CI combiné à lftp peut automatiser la synchronisation, avec un niveau d’atomicité raisonnable même dans ce contexte limité. Deployer, qui suppose un accès SSH, ne s’applique pas ici.
Pourquoi pas un simple rsync ou FileZilla scripté
rsync nécessite SSH pour fonctionner efficacement en delta-sync, une option rarement disponible sur un mutualisé standard. lftp, en revanche, sait dialoguer en SFTP (SSH pour le seul transfert de fichiers, souvent ouvert même quand le shell complet ne l’est pas) ou en FTPS, avec une fonctionnalité clé pour la CI : la reprise automatique en cas de coupure réseau et un mode miroir qui ne transfère que les fichiers modifiés.
Script de synchronisation avec lftp

Le principe : la chaîne de déploiement construit le site (installation des dépendances avec Composer, compilation des ressources), puis un script envoie le résultat dans un dossier de release horodaté, sans toucher au site en ligne. Seule la dernière étape, très courte, le fait basculer. Les identifiants sont fournis par des variables secrètes de la CI, jamais écrits dans le dépôt :
#!/usr/bin/env bash
set -euo pipefail
RELEASE="releases/$(date -u +%Y%m%d%H%M%S)"
lftp -u "$SFTP_USER","$SFTP_PASS" "sftp://$SFTP_HOST" <<EOF
set sftp:auto-confirm yes
set net:max-retries 5
set net:reconnect-interval-base 5
set net:timeout 30
mkdir -p $RELEASE
mirror --reverse --continue --parallel=4 --verbose \
--exclude-glob .git/ \
--exclude-glob node_modules/ \
--exclude-glob wp-content/uploads/ \
./build $RELEASE
bye
EOF
Quelques options méritent d’être comprises. mirror --reverse envoie le dossier local vers le serveur, et non l’inverse. --continue reprend un transfert interrompu au lieu de le recommencer, ce qui vaut de l’or sur une liaison instable. --parallel=4 ouvre quatre transferts simultanés ; certains mutualisés limitent le nombre de connexions, il faut alors redescendre à deux. Les paramètres net:max-retries et net:timeout évitent qu’une coupure brève fasse échouer toute la chaîne. Enfin, set sftp:auto-confirm yes accepte la clé de l’hôte à la première connexion : c’est pratique en CI, mais mieux vaut, dès que possible, enregistrer l’empreinte attendue du serveur.
Avant le premier déploiement réel, ajoutez --dry-run à la commande mirror : lftp liste ce qu’il ferait sans rien transférer.
La bascule : trois niveaux d’atomicité
Sur un serveur dédié, on change la cible d’un lien symbolique et la bascule est instantanée. Sur un mutualisé, tout dépend de ce que l’hébergeur autorise. On choisit donc selon le cas :
- Le lien symbolique, si le serveur SFTP accepte d’en créer. lftp propose une commande
ln -s, mais certains hébergeurs la refusent ou ne suivent pas les liens hors du répertoire du site. Testez-le une fois à la main avant de bâtir le reste dessus. - Le double renommage. Si le dossier du site est un sous-dossier que vous pouvez renommer, deux commandes
mvéchangent les dossiers. L’opération n’est pas strictement atomique, mais la fenêtre d’indisponibilité se compte en fractions de seconde. - La synchronisation directe, en dernier recours. On envoie les fichiers de code puis, à la fin, le point d’entrée
index.php, avec--only-newer. Le site reste en ligne pendant le transfert, avec un risque de mélange temporaire de versions : à réserver aux sites à faible trafic.
Voici la bascule par double renommage, exécutée une fois la release entièrement transférée et vérifiée :
lftp -u "$SFTP_USER","$SFTP_PASS" "sftp://$SFTP_HOST" <<EOF
set sftp:auto-confirm yes
mv www www_precedent
mv $RELEASE www
bye
EOF
Le retour arrière est le geste inverse : rendre à www_precedent son nom. C’est ce qui justifie de conserver les deux ou trois dernières releases et de supprimer les plus anciennes par une commande rm -r en fin de script.
Ce qui ne doit jamais être écrasé
Un site WordPress possède des éléments vivants, qui n’appartiennent pas au dépôt : le fichier wp-config.php, le dossier wp-content/uploads, parfois des caches. La release ne doit ni les contenir ni les effacer. Avec un lien symbolique, on relie simplement le dossier uploads de la release au dossier partagé. Sans lien symbolique, le dossier uploads reste dans le site en ligne, et c’est pourquoi la commande ci-dessus l’exclut : l’envoi ne le touche pas, mais un échange de dossiers l’emporterait. Dans ce cas, déplacez plutôt uniquement le contenu de code, ou copiez de nouveau le dossier uploads dans la nouvelle release avant la bascule.
Vérifier, puis assumer l’échec
Une bascule sans contrôle n’est qu’un espoir. La dernière étape de la chaîne interroge le site et échoue franchement si la réponse n’est pas celle qu’on attend :
CODE=$(curl -s -o /dev/null -w '%{http_code}' https://www.exemple.fr/)
if [ "$CODE" != "200" ]; then
echo "Contrôle en échec (HTTP $CODE) : retour arrière." >&2
# exécuter ici le retour arrière (mv inverse) puis quitter en erreur
exit 1
fi
Un déploiement fiable ne promet pas de ne jamais échouer ; il promet que l’échec se repère vite et se défait en une commande.
Les pièges du mutualisé
- Le cache d’opcodes. Après un changement de dossier, PHP peut continuer à servir d’anciens fichiers compilés pendant le délai de revalidation défini par l’hébergeur. Testez après bascule et, si l’hébergeur le propose, videz le cache depuis son interface.
- Les droits et propriétaires. Certains serveurs SFTP appliquent des droits par défaut différents de ceux du transfert manuel : vérifiez que PHP peut lire les fichiers de la release.
- Les limites de connexion. Trop de transferts en parallèle provoquent des refus. Réduisez
--parallelau besoin. - Le mot de passe en ligne de commande. L’option
-uexpose le mot de passe dans la liste des processus de la machine de CI ; privilégiez une clé SSH dédiée au déploiement quand l’hébergeur l’accepte.
Conclusion
Même sans accès SSH complet, un déploiement reproductible est possible : lftp pour un transfert reprenable, un dossier de release horodaté pour ne jamais toucher le site en cours de route, et une bascule aussi atomique que l’hébergeur le permet. L’essentiel est de savoir ce que votre mutualisé autorise réellement, d’adapter le niveau d’atomicité en conséquence, et de garder toujours un retour arrière à portée de commande.