Sauvegarde Yunohost avec restic

,

EDIT: La version à jour se trouve ici, plus facile à maintenir pour moi: https://gnoobix.net/posts/sauvegarde-yunohost-avec-restic/

Sauvegarde Yunohost avec restic

Sommaire

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 :slight_smile:

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é:

  • En désactivant le login ssh pour le compte utilisateur mytargetuser
  • En limitant la connexion de mytargetuser à une prison sftp

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  
bunzip2 restic_*.bz2 -c > /usr/local/bin/restic
chmod +x /usr/local/bin/restic

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

  • Configurez SSH

Génération d’une paire de clés SSH

ssh-keygen -b 4096 -t rsa -f /root/.ssh/id_rsa_restic -q -N ""

Création du fichier de configuration SSH

cat <<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:

Essai d’initialisation de dépôt sur 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:

  • Utiliser tous les paramètres passés au script ou les supprimer
  • Ajuster la stratégie de nettoyage, je me suis contenté de garder celle du script original avec borg
  • Comprendre l’utilisation des arguments need_mount et mount , je les ai gardés du script d’origine car je me suis dit que c’était utile mais je n’ai pas vraiment saisi comment et pourquoi les utiliser
  • Lancer une vérification des sauvegardes transférées, peut-être dans un script séparé car selon les options choisies elle peut être longue et consommer beaucoup de ressources. Voir la documentation restic à ce sujet

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:

  • Installer 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

EDIT: The up-to-date version here, easier to maintain for me: https://gnoobix.net/en/posts/yunohost-backup-with-restic/

Yunohost restic backup

Table of Contents

Description

This procedure is adapted from this one. I decided to use restic instead of Borg because:

  • I tried the yunohost packaged borg but failed to make it work
  • I did not want to have to install a dependency on the target server, restic only needs a sftp server as target which qualifies to any gnu/linux server with openssh-server installed on.
  • restic has the same features as borg (at least all the ones that matter to me)
  • restic being written in go has no dependency, you copy the binary and that’s it, no packaging problem
  • I was used to restic
  • Why not? It makes an alternative to the existing methods. Everybody is free to choose their favorite one :slight_smile:

The goal here is to backup my Yunohost instance daily and leverage restic’s deduplication and snapshots to keep multiple archives of my data and configuration.

Here we consider the following use case:

  • Backup method: myrestic

  • Server hosting the Yunohost instance to be backed up

    • name mysourceserver
    • address mysourceserver.mysourcedomain.tld
    • private key /root/.ssh/id_rsa_restic
    • public key /root/.ssh/id_rsa_restic.pub
  • Server to backup Yunohost to:

    • Name mytargetserver
    • address mytargetserver.mytargetdomain.tld
    • sftp login user mytargetuser
    • sftp port 2222
    • directory hosting the backup repositories: /home/backup/mysourceserver.mysourcedomain.tld

Adapt those to your needs in the following steps.

You could also use a local directory on an external drive for example and benefit restic’s deduplication and snapshots features.

In that case you would not need any target server configuration other than creating the directory where the backups should be stored on your yunohost server.

You would not need source server ssh configuration either.

Target server configuration

On the server where you want to send your backups

  • Create a user mytargetuser and set its password. Refer to your distribution documentation for this but it should look like something like this:
# as root or using sudo
useradd -m mytargetuser
passwd mytargetuser
  • Create the directory where backups will be stored and make mytargetuser the owner
mkdir /home/backup/mysourceserver.mysourcedomain.tld
chown mytargetuser: /home/backup/mysourceserver.mysourcedomain.tld

Security could be hardened:

  • Disable ssh and shell login for mytargetuser
  • restrain mytargetuser to a sftp jail

Source server configuration

On the Yunohost server to be backed up (all this should be done with the root user):

  • Install restic
cd /tmp
wget https://github.com/restic/restic/releases/download/v0.9.6/restic_0.9.6_linux_amd64.bz2  
bunzip2 restic_*.bz2 -c > /usr/local/bin/restic
chmod +x /usr/local/bin/restic

Update this with the latest release that can be found on the release page and select the one matching your architecture (e.g: linux_arm64 for a raspberry).

Any other installation method would do, check here

  • Configure SSH

Generate an SSH keypair

ssh-keygen -b 4096 -t rsa -f /root/.ssh/id_rsa_restic -q -N ""

