Description

Il faut disposer d’un serveur debian que nous appellerons serveur source qui se connectera (via ssh + clés) et exécutera, via le planificateur (cron), des sauvegardes de serveurs distants (via rsync) dans un dossier de sauvegarde du serveur source

Serveur distant

Les opérations suivantes sont à faire sur tous les serveurs distants

Vérifier ou installer rsync

sudo apt install rsync # debian

Utilisateur et dossier backupuser

Ajout utilisateur de backupuser dans le groupe users ,qui ne peut exécuter que rsync ,et copier la clé publique du “serveur source”

sudo useradd -g users --system --shell /bin/bash --home-dir /home/backupuser --create-home backupuser  

Se connecter en backupuser et accéder au dossier

sudo su backupuser
cd /home/backupuser

Création dossier .ssh

mkdir .ssh

Ajout clé publique ssh du “serveur source”

dans le fichier authorized_keys du nouvel utilisateur

nano .ssh/authorized_keys

coller le contenu du “fichier local”

Script rsync-wrapper.sh

Création script bash rsync-wrapper.sh

nano rsync-wrapper.sh

Contenu du script

#!/bin/sh
 
date > /home/backupuser/backuplog
#echo $@ >> /home/backupuser/backuplog
/usr/bin/sudo /usr/bin/rsync "$@";

Droits en exécution

chmod +x rsync-wrapper.sh

fin session backupuser

exit                                                # fin session backupuser

Autoriser utilisateur à exécuter rsync uniquement

Autoriser backupuser à exécuter rsync en root sans mot de passe, ajouter au fichier sudoers

sudo -s
echo "backupuser ALL=NOPASSWD:/usr/bin/rsync" >> /etc/sudoers
exit

Serveur source

Utilisateur et dossier backupuser

Création utilisateur backupuser dans le groupe users et d’un jeu de clé ssh

sudo useradd -g users --system --shell /bin/bash --home-dir /home/backupuser --create-home backupuser  

Se connecter en backupuser et accéder au dossier

sudo su backupuser
cd /home/backupuser

Création dossier .ssh

mkdir .ssh

Création clé (ed25519 SHA512)

ssh-keygen -t ed25519 -f .ssh/backup_key_ed25519    # Accepter les valeurs par défaut

Sauvegarde complète (sauvegarde.sh)

Ce script permet la connexion sur un serveur distant via ssh et la sauvegarde complète via rsync

Fichiers à exclure de la sauvegarde : "dev/*","proc/*","sys/*","tmp/*","run/*","mnt/*","media/*","lost+found"

Script sauvegarde.sh exécuté sur le serveur source

nano sauvegarde.sh
#!/bin/bash

# -a Archive mode (keep file permissions etc...)
# hôtes distants
echo $(date) "Sauvegarde hôte distant yanfi.net"  >> /srv/sauvegarde/savdistant.log
/usr/bin/rsync -aev \
    --delete \
    --rsync-path=/home/backupuser/rsync-wrapper.sh \
    --exclude={"dev/*","proc/*","sys/*","tmp/*","run/*","mnt/*","media/*","lost+found"} \
    --rsh="/usr/bin/ssh -p 49022 -i /home/backupuser/.ssh/backup_key_ed25519" backupuser@yanfi.net:/ /srv/sauvegarde/yanfi &>> /srv/sauvegarde/savdistant.log
echo $(date) "Fin sauvegarde hôte distant yanfi.net"  >> /srv/sauvegarde/savdistant.log

#envoi des logs du jour par mail
# grep "$(date +"%d %B %Y")" /srv/sauvegarde/savdistant.log |mail -s "Sauvegarde du $(date +"%d %B %Y")" $desti

Les droits en exécution

chmod +x sauvegarde.sh

fin session backupuser

exit                                                # fin session backupuser

Création dossier de sauvegarde

En mode su

sudo mkdir -p /srv/sauvegarde

Donner les droits utilisateur backupuser au dossier de sauvegarde

sudo chown backupuser:users /srv/sauvegarde

Autoriser utilisateur à exécuter rsync uniquement

Autoriser backupuser à exécuter rsync en root sans mot de passe, ajouter au fichier sudoers

