# Sauvegardes automatisées vers S3 avec WP-CLI, cron et rotation

> Un script de sauvegarde base et fichiers, un envoi vers un stockage objet, une rotation propre, et surtout un test de restauration régulier.

- Auteur : Clément Hadrot
- Publié le : 2021-04-07
- Mis à jour le : 2021-04-07
- Catégorie : Outils &amp; workflow
- URL : https://wpmoderne.dev.wordpress-developpement.fr/outils/sauvegardes-automatisees-s3-wp-cli-cron/

## L’essentiel

- Script bash combinant wp db export et une archive des fichiers
- Rotation automatique pour ne garder que les sauvegardes utiles
- Test de restauration mensuel, la seule vraie garantie

Une sauvegarde qui n'a jamais été restaurée n'est pas une sauvegarde, c'est une hypothèse. Ce constat, découvert à ses dépens par beaucoup de développeurs WordPress le jour où un site est réellement compromis, guide toute la conception d'un système de sauvegarde fiable : automatisation de la capture, envoi hors du serveur d'origine, rotation maîtrisée, et test périodique de restauration. Ce tutoriel construit ce système avec WP-CLI, un script bash et un stockage objet compatible S3, sans aborder la question plus large du plan de reprise d'activité.

L'intérêt d'un stockage objet externe est simple : si le serveur est compromis ou détruit, une sauvegarde stockée sur ce même serveur ne sert à rien. Les sauvegardes doivent vivre ailleurs.

## Exporter la base de données proprement

WP-CLI propose `wp db export`, qui s'appuie sur `mysqldump` en arrière-plan tout en lisant automatiquement les identifiants depuis `wp-config.php` :

```
wp db export /tmp/backup/db-$(date +%Y%m%d-%H%M).sql --allow-root
```

Sur une base volumineuse, il est utile de compresser directement l'export pour économiser du temps de transfert :

```
wp db export - --allow-root | gzip > /tmp/backup/db-$(date +%Y%m%d-%H%M).sql.gz
```

## Archiver les fichiers sans le superflu

> L'essentiel à retenir : Script bash combinant wp db export et une archive des fichiers ; Rotation automatique pour ne garder que les sauvegardes utiles ; Test de restauration mensuel, la seule vraie garantie

Inutile de sauvegarder le cœur de WordPress ou le dossier `node_modules` : ce qui compte, c'est le contenu réellement spécifique au site.

```
tar --exclude='wp-content/cache' \
    --exclude='wp-content/uploads/backups' \
    -czf /tmp/backup/content-$(date +%Y%m%d-%H%M).tar.gz \
    wp-content
```

## Le script complet de sauvegarde

```
#!/bin/bash
set -euo pipefail

DATE=$(date +%Y%m%d-%H%M)
DIR=/var/www/mon-site
BACKUP_DIR=/tmp/backup
BUCKET=s3://mon-bucket-sauvegardes/mon-site

mkdir -p "$BACKUP_DIR"
cd "$DIR"

wp db export - --allow-root | gzip > "$BACKUP_DIR/db-$DATE.sql.gz"
tar --exclude='wp-content/cache' -czf "$BACKUP_DIR/content-$DATE.tar.gz" wp-content

aws s3 cp "$BACKUP_DIR/db-$DATE.sql.gz" "$BUCKET/db-$DATE.sql.gz"
aws s3 cp "$BACKUP_DIR/content-$DATE.tar.gz" "$BUCKET/content-$DATE.tar.gz"

rm -f "$BACKUP_DIR"/*.gz
```

L'option `set -euo pipefail` en tête de script est ce qui évite les catastrophes silencieuses : si `wp db export` échoue, le script s'arrête immédiatement plutôt que d'envoyer une sauvegarde de fichiers seule en pensant que tout s'est bien passé.

## Planifier avec cron

Une tâche cron système, plutôt que WP-Cron, garantit une exécution fiable indépendamment du trafic du site :

```
0 3 * * * /var/www/mon-site/scripts/backup.sh >> /var/log/backup-mon-site.log 2>&1
```

L'heure creuse (3 h du matin ici) limite l'impact de l'export sur les visiteurs, notamment sur une base de données volumineuse où `mysqldump` peut verrouiller temporairement certaines tables.

## Rotation pour éviter un stockage qui explose

Sans rotation, le bucket S3 grossit indéfiniment. La commande AWS CLI `s3 ls` combinée à un petit script permet de ne garder que les trente derniers jours :

```
aws s3 ls "$BUCKET/" | while read -r line; do
  FILE_DATE=$(echo "$line" | awk '{print $1" "$2}')
  FILE_NAME=$(echo "$line" | awk '{print $4}')
  FILE_TIMESTAMP=$(date -d "$FILE_DATE" +%s)
  CUTOFF=$(date -d "30 days ago" +%s)
  if [ "$FILE_TIMESTAMP" -lt "$CUTOFF" ]; then
    aws s3 rm "$BUCKET/$FILE_NAME"
  fi
done
```

Une alternative plus simple, si le stockage objet le permet, consiste à configurer directement une règle de cycle de vie (« lifecycle rule ») côté bucket, qui supprime automatiquement les objets après un délai défini, sans script supplémentaire à maintenir.

## Le test de restauration, l'étape qu'on saute toujours

> La sauvegarde la plus sophistiquée ne vaut rien si personne ne sait, le jour où elle est nécessaire, si elle fonctionne réellement. Je programme un test de restauration mensuel dans un environnement isolé, jamais improvisé en urgence.

Un test de restauration simple, à automatiser également :

1. Télécharger la dernière sauvegarde depuis S3 vers un environnement de test isolé
2. Créer une base de données vide et y importer l'archive SQL
3. Extraire l'archive de fichiers dans un dossier `wp-content` propre
4. Lancer le site et vérifier visuellement qu'il s'affiche correctement, y compris l'administration

Un test qui échoue révèle des problèmes qu'aucune inspection du script de sauvegarde n'aurait montrés : une extension PHP manquante sur l'environnement cible, une version de MySQL incompatible, une archive tronquée par un espace disque insuffisant au moment de la capture.

## En résumé

Un système de sauvegarde fiable combine trois piliers indissociables : une capture automatisée et complète, un stockage réellement externe au serveur d'origine, et une rotation qui empêche les coûts de dériver. Le quatrième pilier, souvent négligé, est le seul qui prouve que les trois premiers fonctionnent vraiment : un test de restauration régulier, effectué avant d'en avoir besoin plutôt qu'après.