Set ssh config file

cat <<EOCONF >> ~/.ssh/config
Host mytargetserver
  Hostname mytargetserver.mytargetdomain.tld
  Port 2222
  User mytargetuser
  IdentityFile /root/.ssh/id_rsa_restic
EOCONF
  • Copy ssh key to target server
ssh-copy-id -i /root/.ssh/id_rsa_restic mytargetserver

Check that everything works up to that point

Now that we have configured both our source and target server, we want to make sure we can actually make a restic backup from source to target.

On mysourceserver as root:

Try to initialize a repository on mytargetserver from mysourceserver

restic -r sftp:mytargetserver:/home/backup/mysourceserver.mysourcedomain.tld/test-repository init

This should ask for a password (use any one you like) and return a success.

Backup script

It’s time to create the script that will backup our system and applications using restic.

  • Create a file /etc/yunohost/hooks.d/backup_method/05-myrestic with this content:
#!/bin/bash

set -e

RESTIC_PASSWORD="mysupersecretpassword"  # change it but DO NOT loose this password, you can't recover it
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

    # Try to list snapshot from repository, otherwise initialize repository
    $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

    # cleanup old archives only if the backup succeeded
    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
  • Make it executable and set safer permissions as it contains sensitive information
chmod u=rwx,go= /etc/yunohost/hooks.d/backup_method/05-myrestic
  • Test it
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

Proceed to the next step only if this ran without errors.

Some warnings may be ignored as this one:

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

this is generated when restic is trying to access the remote repository the first time.

There are still some changes left to be made in that script:

  • Make some use of all the parameters passed to the script or remove them
  • Tune cleanup policy, I kept the one used in the original borg script
  • Understand the use off need_mount and mount arguments, I kept them from the original script as I guess this is a required interface but I am not sure of how to use them and why
  • Add a restic check to make sure backups are consitent but maybe add it to a separate script planed weekly or monthly as this is resource and time consuming you may not want to do it daily. Check restic documentation about that

Scheduled script

Since we know our backup script works, we can schedule it to run daily. The first backup can take a long time to finish depending on the amount of data to be processed. The following backups should be a lot faster since changes will be incremental and take advantage of deduplication for snapshots.

  • Create a file /root/yunohost-99-backup with this content:
#!/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"
  • Make it executable
chmod +x /etc/cron.daily/yunohost-99-backup

I made some changes to the original script:

  • Used a lock file to make sure multiple backups don’t run at the same time
  • I did not directly schedule this script, the reason is given in the note below

I noticed that the gitlab backup spawned a question and required an interaction (a “y” answer) for the backup to proceed.

I looked into the yunohost backup --help with no luck.
I tried some tricks using the yes command or a basic piped echo "y", nothing worked.
Since I want a totally unattented backup script I had to use the expect program to answer this question for me.

This has the advantage of being able to select which question I want to answer.

Note that this question is whether you are okay with taking a little more space temporarily to make the backup.
This could be a problem in a low space environment.

Here’s how to do it

  • Install the expect program
apt install expect -y
  • Create a file /etc/cron.daily/yunohost-99-backup-answerbot with this content
#!/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

This will launch the backup script and automatically answer “y” when prompted.

Restore from backup

You may want or need to restore data from your backups someday.

See official restic documentation for details about the commands.

Here is a simple example for piwigo application restoration.

  • List existing snapshots
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
  • Restore files from 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
  • Check that you have the files restored to temporary directory, choose what to restore and how according to yunohost or package documentation.
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
5 Likes

Salut !
Ça a l’air cool, est-ce que tu prévois une app un jour pour faire tout ça en quelques clics ?
Pour l’instant j’utilise borg sur un DD externe, mais je voudrais mettre en place un backup distant, du coup le simple accès sftp me plait.
Merci !

Salut,

Pour l’instant mes connaissances en packaging Yunohost sont au niveau 0, je vais y jeter un oeil, vu qu’il n’y a pas de conf web ni de SSO à gérer ça ne devrait pas être excessivement compliqué.

1 Like

Salut,

Voici un premier essai de package, j’ai allègrement repompé ce qu’a fait zamentur pour le package borg.
Je l’ai essayé sur mon instance de test, ça a l’air de fonctionner.
Je vais laisser tourner quelques jours et entre temps me renseigner concernant la procédure de tests et d’intégration officielle.

