~rom1v/blog { un blog libre }

Duplicity : des backups incrémentaux chiffrés

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 --partial-dir=/my/local/tmpbackup --ignore-existing --stats \
    -h server:/var/backups/duplicity/ /my/local/backup/

--ignore-existing évite de récupérer des modifications malicieuses des backups sur le serveur (ils ne sont pas censés être modifiés). Du coup, il faut aussi faire attention à sauvegarder les transferts partiels ailleurs (--partial-dir), sans quoi ils ne se termineront jamais.

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 !

Commentaires

Fred

Une sauvegarde complète par mois et une incrémentale chaque jour ? Du coup, si votre complète est corrompue pour une raison X ou Y, vous perdez un mois complet de backup. Je crains aussi un peu le temps de restauration de l’incrémentale 29 (la veille de la nouvelle complète, en général quand on a la poisse, on a l’a pour de bon).

Signé un adepte de la méthode barbare (une complète par jour :p)

arno

Très intéressant, merci ; ça semble correspondre à ce que je veux faire :)

Je pense que je ferai une complète tous les 10 jours par cron, et des différentielles entre.

Par contre, j’ai une question : un conseil pour la partie “sauvegarde distante” ? J’envisage d’installer un raspberry pi chez quelqu’un de ma famille, mais ça ne me paraît pas adapté, pour une simple solution de backup distant…

À moins de l’utiliser en redondance avec le mien, mais comment fait-on ça ?

Cascador

Hello All,

Tout à fait d’accord avec Fred, je trouve que la mode de s’amuser avec des sauvegardes différentielles/incrémentales est une absurdité (je ne dis pas ça méchamment of course). J’ai souvent l’impression que les particuliers se basent sur les pratiques des professionnels alors que ce n’est pas du tout les mêmes contraintes.

Professionnellement, je fais comme Fred càd sauvegarde complète dans 98 % des cas :

  • C’est simple à restaurer, il y a tout et la simplicité est trop souvent un critère négligée. Tu sauvegardes simplement, tu débugges ton script et tes problèmes de sauvegarde simplement et enfin (le plus important de tous) tu fais des tests de restauration simplement (et du coup plus souvent/régulièrement)
  • Si tu as un problème le jeudi avec ton serveur alors que tu fais des sauvegardes incrémentales, il faut que tu remontes ta complète du vendredi précédent ou du mois précédent pour recharger ensuite tous les jours écoulés. What the fuck ? En entreprise, c’est une blague, bonjour la perte de temps et si tu as une seule sauvegarde échouée entre les deux dates : Game Over !
  • Dernier argument, ça reste complexe de gérer une restauration à base d’une complète + les autres différentielles (on se dit toujours facile avec des données mais lorsque tu as une base SQL ou une base Exchange à remonter avec complète + différentielles, tu es tout de suite bien moins serein). Ne nous le cachons pas, la sauvegarde est entrée dans les moeurs même chez les particuliers, ce qui est évidemment une très bonne chose. Cependant, la pierre angulaire d’une bonne sauvegarde c’est de tester la restauration et ça, 1 personne sur 2 ne le fait pas (y compris chez les professionnels) donc autant que ce soit le plus simple et compréhensif possible

@Rom1 : Super tuto sur Duplicity !

@arno : Je suppose que tu t’es penché sur les sauvegardes dans le cloud ? Ca commence à devenir intéressant (CrashPlan, SugarSync)

Tcho !

arno

@Cascador : non, je ne connaissais pas. Mais ça ne m’inspire pas plus confiance que gdrive ou skytruc : sans doute à tort, je préfère savoir où sont physiquement mes données (dans la famille ou chez un ami), même si elles sont chiffrées…

®om

@Cascador

Professionnellement, je fais comme Fred càd sauvegarde complète dans 98 % des cas :

  • C’est simple à restaurer, il y a tout et la simplicité est trop souvent un critère négligée. […]
  • Si tu as un problème le jeudi avec ton serveur alors que tu fais des sauvegardes incrémentales, il faut que tu remontes ta complète du vendredi précédent ou du mois précédent pour recharger ensuite tous les jours écoulés. What the fuck ?

La restauration par duplicity est transparente que tu utilises des sauvegardes incrémentales ou non.

@Fred

Je crains aussi un peu le temps de restauration de l’incrémentale 29 (la veille de la nouvelle complète, en général quand on a la poisse, on a l’a pour de bon).

Je viens de comparer la restauration du 31 juillet (donc 1 complète avec 30 incrémentales) avec celle du 1er août (1 complète seule) :

time duplicity restore -t 2013-08-01T12:00:00+02:00 \
  file:///var/backups/duplicity/ restore1/
