backup

Quiconque s’auto-héberge doit maintenir un système de sauvegarde de son serveur, permettant de tout remettre en place dans le cas d’un crash de disque dur, d’un piratage ou d’un cambriolage.

Objectifs

Il est nécessaire de sauvegarder à la fois des fichiers (les mails, les services hébergés, les fichiers de config…) et le contenu de bases de données (associées aux services hébergés).

Le système de sauvegarde doit conserver les archives durant un certain temps (par exemple 2 mois). En effet, un piratage ou une erreur de manipulation peuvent n’être détectés que quelques jours plus tard : il est important de pouvoir restaurer un état antérieur.

La sauvegarde doit être régulière (par exemple quotidienne).

Seule une infime partie des données étant modifiées d’un jour à l’autre, la sauvegarde a tout intérêt à être incrémentale.

Pour résister aux cambriolages, une sauvegarde doit être réalisée sur (au moins) une machine distante. Il est donc préférable que ces données soient chiffrées.

Duplicity

Vous l’aurez compris, duplicity répond à tous ces besoins.

Je ne vais pas expliquer tout ce qu’il sait faire, mais plutôt comment je l’utilise et pourquoi.

Mes choix d’utilisation

Sauvegarde locale

Personnellement, je n’effectue qu’une sauvegarde locale dans une tâche cron, c’est-à-dire que les fichiers de backups sont stockés sur le serveur lui-même.

En effet, une sauvegarde automatique vers un serveur distant, par SSH par exemple, nécessiterait une clé privée en clair sur le serveur. Cette configuration ne résisterait pas à certains piratages : une intrusion sur le serveur donnerait également accès aux sauvegardes, permettant à un pirate d’effacer à la fois les données et les backups.

C’est donc une autre machine, à l’initiative de la connexion, qui rapatrie les backups. Évidemment, elle ne doit pas synchroniser localement les backups supprimés du serveur (elle serait vulnérable à la suppression des backups par un pirate), mais doit plutôt supprimer les anciennes sauvegardes de sa propre initiative.

Chiffrement

Duplicity utilise GPG pour le chiffrement, permettant :

Le premier choix nécessite à la fois quelque chose que je possède (la clé, de forte entropie) et quelque chose que je connais (la passphrase, de plus faible entropie). Le second ne nécessite que la passphrase à retenir.

L’utilisation d’une clé privée autorise donc une meilleure sécurité, notamment si vous souhaitez envoyer vos backups sur un serveur américain.

Néanmoins, les backups sont surtout utiles lors de la perte de données, notamment dans le cas d’un cambriolage, où la clé GPG a potentiellement également disparu. Et les sauvegardes distantes ne seront d’aucune utilité sans la clé…
Il peut donc être moins risqué d’opter, comme je l’ai fait, pour une simple passphrase.

À vous de placer le curseur entre la protection de vos données et le risque de ne plus pouvoir les récupérer.

Installation

Sur une Debian :

sudo apt-get install duplicity

Fonctionnement

Duplicity effectue des sauvegardes complètes et incrémentales. Les sauvegardes incrémentales nécessitent toutes les sauvegardes depuis la dernière complète pour être restaurées.
Personnellement, j’effectue une sauvegarde complète tous les mois, et une incrémentale tous les jours.

Pour choisir le mode :

  • duplicity full … force une sauvegarde complète ;
  • duplicity incr … force une sauvegarde incrémentale (échoue si aucune complète n’est trouvée) ;
  • duplicity … effectue une sauvegarde incrémentale si possible, complète sinon.

Exemple (à exécuter en root pour avoir accès à tous les fichiers) :

duplicity / file:///var/backups/duplicity/ --include-globbing-filelist filelist.txt --exclude '**'

Duplicity va sauvegarder à partir de la racine ("/") tous les fichiers selon les règles d’inclusion et d’exclusion définies dans filelist.txt. Ce fichier contient simplement la liste des fichiers et répertoires à sauvegarder, ainsi que ceux à exclure. Par exemple :

/usr/local/bin/
/home/rom/Maildir/
/home/rom/.procmailrc
- /var/www/blog/wp-content/cache/
/var/www/blog/

Attention : les fichiers et répertoires à exclure doivent apparaître avant l’inclusion d’un répertoire parent. En effet, duplicity s’arrête à la première règle qui matche un chemin donné pour déterminer s’il doit l’inclure ou l’exclure.

Pour restaurer :

duplicity restore file:///var/backups/duplicity/ /any/directory/

(utiliser l’option -t pour restaurer à une date particulière)

Pour supprimer les anciennes sauvegardes (ici de plus de 2 mois) :

duplicity remove-older-than 2M file:///var/backups/duplicity/ --force

Bases de données