sudo -s
echo "backupuser ALL=NOPASSWD:/usr/bin/rsync" >> /etc/sudoers
exit

Copie clé publique sur serveur distant

Copie de la clé publique (.ssh/backup_key_ed25519.pub) dans le fichier .ssh/authorized_keys du serveur distant à sauvegarder :

sudo cat /home/backupuser/.ssh/backup_key_ed25519.pub | ssh backupuser@serveur-distant 'cat >> .ssh/authorized_keys'

ATTENTION !!! ceci n’est possible que si l’utilisateur backupuser existe sur le serveur distant

Dans le cas contraire, il faut copier la clé publique dans un fichier local (on suppose que l’on est connecté au “serveur source” pat ssh)

sudo cat /home/backupuser/.ssh/backup_key_ed25519.pub  # Sélectionner tout le fichier et faire un Shift+Ctrl+v pour le copier dans le presse papier

Ouvrir un “fichier local” , puis y copier le contenu du presse-papier

Rotation du fichier log (facultatif)

Rotation avec compression

sudo nano /etc/logrotate.d/sauvegarde

/srv/sauvegarde/savdistant.log {
        rotate 6
        monthly
        compress
        missingok
}
  • surveille le fichier savdistant.log et génère une rotation une fois par mois - c’est l’ “intervalle de rotation”.
  • ‘rotate 6’ signifie qu’à chaque intervalle, on conserve 6 semaines de journalisation.
  • Les fichiers de logs peuvent sont compressés au format gzip en spécifiant ‘compress’
  • ‘missingok’ permet au processus de ne pas s’arrêter à chaque erreur et de poursuivre avec le fichier de log suivant.

Ordonnancement (cron)

Sauvegarde une fois par jour à 3h15 du matin

sudo crontab -e

# tous les jours à 3h15
15 3 * * * /home/backupuser/sauvegarde.sh

Connexion ssh manuelle pour valider le distant

Le serveur source doit effectuer une connexion ssh manuelle pour valider le distant

sudo su backupuser
cd /home/backupuser
#ssh -i .ssh/backup_key_ed25519 backupuser@serveur-distant # si le port du distant est différent de celui par défaut ,il faut le déclarer par -p N°Port.

retour sur utilisateur précédent

exit                   # retour sur utilisateur précédent

Sauvegarde Locale Yunohost

Outil yunohost backup

La sauvegarde Yunohost sera générée dans le répertoire /home/yunohost.backup/archives (certaines applications ne sont pas sauvegardées). L’archive est au format AAAAMMJJ-HHMMSS.tar.gz ainsi que le fichier info associé AAAAMMJJ-HHMMSS.info.json
La sauvegarde est LOCALE , il faut copier le contenu sur une source externe (USB formatée en ext4 , via le réseau par rsync , etc…)
Donner les droits d’accès aux archives au groupe de l’utilisateur $USER :

sudo usermod -a -G users $USER
sudo chown -Rv root:users /home/yunohost.backup

Yunohost bash savyuno.sh

Se connecter en backupuser et accéder au dossier

sudo su backupuser
cd /home/backupuser

Créer un bash pour la sauvegarde yunohost

nano  savyuno.sh
#!/bin/bash

DOMAINE="domaine_tld"
SAVDIR="/srv/sauvegarde"
if [ -f "$SAVDIR/$DOMAINE.info.json" ];then
 rm $SAVDIR/{$DOMAINE.info.json,$DOMAINE.tar.gz}
fi
/usr/bin/yunohost backup create -n $DOMAINE 
mv /home/yunohost.backup/archives/{$DOMAINE.info.json,$DOMAINE.tar.gz} $SAVDIR/

Remplacer domaine_tld par votre nom de backup (!!! remplacer les “.” par des “_” dans les noms)

droits en exécution

chmod +x  savyuno.sh

retour sur utilisateur précédent

exit                   # retour sur utilisateur précédent

Vérifier si le répertoire de sauvegarde /srv/sauvegarde existe

sauvegarde des bases MariaDB/Mysql (backupmysql.sh)

Se connecter en backupuser et accéder au dossier

sudo su backupuser
cd /home/backupuser

Créer un bash pour la sauvegarde des bases

nano  backupmysql.sh
#!/bin/bash

