Sauvegarde Yunohost avec Restic
On m’a suggéré de créer un paquet sur le forum suite à cette publication, c’est chose faite! Ce qui suit est toujours vrai mais ce sera bien plus simple d’utiliser le paquet, qui de plus intègre la planification des vérifications des dépôts. Il est encore expérimental donc pour l’installer: Pour l’installer: |
Description
Cette procedure est une adaptation de celle-ci. J’ai décidé d’utiliser restic au lieu de borg parce que:
-
J’ai essayé la version packagée de borg pour Yunohost et je n’ai pas réussi à la faire fonctionner
-
Je ne voulais pas installer de dépendance sur mon serveur cible, restic ne nécessite qu’un accès à un serveur sftp ce que fait n’importe quelle machine avec le paquet openssh-server.
-
restic dispose des mêmes fonctionalités que borg (du moins celles qui m’intéressent)
-
restic étant écrit en go, l’installation se résume à la copie d’un fichier, c’est très simple et évite d’avoir à installer plusieurs autres paquets sur mon serveur yunohost.
-
j’avais déjà utilisé restic et j’en étais content
-
Je peux le faire, tout simplement. Ça fait une alternative de plus aux options existantes. Chacun peut choisir celle qu’il préfère :)
L’objectif ici est de sauvegarder mon instance Yunohost quotidiennement et de tirer partie des fonctionalités de déduplication et de snapshots de restic pour garder de multiples versions de mes configurations et fichiers.
Tout au long de cette procédure, on partira du postulat suivant:
-
Méthode de sauvegarde:
myrestic
-
Server hébergeant l’instance Yunohost à sauvegarder
-
nom
mysourceserver
-
adresse
mysourceserver.mysourcedomain.tld
-
clé privée ssh
/root/.ssh/id_rsa_restic
-
clé publique ssh
/root/.ssh/id_rsa_restic.pub
-
-
Serveur vers lequel on veut sauvegarder Yunohost:
-
nom
mytargetserver
-
adresse
mytargetserver.mytargetdomain.tld
-
utilisateur sftp
mytargetuser
-
port sftp
2222
-
répertoire de stockage des sauvegardes:
/home/backup/mysourceserver.mysourcedomain.tld
-
Pensez bien à adapter ces informations à votre cas dans tout ce qui va suivre
Vous pouvez aussi utiliser un répertoire local (sur un disque dur externe monté par exemple) et bénéficier quand même des fonctionalités de restic. Dans ce cas vous pouvez vous passer de la configuration du serveur cible, il suffit simplement de s’assurer que le répertoire cible de la sauvegarde existe. Vous n’aurez pas non plus besoin de configurer ssh. |
Configuration du serveur cible
Sur le serveur où vous voulez envoyer vos sauvegardes:
-
Créez l’utilisateur
mytargetuser
et définissez son mot de passe. Je vous renvoie à la documentation de votre distribution GNU/Linux pour cela mais pour indication ça devrait ressembler à quelque chose comme ça:# en tant que root ou alors à précéder d'un `sudo ` useradd -m mytargetuser passwd mytargetuser
-
Créez le répertoire de destination des sauvegardes et définissez le propriétaire à
mytargetuser
mkdir /home/backup/mysourceserver.mysourcedomain.tld chown mytargetuser: /home/backup/mysourceserver.mysourcedomain.tld
On pourrait améliorer la sécurité:
|
Configuration du serveur source
Sur le serveur Yunohost à sauvegarder (tout ceci doit être fait en tant que root):
-
Installer restic
cd /tmp wget https://github.com/restic/restic/releases/download/v0.9.6/restic_0.9.6_linux_amd64.bz2 (1) bunzip2 restic_*.bz2 -c > /usr/local/bin/restic chmod +x /usr/local/bin/restic
1 Choisissez la dernière version correspondant à votre architecture sur cette page ( linux_arm64
si vous êtes sur Raspberry Pi par exemple).Vous pouvez choisir n’importe quelle autre méthode d’installation, tout est là -
Configurez SSH
Génération d’une paire de clés SSHssh-keygen -b 4096 -t rsa -f /root/.ssh/id_rsa_restic -q -N ""
Création du fichier de configuration SSHcat <<EOCONF >> ~/.ssh/config Host mytargetserver Hostname mytargetserver.mytargetdomain.tld Port 2222 User mytargetuser IdentityFile /root/.ssh/id_rsa_restic EOCONF
-
Copiez la clé ssh sur le serveur cible
ssh-copy-id -i /root/.ssh/id_rsa_restic mytargetserver
Vérifiez que tout fonctionne jusque-là
Maintenant qu’on a configuré nos serveurs source et de destination, on veut être sûr que restic sait faire des sauvegardes entre les deux.
Sur mysourceserver
en tant que root:
mytargetserver
depuis mysourceserver
restic -r sftp:mytargetserver:/home/backup/mysourceserver.mysourcedomain.tld/test-repository init
Restic devrait vous demander un mot de passe (mettez ce que vous voulez) et terminer sans erreur.
Script de sauvegarde
Il est temps de créer le script qui va sauvegarder l’ensemble de notre instance
-
Créez un fichier
/etc/yunohost/hooks.d/backup_method/05-myrestic
avec ce contenu:#!/bin/bash set -e RESTIC_PASSWORD="mysupersecretpassword" # changez le mot de passe MAIS ne le perdez pas, il est irrécupérable! RESTIC_REPOSITORY_BASE=sftp:mytargetserver:/home/backup/mysourceserver.mysourcedomain.tld RESTIC_COMMAND=/usr/local/bin/restic do_need_mount() { work_dir="$1" name="$2" repo="$3" size="$4" description="$5" export RESTIC_PASSWORD export RESTIC_REPOSITORY=${RESTIC_REPOSITORY_BASE}/$name # On essaie de lister les snapshots, sinon on initialise le dépôt $RESTIC_COMMAND list snapshots || $RESTIC_COMMAND init } do_backup() { work_dir="$1" name="$2" repo="$3" size="$4" description="$5" export RESTIC_PASSWORD export RESTIC_REPOSITORY=${RESTIC_REPOSITORY_BASE}/$name LOGFILE=/var/log/backup_restic.log ERRFILE=/var/log/backup_restic.err current_date=$(date +"%d_%m_%y_%H:%M") pushd $work_dir $RESTIC_COMMAND backup ./ >> $LOGFILE 2>> $ERRFILE return_code="$?" popd # On ne nettoie que si la sauvegarde s'est bien passée if [ "$return_code" -eq "0" ];then $RESTIC_COMMAND forget --keep-daily 7 --keep-weekly 8 --keep-monthly 12 >> $LOGFILE 2>> $ERRFILE fi } work_dir=$2 name=$3 size=$5 description=$6 case "$1" in need_mount) do_need_mount $work_dir $name $repo $size $description ;; backup) do_backup $work_dir $name $repo $size $description ;; mount) do_need_mount $work_dir $name $repo $size $description ;; *) echo "hook called with unknown argument \`$1'" >&2 exit 1 ;; esac exit 0
-
Rendez le script exécutable et limitez-y l’accès puisqu’il contient des informations secrètes
chmod u=rwx,go= /etc/yunohost/hooks.d/backup_method/05-myrestic
-
Testez le script
rm -rf /tmp/test-backup/; mkdir /tmp/test-backup; yunohost backup create --system conf_ldap -n conf_ldap --methods myrestic --debug -r -o /tmp/test-backup; rm -rf /tmp/test-backup
Ne passez à l’étape suivante que si cette commande s’est exécutée sans erreurs.
Il peut subsiter des avertissemnts (Warning), celui-ci peut être ignoré par exemple:
Fatal: unable to open config file: Lstat: file does not exist
Is there a repository at the following location?
sftp:mytargetserver:/home/backup/mysourceserver.mysourcedomain.tld/xxxx
C’est ce que restic affiche quand on essaie d’accéder à un dépôt non initialisé.
Il reste quelques modifications à apporter à ce script selon moi:
|
Script de planification
Puisqu’on sait que notre script de sauvegarde fonctionne, on peut le planifier. La première sauvegarde peut être très longue, ça dépendra du volume de données à transférer. Les sauvegardes suivantes seront beaucoup plus rapides grâce à la déduplication.
-
créez un fichier
/root/yunohost-99-backup
avec ce contenu:#!/bin/bash LOCK_FILE=/tmp/yunohost-99-backup.lock if [ -f "$LOCK_FILE" ];then echo "Backup already launched by process $(grep '.*' $LOCK_FILE), canceling this one" >&2 exit 1 fi echo $$ > "$LOCK_FILE" if yunohost -v | grep "version: 2." > /dev/null; then ignore_apps="--ignore-apps" ignore_system="--ignore-system" else ignore_apps="" ignore_system="" fi filter_hooks() { ls /usr/share/yunohost/hooks/backup/ /etc/yunohost/hooks.d/backup/ | grep "\-$1_" | cut -d"-" -f2 | uniq } # Backup system part conf yunohost backup create $ignore_apps -n auto_conf --methods myrestic --system $(filter_hooks conf) # Backup system data yunohost backup create $ignore_apps -n auto_data --methods myrestic --system $(filter_hooks data) # Backup all apps independently for app in $(yunohost app list --installed -b | grep id: | cut -d: -f2); do backup_methods=$(yunohost app setting $app backup_methods) if [ -z "$backup_methods" ]; then backup_methods=myrestic fi if [ "$backup_methods" != "none" ]; then yunohost backup create $ignore_system -n auto_$app --methods $backup_methods --apps $app fi done rm "$LOCK_FILE"
-
Rendez-le exécutable
chmod +x /etc/cron.daily/yunohost-99-backup
J’ai apporté quelques modifications au script d’origine:
-
J’utilise un fichier de verrou pour éviter le lancement concurrent de plusieurs sauvegardes
-
Je n’ai pas planifié directement ce script pour la raison qui suit
J’ai remarqué que la sauvegarde de gitlab bloquait car elle attendait que je réponde à une question par un "y".
J’ai cherché dans yunohost backup --help
pour savoir comment y répondre sans succès.
J’ai essayé quelques astuces avec la commande yes ou un simple echo "y"
passé à la commande de backup par un pipe, même résultat.
Il fallait absolument que la sauvegarde se fasse sans interaction, j’ai donc utilisé le programme expect pour répondre à la question pour moi.
Ça a l’avantage d’être sûr de la question à laquelle on répond
Pour info la question est une demande de confirmation avant de prendre un peu plus d’espace disque que prévu temporairement pour faire la sauvegarde. Si vous êtes juste en place ça peut poser problème.
Voilà comment faire:
-
Install expect
apt install expect -y
-
Créer un fichier
/etc/cron.daily/yunohost-99-backup-answerbot
avec ce contenu#!/usr/bin/expect -f set timeout -1 spawn /root/yunohost-99-backup expect -re "Some files couldn't be prepared.*Do you agree?" send -- "y\r" expect eof
Ce script va lancer le script de sauvegarde et répondre par "y" quand on lui demandera.
Restauration d’une sauvegarde
Vous pouriez avoir envie (ou besoin) de restaurer des données d’une sauvegarde (c’est tout l’intérêt :p)
Je vous renvoie à la documentation officielle pour les détails des commandes.
Voici un simple exemple de restauration pour l’application Piwigo
-
Listez les snapshots existants
restic -r sftp:mytargetserver:/home/backup/mysourceserver.mysourcedomain.tld/auto_piwigo snapshots # enter password for repository: # repository xxxxxx opened successfully, password is correct # created new cache in /home/mytargetuser/.cache/restic # ID Time Host Tags Paths # ------------------------------------------------------------------------------------------------------------------- # yyyyyyyy 2020-02-10 22:03:22 mysourceserver.mysourcedomain.tld /home/yunohost.backup/tmp/auto_piwigo # ------------------------------------------------------------------------------------------------------------------- # 1 snapshots
-
Restaurez à partir du snapshot
yyyyyyyy
mkdir /tmp/restore restic -r sftp:mytargetserver:/home/backup/mysourceserver.mysourcedomain.tld/auto_piwigo restore yyyyyyyy --target /tmp/restore # enter password for repository: # repository xxxxxx opened successfully, password is correct # restoring <Snapshot yyyyyyyy of [/home/yunohost.backup/tmp/auto_piwigo] at 2020-02-10 22:03:22.602905984 +0100 CET by root@mysourceserver.mydomain.tld to /tmp/restore
-
Vérifiez que vos fichiers se trouvent bien dans le répertoire de restauration temporaire, référez-vous à la documentation de Yunohost ou du paquet de l’application pour savoir où et quels fichiers restaurer.
tree /tmp/restore/ -L 4 # /tmp/restore/ # ├── apps # │ └── piwigo # │ ├── backup # │ │ ├── db.sql # │ │ ├── etc # │ │ ├── home # │ │ └── var # │ └── settings # │ ├── conf # │ ├── manifest.json # │ ├── scripts # │ ├── settings.yml # │ └── status.json # ├── backup.csv # └── info.json # # 9 directories, 6 files