2 Likes

Bonjour,

Je débute sur Yunohost.

Est-ce qu’avec un tel backup, les données utilisateurs sont également sauvegardées? Je pense par exemple aux bookmarks dans Shaarli et aux pages sauvegardées dans Wallabag.

Bonjour,
La méthode de sauvegarde ne définit par ce qui est sauvegardé. En gros avec restic tel que décrit ici tu sauvegarderas la même chose qu’avec la méthode de sauvegarde standard (locale) donc oui tu auras aussi bien ta configuration que tes données.

Mais si tu n’es pas à l’aise avec le concept je te conseille de commencer par la méthode de sauvegarde par défaut et de ne passer à une autre qu’une fois que ça fonctionne et que tu comprends ce qu’il se passe.

Salut !
J’ai testé le package, ça a l’air de bien fonctionner, merci ! J’ai quand même quelques questions :

  • si un backup est en cours et qu’un autre est programmé avant que le premier ne soit terminé, qu’est-ce qu’il fait ? Est-ce qu’il lance une nouvelle instance, ou est-ce qu’il laisse tourner le premier ?
  • Je vais avoir des difficultés à lancer le 1er backup, qui va devoir uploader 400 Go avec un débit d’upload d’environ 2 Mo/s. Donc une bonne 50 aine d’heures ! Et pendant ce temps, ça sature la connexion, donc tous les autres services du serveur sont difficilement voir pas accessbles. Est-ce qu’il y a un moyen de limiter le débit utilisé par Restic ? Qu’est-ce qu’il se passe si je le laisse se lancer tous les jours à minuit et que je l’interrompt à la main le matin ? Est-ce qu’il va reprendre où il en était à chaque re-démarrage ?
  • est-ce que les backups sont chiffrés ?

Merci !

2ème problème : le backup ne se lance plus, j’ai le message d’erreur suivant :

avril 22 01:04:58 lamo systemd[1]: Starting Run backup restic...
avril 22 01:04:58 lamo backup-with-restic[3912]: Backup already launched by process 15162, canceling
avril 22 01:04:58 lamo systemd[1]: restic.service: Main process exited, code=exited, status=1/FAILURE
avril 22 01:04:58 lamo systemd[1]: Failed to start Run backup restic.
avril 22 01:04:58 lamo systemd[1]: restic.service: Unit entered failed state.
avril 22 01:04:58 lamo systemd[1]: restic.service: Failed with result 'exit-code'.

Je n’ai pas de processus 15162 en cours. J’avais interrompu un backup en stoppant le service, je suppose qu’il y a un “lock” qui fait qu’il considère qu’un backup est toujours en cours alors que ça n’est plus le cas ?
Et j’ai voulu tenter des commandes genre “restic unlock”, mais mon repo est accessible en sftp, et je me connecte avec une clé et pas de mot de passe. Je n’arrive pas à lancer la commande restic avec identification par clé, quelqu’un pourrait me donner la commande à entrer ?

Salut,

Effectivement il y a un fichier lock posé dans /tmp/app_restic.lock mais c’est bizarre normalement il y a une fonction qui est censée détecter l’interruption et supprimer le fichier, à moins que tu n’aies fait un kill -9 là effectivement elle ne peut rien faire. Tu dois le supprimer manuellement.

Pour supprimer un lock sur un repo c’est la commande restic -r sftp:serveura/serveurb/auto_<app> unlock il te demandera le mot de passe pour déchiffrer le dépôt, c’est celui que tu as entré lors de l’installation du paquet. Dans le doute tu peux l’avoir avec la commande yunohost app setting restic passphrase.

Pour résumer et répondre clairement aux questions de ton premier message:

  • Si un backup est en cours aucun autre ne se lancera (du moins aucun autre vers le même serveur, si tu installes une autre instance de restic pour sauvegarder vers un autre serveur le fichier de lock aura un autre nom et les deux sauvegardes pourront fonctionner en parrallèle mais je ne pense pas que ce soit souhaitable dans ta situation)
  • Il y a les options --limit-upload et --limit-download visiblement avec restic je vais tâcher de permettre l’utilisation d’options personalisées dans la prochaine version du paquet
  • Les sauvegardes sont bien chiffrées, avec la phrase de passe donnée lors de l’installation