# Configuration de base: datestamp e.g. YYYYMMDD
DATE=$(date +"%Y%m%d")

# Dossier où sauvegarder les backups (créez le d'abord!)
BACKUP_DIR="/srv/sauvegarde/mysql"

# Identifiants MySQL
MYSQL_USER="root"
MYSQL_PASSWORD=$(cat /etc/yunohost/mysql)
GZIP="$(which gzip)"

# Commandes MySQL (aucune raison de modifier ceci)
MYSQL="$(which mysql)"
MYSQLDUMP="$(which mysqldump)"

# Bases de données MySQL à ignorer
SKIPDATABASES="Database|information_schema|performance_schema|mysql"

# Nombre de jours à garder les dossiers (seront effacés après X jours)
RETENTION=7

# ---- NE RIEN MODIFIER SOUS CETTE LIGNE ------------------------------------------
#
# Create a new directory into backup directory location for this date
mkdir -p $BACKUP_DIR/$DATE

# Retrieve a list of all databases
databases=`$MYSQL -u$MYSQL_USER -p$MYSQL_PASSWORD -e "SHOW DATABASES;" | grep -Ev "($SKIPDATABASES)"`

# Dump the databases in seperate names and gzip the .sql file
for db in $databases; do
echo $db
$MYSQLDUMP --force --opt --user=$MYSQL_USER -p$MYSQL_PASSWORD --skip-lock-tables --events --databases $db | $GZIP > "$BACKUP_DIR/$DATE/$db.sql.gz"
done

# Remove files older than X days