time duplicity restore -t 2013-07-31T12:00:00+02:00 \
  file:///var/backups/duplicity/ restore2/

La complète a mis 5mn06s. La complète avec 30 incrémentales, 7mn49s. Donc on s’en fiche, ça reste rapide (la restauration est un événement rare).

À côté de ça, 15Mio par jour au lieu de 1.4Gio c’est appréciable (surtout à transférer sur des machines distantes avec une connexion ADSL) !

@Fred

Du coup, si votre complète est corrompue pour une raison X ou Y, vous perdez un mois complet de backup.

Oui. C’est un risque que je prends (j’ai confiance en duplicity), la différence de taille entre les sauvegardes incrémentales et complètes étant vraiment importante. Le risque reste cependant mesuré : je n’ai pas tant de données qui changent d’un mois sur l’autre sur mon serveur.

@Cascador

Dernier argument, ça reste complexe de gérer une restauration à base d’une complète + les autres différentielles (on se dit toujours facile avec des données mais lorsque tu as une base SQL ou une base Exchange à remonter avec complète + différentielles, tu es tout de suite bien moins serein).

C’est justement un gros point fort de duplicity (comme je l’explique dans le billet). Si les bases de données ne sont pas trop grosses (si tu as 600Go de données, ce n’est pas la peine), tu peux éviter de gérer manuellement les sauvegardes incrémentales des bases de données : dans chaque version tu mets un dump complet et duplicity ne sauvegardera que les blocs différents.

@arno

Par contre, j’ai une question : un conseil pour la partie “sauvegarde distante” ? J’envisage d’installer un raspberry pi chez quelqu’un de ma famille, mais ça ne me paraît pas adapté, pour une simple solution de backup distant…

À moins de l’utiliser en redondance avec le mien, mais comment fait-on ça ?

Un Raspberry π ferait très bien l’affaire je pense (de préférence avec un disque dur). Personnellement, je récupère les backups sur mon pc perso avec rsync, puis je redispatche vers d’autres machines.

Salut tous!

Bah j’utilise “dar” pour faire des backups.

Full tout les dimanches, Incrémental les autres jours.

Mais le plus marrant, c’est que je balance mes backups (chiffrés) sur http://dl.free.fr

Il reste 1 mois minimum bien au chaud sur les serveurs de Free, et je suis notifié par mail de chaque transfert.

A+

Fred

Merci pour les précisions. Je vais quand même faire mon lourdingue en disant que pour 1,4 Go de données, on peut faire du backup complet quotidien :p

Mon credo est de dire que le stockage ne coûte pas cher, sauf si vous voulez du stockage rapide (SSD, disques à 15k tours, SAN…). Côté pro, j’ai 1,2 To de données à gérer (fichiers, boites mail, multiples BDD) et je fais quand même du complet chaque jour pour pas très cher (dans un contexte perso, ça peut être vécu autrement) avec rsync. Par contre, je commence à atteindre un cap côté performances et synchro des scripts des différents serveurs, du coup je me fais ma petite veille sur des outils comme celui-ci

La complète a mis 5mn06s. La complète avec 30 incrémentales, 7mn49s. Donc on s’en fiche, ça reste rapide (la restauration est un événement rare).

A peu près 50% plus lent avec 29x15 Mo d’incrémentales. Curieux de voir si quelqu’un a des stats avec de plus gros volumes. En tout cas, merci pour ces infos, très instructif.

C’est simple à restaurer, il y a tout et la simplicité est trop souvent un critère négligée.

Ah, voilà un commentaire qui me fait bien plaisir. C’est beaucoup de travail de faire des choses simples et efficaces :)

Pour ma part, je fais des sauvegardes pseudo-incrémentales avec des liens en dur.

Ca ressemble en tant qu’utilisateur à du non incrémentale, mais pour le disque c’est bel et bien de l’incrémental. Si une sauvegarde plante, on ne brise pas les autres sauvegardes.

Cascador

Hello All,