Tout comme pour les fichiers, il est préférable de sauvegarder incrémentalement les bases de données (seule une toute petite partie des données change d’un jour à l’autre).

Une première solution serait d’utiliser la fonctionnalité-qui-va-bien de votre SGBD.

Mais si le contenu de vos bases de données ne dépasse pas quelques Go (ce qui est très probable pour de l’auto-hébergement), duplicity permet de faire beaucoup plus simple.

Il suffit en effet de générer un dump complet des bases de données vers des fichiers .sql et d’inclure leur chemin dans la liste des fichiers à sauvegarder. Et là, c’est magique, duplicity va ne sauvegarder que les parties de ces (gros) fichiers qui ont changées, grâce à rsync et à son algorithme qui utilise des rolling checksums.

Bien sûr, il ne faut pas compresser ces fichiers avant de les donner à manger à duplicity (sinon l’intégralité du fichier risque de changer) ; c’est lui qui va s’en charger. De même, il vaut mieux éviter d’inclure dans les fichies SQL des informations liées au dump, comme sa date de génération.

Pour exporter une base de données MySQL par exemple :

mysql -uroot -ppassword --skip-comments -ql my_database > my_database.sql

Script

Il reste donc à écrire un script qui exporte les bases de données et qui appelle duplicity avec la liste de ce qu’il y a à sauvegarder.

Voici un prototype, à sauvegarder dans /usr/local/bin/backup :

#!/bin/bash
BACKUP_HOME=/var/backups
TMP_DBDIR="$BACKUP_HOME/dbdump"
BACKUP_DIR="$BACKUP_HOME/duplicity"
MYSQLPW=mon_password_mysql
PASSPHRASE=ma_passphrase_de_chiffrement_des_backups
DATABASES='blog autre_base'
FILELIST="/usr/local/bin/
/home/rom/Maildir/
/home/rom/.procmailrc
- /var/www/blog/wp-content/cache/
/var/www/blog/
$TMP_DBDIR/"

# databases
mkdir -p "$TMP_DBDIR"
for dbname in $DATABASES
do
  printf "## Dump database $dbname...\n"
  mysqldump -uroot -p"$MYSQLPW" --skip-comments -ql "$dbname" \
    > "$TMP_DBDIR/$dbname.sql"
done

# duplicity
printf '## Backup using duplicity...\n'
unset mode
[ "$1" = full ] && mode=full && printf '(force full backup)\n'
mkdir -p "$BACKUP_DIR"
export PASSPHRASE
duplicity $mode / file://"$BACKUP_DIR"/ \
  --include-globbing-filelist <(echo "$FILELIST") --exclude '**'

printf '## Delete old backups\n'
duplicity remove-older-than 2M file://"$BACKUP_DIR"/ --force

# backups are encrypted, we can make them accessible
chmod +r "$BACKUP_DIR"/*.gpg

# remove temp files
rm "$TMP_DBDIR"/*.sql

Une fois configuré, ne pas oublier de tester : exécuter le script et restaurer les données dans un répertoire de test, puis vérifier que tout est OK. Cette vérification doit être effectuée de temps en temps : il serait dommage de s’apercevoir, lorsqu’on en a besoin, que les backups sont inutilisables ou qu’un répertoire important a été oublié.

Cron

Pour démarrer automatiquement une sauvegarde complète le premier jour du mois et une incrémentale tous les autres jours, cron est notre ami :

sudo crontab -e

Ajouter les lignes :

0 1 1    * * /usr/local/bin/backup full
0 1 2-31 * * /usr/local/bin/backup

La première colonne correspond aux minutes, la deuxième aux heures : le script sera donc exécuté à 1h du matin. La 3e correspond au numéro du jour dans le mois. Les deux suivantes sont le numéro du mois dans l’année et le jour de la semaine.

Il peut être préférable d’exécuter le script en priorité basse :

0 1 1    * * nice -15 ionice -c2 /usr/local/bin/backup full
0 1 2-31 * * nice -15 ionice -c2 /usr/local/bin/backup

Copies

Il ne reste plus qu’à effectuer des copies des fichiers de backups ailleurs.

À partir d’une autre machine, le plus simple est d’utiliser rsync (sans l’option --delete !) :

rsync -rvP --stats -h server:/var/backups/duplicity/ /my/local/backup/

Pour supprimer les anciens backups sur cette machine, c’est la même commande que sur le serveur :

duplicity remove-older-than 2M file:///my/local/backup/ --force

Conclusion

La génération de sauvegardes à la fois incrémentales et chiffrées, y compris pour les bases de données, font de duplicity une solution de backup idéale pour l’auto-hébergement.

Je l’utilise depuis plusieurs mois, et j’en suis très satisfait (même si je n’ai pas encore eu besoin de restaurer les backups en situation réelle).

À vos backups !