find $BACKUP_DIR/* -mtime +$RETENTION -delete

droits en exécution

chmod +x  backupmysql.sh

retour sur utilisateur précédent

exit                   # retour sur utilisateur précédent

Créer le répertoire de sauvegarde des bases

sudo mkdir -p /srv/sauvegarde/mysql

Ordonnancement des tâches (cron)

Sauvegarde yunohost tous les jours à 2h15
Sauvegarde des bases mysql tous les jours à 2h30
Vérification validité des certificats SSL 1 fois par semaine à 2h30 et regénération auto si nécessaire (NE PAS AJOUTER si serveur Yunohost)

le fichier crontab

sudo -s
crontab -e
# m h  dom mon dow   command
30 1 * * * /home/backupuser/savyuno.sh
30 2 * * * /home/backupuser/backupmysql.sh
30 2 * * 1 /usr/local/sbin/le-renew-webroot >> /var/log/le-renewal.log

ATTENTION!!! La sauvegarde de yunohost (savyuno.sh) est très longue en temps

Sauvegarde locale via systemd timer

Le fonctionnement de systemd impose cependant d’avoir deux fichiers :
service, qui contient la définition du programme
timer, qui dit “quand” le lancer.

Ils doivent porter le même nom et se situer dans /etc/systemd/system/.

Création service et timer

Si vous gérez déjà vos services via systemd, vous avez déjà utilisé des “unit” systemd de type “service”.
Ces “unit” permettent de définir un process et son mode d’éxécution.
Pour implémenter un “timer” sous systemd, il va nous falloir un fichier “service”.

Pour notre tâche à planifier, nous allons avoir au final 3 fichiers :

Le script à exécuter
Le fichier “service” qui va dire quel script exécuter
Le fichier “timer” qui va indiquer quand il doit être exécuté.

A noter que par convention, les fichiers service et timer doivent avoir le même nom

Nous devons exécuter ,une fois par jour , un script de sauvegarde /home/yannick/scripts/savarch sur un ordinateur qui n’est pas sous tension 24/24h.

Pour le fichier service /etc/systemd/system/savarch.service, une base simple

[Unit]
Description=Sauvegarde jour

[Service]
Type=simple
ExecStart=/bin/bash /home/yannick/scripts/savarch
StandardError=journal
Type=oneshot

Je fournis une description à mon service, indique que c’est un process de type simple, le chemin vers mon script et je rajoute que le flux d’erreur est envoyé dans le journal.Il ne faut pas de section [Install] car le script va être piloté par le fichier timer.
La ligne Type=oneshot est importante, c’est elle qui dit à systemd de ne pas relancer le service en boucle.

Le fichier “timer” /etc/systemd/system/savarch.timer

[Unit]
Description=Sauvegarde jour

[Timer]
# lisez le man systemd.timer(5) pour tout ce qui est disponible
OnCalendar=daily
# Autoriser la persistence entre les reboot
Persistent=true
Unit=savarch.service

[Install]
WantedBy=timers.target
  • OnCalendar permet d’indiquer l’occurrence et la fréquence d’exécution du script. Il y a les abréviations classiques (“minutely”, “hourly”, “daily”, “monthly”, “weekly”, “yearly”, “quarterly”, “semiannually”, etc) mais vous pouvez avoir des choses plus complexes comme “Mon,Tue --01..04 12:00:00” - voir systemd.time
  • Persistent va forcer l’exécution du script si la dernière exécution a été manquée suite à un reboot de serveur ou autre événement.
  • Install va créer la dépendance pour que votre “timer” soit bien exécuté et pris en compte par systemd.

Activation et démarrage du timer

Il est possible de tester le service avec un simple systemctl start savarch.service, de regarder les logs avec journalctl -u savarch.service.

Ensuite, pour qu’il soit actif, il faut prévenir systemd

sudo systemctl enable savarch.timer
sudo systemctl start savarch.timer

Gestion et suivi d’un timer

Pour voir la liste des “timers” actifs et la date de leur dernière et prochaine exécution

systemctl list-timers
NEXT                         LEFT     LAST                         PASSED    UNIT                         ACTIVATES
Fri 2018-03-02 00:00:00 CET  15h left Thu 2018-03-01 07:49:43 CET  56min ago logrotate.timer              logrotate.service
Fri 2018-03-02 00:00:00 CET  15h left Thu 2018-03-01 07:49:43 CET  56min ago man-db.timer                 man-db.service
Fri 2018-03-02 00:00:00 CET  15h left Thu 2018-03-01 07:49:43 CET  56min ago savarch.timer                savarch.service
Fri 2018-03-02 00:00:00 CET  15h left Thu 2018-03-01 07:49:43 CET  56min ago shadow.timer                 shadow.service
Fri 2018-03-02 00:00:00 CET  15h left Thu 2018-03-01 07:49:43 CET  56min ago updatedb.timer               updatedb.service
Fri 2018-03-02 08:04:45 CET  23h left Thu 2018-03-01 08:04:45 CET  41min ago systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.service

et accéder aux logs de vos “timers” :

journalctl -u savarch.service
...
mars 01 08:43:47 yannick-pc bash[1932]: 2018-03-01 08:43:15 Départ sauvegarde
mars 01 08:43:47 yannick-pc bash[1932]: 2018-03-01 08:43:15 synchronisation source partagée /home/yannick/media/Musique cible locale /home/yannick/media/savlocal/Musique
mars 01 08:43:47 yannick-pc bash[1932]: 2018-03-01 08:43:21 synchronisation partagée /home/yannick/media/devel cible locale /home/yannick/media/savlocal/devel
mars 01 08:43:47 yannick-pc bash[1932]: 2018-03-01 08:43:33 synchronisation partagée /home/yannick/media/BiblioCalibre cible locale /home/yannick/media/savlocal/BiblioCalibre
mars 01 08:43:47 yannick-pc bash[1932]: 2018-03-01 08:43:41 SAUVEGARDE /home/yannick -> /home/yannick/media/savlocal/yannick-pc/yannick
mars 01 08:43:47 yannick-pc bash[1932]: 2018-03-01 08:43:42 SAUVEGARDE /home/yannick/media/dplus -> /home/yannick/media/savlocal/dplus
mars 01 08:43:47 yannick-pc bash[1932]: 2018-03-01 08:43:47 SAUVEGARDE /home/yannick/media/yanspm-md -> /home/yannick/media/savlocal/yanspm-md
mars 01 08:43:47 yannick-pc bash[1932]: 2018-03-01 08:43:47 FIN sauvegarde
mars 01 08:43:47 yannick-pc systemd[1]: Started Sauvegarde jour.

En cas de modification du .timer ou du .service, ne pas oublier de faire un systemctl daemon-reload pour que la version actualisée de vos fichiers soit prise en compte par systemd.