J’ai une autre version en cours, il reste à lui faire passer les tests. Je ne pense pas pouvoir travailler sur le paquet avant ce week-end.

En attendant sii tu veux te débloquer tu peux modifier le fichier /etc/yunohost/hooks.d/backup_method/05-restic_app, ligne 7 remplacer RESTIC_COMMAND=/usr/local/bin/restic par RESTIC_COMMAND=/usr/local/bin/restic --limit-upload 1024 par exemple.

EDIT: Je vais voir comment gérer les locks des dépôts avec le paquet pour simplifier l’usage.

Tiens moi au courant :o)

Merci, j’ai fait un sudo rm /tmp/restic_backup.lock et j’ai pu relancer le backup. Je l’avais interrompu avec sudo service restic stop, est-ce qu’il y a une autre façon pour qu’il s’arrête proprement ?

Cool pour la limite d’upload, je ne savais pas si c’était possible. Par contre pour l’instant ça ne marche pas :
./05-restic_app: ligne 7: --limit-upload : commande introuvable
J’ai bien mis dans 05-restic_app : RESTIC_COMMAND=/usr/local/bin/restic --limit-upload 1024
Et quand je lance le backup, j’ai dans le journal :

./05-restic_app: ligne 7: --limit-upload : commande introuvable
Échec de l’exécution du script : /etc/yunohost/hooks.d/backup_method/05-restic_app

J’ai vérifié, ça marche en supprimant la limite.

Merci beaucoup !

Ok je vois, dans ce cas modifie plutôt la ligne 35: $RESTIC_COMMAND backup ./ > >(tee -a $LOGFILE) 2> >(tee -a $ERRFILE >&2) en $RESTIC_COMMAND --limit-upload 1024 backup ./ > >(tee -a $LOGFILE) 2> >(tee -a $ERRFILE >&2)

Il faut que je revoie cette histoire de service stop qui ne supprime pas le fichier lock du coup.
Merci pour ton retour.

Cool, ça marche cette fois, merci beaucoup ! Je vais laisser tourner le 1er backup le temps qu’il faut, mais au moins il me reste la moitié de la bande passante. Effectivement la limite d’upload pourrait être une option à l’installation.

Pour l’histoire du service stop, ça ne me l’a fait qu’une fois, les autres fois j’ai pas eu de problème, donc peut-être pas la peine de se pencher dessus si ça ne se reproduit pas.