Je persiste et signe comme Fred et je donne modestement mon point de vue sur ce que tu pourrais faire :

  • Tu met en place une rotation de tes sauvegardes (càd une copie des données que tu souhaites sauvegarder avec une gestion dans le temps) sur les 3 derniers jours sur ton serveur en local. Tu utilises une variable comme ça DATE="$(date +"%d-%m-%Y" )" dans le nom de tes répertoires (ça va te donner 16-08-2013, 17-08-2013 etc.) puis toujours dans le même script tu purges les dossiers plus vieux de 3 jours (find $DEST_BACKUP -maxdepth 1 -type d -mtime +3 -exec rm -frv {} \;)
  • Second script du côté de ton poste à ton domicile, tu synchronises toujours le même dossier du côté de chez toi et du côté de ton serveur dédié ainsi les différences sont minimes (comme si tu faisais une sauvegarde incrémentale ou différentielle) mais tu as une sauvegarde complète de chaque côté (c’est du mirroring quoi). Je pense que tu l’auras compris mais du côté de ton domicile le nom du dossier de ta sauvegarde ne bougera jamais et du côté de ton serveur dédié, tu utilises la variable DATE pour faire la sauvegarde. Tu reprends ton premier script et tu met en place une rotation sur 7 jours sur ton poste en local
  • Troisième script (ultra-simple donc inutile de crier lol), tu copies les dossiers en “matchant” avec cp le nom de tes dossiers 01-, 08-, 15-, 22-, 29- afin d’avoir un dossier avec tes sauvegardes hebdomadaires (sauvegardes du premier jour de chaque mois, du 8 de chaque mois etc.). Ca donnera cp -pR $DEST_BACKUP'/'$NOM_BACKUP'_01-* $WEEKLY_BACKUP'/'

Pour résumer :

  • Tu as une tâche cron sur ton serveur dédié et 2 tâches cron sur ton poste à ton domicile
  • Tu as 3 sauvegardes complètes sur ton serveur en local (soit moins de 5 Go). Tu as 7 sauvegardes complètes sur ton poste à ton domicile pour les 7 derniers jours (soit moins de 10 Go) ainsi que 4 sauvegardes complètes pour les 4 dernières semaines (soit moins de 6 Go)
  • Tu as des scripts simples (avec des outils ultra-connus comme cp, rsync ou duplicity) et réutilisables pour d’autres serveurs
  • Tu as une méthode de sauvegarde 4 étoiles, increvable, facile à restaurer
  • Tu peux évidemment te passer du troisième script
  • Tout cela en ne consommant pas beaucoup d’espace sur tes machines et en minimisant le trafic réseau (dans ce cas via internet) pour la sauvegarde distante à ton domicile

Tcho !

®om

@Cascador En résumé, tu proposes d’écrire manuellement une solution de sauvegardes non incrémentales et non chiffrées. Pour quels avantages ?

J’utilisais un peu de genre de scripts manuels avant d’utiliser duplicity… D’ailleurs, de mémoire, c’est un peu ce que font rdiff-backup et rsnapshot.

[…] Duplicity : des backups incrémentaux chiffrés […]

sybix

o/

Juste pour dire que GPG est vraiment une meilleurs solution.

Effectivement le chiffrement asymétrique te demande deux fichiers. Une clefs publique et une clefs privé. Si tu génère ta paire de clefs sur la machine qui te sers a stocker les backup. Tu transfère seulement la clef publique sur le serveur. La clef publique sers à chiffrer les données pour la clef privé, mais ne pourras pas les déchiffrer. Et il est plus dure de casser une clef gpg que de brute forcer un chiffrement symétrique. Bien entendu, il faut quand même avoir la possibilité de sauvegarder au moins la clefs privé, si tu prends en compte que le serveur de backup peux être défaillant en même temps qu’un incident sur le serveur principal.

®om

@sybix

Juste pour dire que GPG est vraiment une meilleurs solution.

Pour être précis, qu’on utilise le chiffrement symétrique ou asymétrique ici, il s’agit toujours de gpg (avant d’écrire ce billet je croyais aussi que gpg ne supportait que l’asymétrique).

@sybix

Tu transfère seulement la clef publique sur le serveur.

En fait, le serveur a également besoin de la clé privée. D’abord parce qu’il signe les backups (apparemment, duplicity ne permet pas de chiffrer sans signer), ensuite parce pour une sauvegarde incrémentale il a besoin de lire les anciens backups (à vérifier quand même, peut-être qu’il garde des données non chiffrées en cache).

Bonsoir,

Pour ceux qui souhaitent utiliser duplicity sans trop mettre les mains dans le cambouis, il y a duply, une surcouche pour duplicity.

Cela permet notamment de gérer facilement des profils et l’export des données via de nombreux protocoles.

Je l’utilise personnellement pour gérer les backups de ma dédibox vers l’espace FTP de backup proposé par mon hébergeur, cela fonctionne parfaitement bien !

Très bon article !

[…] faisant ma ronde habituelle sur le planet Ubuntu, je suis tombé sur un article de Romain Vimont détaillant l’utilisation de duplicity, que j’utilise actuellement […]

grou

Très bon article, merci pour ces infos :)

Ce qui me chagrine un peu, c’est que l’on s’efforce a chiffrer ses sauvegardes et que l’on met le mot de passe de la clé GPG dans un script…

beaucoup utilisent la fonction “export password” et “unset password” mais je ne trouve cela pas top..

N’y a t’il pas d’autres solutions ?

Les commentaires sont fermés.