Salut,
Ça a mis presque une semaine, mais le backup s’est bien terminé ! Je reçois maintenant les mails quotidiens de log des backups, et dedans j’ai cette ligne :
avril 28 00:15:02 lamo backup-with-restic[16647]: ls: impossible d'accéder à ' */etc/yunohost/hooks.d/backup/* ': Aucun fichier ou dossier de ce type
C’est pour info, ça n’a pas l’air d’avoir de conséquence.

Salut,
Le backup ne marche plus pour les apps depuis quelques temps, alors qu’il marche bien pour les configs et les données. Voici les logs reçus par mail :

-- Logs begin at Mon 2020-06-08 22:18:29 CEST, end at Tue 2020-06-09 00:28:37 CEST. --
juin 09 00:15:07 serveur backup-with-restic[20746]: ls: impossible d'accéder à '/etc/yunohost/hooks.d/backup/': Aucun fichier ou dossier de ce type
juin 09 00:15:11 serveur slapcat[20820]: DIGEST-MD5 common mech free
juin 09 00:15:11 serveur slapcat[20824]: DIGEST-MD5 common mech free
juin 09 00:15:31 serveur backup-with-restic[20746]: Création d’une archive de sauvegarde à partir des fichiers collectés …
juin 09 00:15:36 serveur backup-with-restic[20746]: subprocess ssh: Warning: Permanently added '[domainebackup.fr]:22,[109.190.7.143]:22' (ECDSA) to the list of known hosts.
juin 09 00:15:44 serveur backup-with-restic[20746]: subprocess ssh: Warning: Permanently added '[domainebackup.fr]:22,[109.190.7.143]:22' (ECDSA) to the list of known hosts.
juin 09 00:15:56 serveur backup-with-restic[20746]: subprocess ssh: Warning: Permanently added '[domainebackup.fr]:22,[109.190.7.143]:22' (ECDSA) to the list of known hosts.
juin 09 00:15:59 serveur backup-with-restic[20746]: Sauvegarde terminée
juin 09 00:15:59 serveur backup-with-restic[20746]: name: auto_conf
juin 09 00:15:59 serveur backup-with-restic[20746]: results:
juin 09 00:15:59 serveur backup-with-restic[20746]:   apps:
juin 09 00:15:59 serveur backup-with-restic[20746]:   system:
juin 09 00:15:59 serveur backup-with-restic[20746]:     conf_cron: Success
juin 09 00:15:59 serveur backup-with-restic[20746]:     conf_ldap: Success
juin 09 00:15:59 serveur backup-with-restic[20746]:     conf_nginx: Success
juin 09 00:15:59 serveur backup-with-restic[20746]:     conf_ssh: Success
juin 09 00:15:59 serveur backup-with-restic[20746]:     conf_ssowat: Success
juin 09 00:15:59 serveur backup-with-restic[20746]:     conf_xmpp: Success
juin 09 00:15:59 serveur backup-with-restic[20746]:     conf_ynh_certs: Success
juin 09 00:15:59 serveur backup-with-restic[20746]:     conf_ynh_currenthost: Success
juin 09 00:15:59 serveur backup-with-restic[20746]:     conf_ynh_firewall: Success
juin 09 00:15:59 serveur backup-with-restic[20746]:     conf_ynh_mysql: Success
juin 09 00:15:59 serveur backup-with-restic[20746]: size: 4589062
juin 09 00:16:00 serveur backup-with-restic[20746]: ls: impossible d'accéder à '/etc/yunohost/hooks.d/backup/': Aucun fichier ou dossier de ce type
juin 09 00:16:49 serveur backup-with-restic[20746]: Création d’une archive de sauvegarde à partir des fichiers collectés …
juin 09 00:16:50 serveur backup-with-restic[20746]: subprocess ssh: Warning: Permanently added '[domainebackup.fr]:22,[109.190.7.143]:22' (ECDSA) to the list of known hosts.
juin 09 00:16:54 serveur backup-with-restic[20746]: subprocess ssh: Warning: Permanently added '[domainebackup.fr]:22,[109.190.7.143]:22' (ECDSA) to the list of known hosts.
juin 09 00:28:27 serveur backup-with-restic[20746]: subprocess ssh: Warning: Permanently added '[domainebackup.fr]:22,[109.190.7.143]:22' (ECDSA) to the list of known hosts.
juin 09 00:28:33 serveur backup-with-restic[20746]: Sauvegarde terminée
juin 09 00:28:33 serveur backup-with-restic[20746]: name: auto_data
juin 09 00:28:33 serveur backup-with-restic[20746]: results:
juin 09 00:28:33 serveur backup-with-restic[20746]:   apps:
juin 09 00:28:33 serveur backup-with-restic[20746]:   system:
juin 09 00:28:33 serveur backup-with-restic[20746]:     data_home: Success
juin 09 00:28:33 serveur backup-with-restic[20746]:     data_mail: Success
juin 09 00:28:33 serveur backup-with-restic[20746]: size: 24050340569
juin 09 00:28:36 serveur backup-with-restic[20746]: usage: yunohost
juin 09 00:28:36 serveur backup-with-restic[20746]:                 {user,domain,app,backup,settings,service,firewall,dyndns,tools,hook,log,diagnosis}
juin 09 00:28:36 serveur backup-with-restic[20746]:                 ...
juin 09 00:28:36 serveur backup-with-restic[20746]:                 [-h] [--no-cache] [--output-as {json,plain,none}] [--debug]
juin 09 00:28:36 serveur backup-with-restic[20746]:                 [--quiet] [--timeout ==SUPPRESS==] [--admin-password PASSWORD]
juin 09 00:28:36 serveur backup-with-restic[20746]:                 [-v]
juin 09 00:28:36 serveur backup-with-restic[20746]: yunohost: error: unrecognized arguments: -b

Une idée de ce qui a pu causer le problème ? Il y a eu plusieurs màj yunohost depuis.
Merci !

Le problème a l’air d’être réglé dans l’app borg, j’ai ouvert une issue sur restic pour faire la même modif : https://github.com/ashemsay/restic_ynh/issues/1
@bleeh est-ce que tu pourrais mettre à jour l’app ?