J’ai mis en place une sauvegarde de quelques fichiers de ma machine vers un compte S3 suite à une petite frayeur.
Pour cela j’ai utilisé restic et un cron pour automatiser la sauvegarde (sinon ce n’est pas vraiment une sauvegarde). Ce n’est sans doute pas la meilleure solution ni la plus complète mais pour aller vite c’est un bon début.
Syncthing n’est pas une sauvegarde
J’utilise org-mode pour prendre des notes et je synchronise le répertoire ~/org
sur d’autres machines avec syncthing.
Jusqu’ici tout fonctionnait et je me disais que je n’avais pas besoin de sauvegardes car le contenu est répliqué sur plusieurs machines.
Mais aujourd’hui en voulant enregistrer une note pour la journée emacs m’a avertit que le répertoire ~/org/daily/
n’existait pas.
Curieux car depuis plusieurs semaines c’est dans ce répertoire que j’enregistre mes notes quotidiennes de travail.
Et effectivement emacs a raison !!
Je ne sais pas ce qu’il s’est passé, c’est comme si le répertoire était revenu à un état antérieur de plusieurs mois. J’ai pu récupérer les données sur une autre machine et j’ai repris proprement la configuration de syncthing dans ma configuration nixos car j’avais quelques modifications à la main. J’en ai profité pour activer le versionning des fichiers sur le serveur qui reçoit les fichiers. C’est une première mesure. Mais on va mettre en place une vraie sauvegarde.
Restic
J’ai choisi restic car j’avais ce nom en tête, sans chercher d’autres solutions. C’est packagé dans nix et on peut envoyer les sauvegardes sur un bucket S3. Et pour que ce soit une vraie sauvegarde je voulais que ce soit automatique. Syncthing recopie sur plusieurs machines, mais il recopie aussi les erreurs. Peut-être que le versionning de syncthing est suffisant mais je voulais bien une sauvegarde régulière externalisée.
J’ai mis en place la configuration sur mon poste client plutôt que sur le serveur car je voudrais aussi sauvegarder d’autres répertoires qui ne sont pas sur le serveur.
Il semble qu’un simple cron ne soit plus suffisant à l’heure de systemd alors je me suis tourné vers un service et timer. Je ne suis même pas sûr d’avoir les bons termes :-) Le timer va définir la périodicité de l’appel au service. Et le service va définir la commande à appeler.
Bucket S3
La sauvegarde sera envoyée sur un bucket S3 chez Scaleway. Je ne vais pas détailler comment créer le bucket et lui donner les droits nécessaires et suffisants, la documentation de Scaleway explique tout cela. Il faut donc créer ce bucket et mettre à disposition la clef et le secret nécessaires pour se connecter.
Pour l’instannt j’ai placé ces informations dans un fichier dans mon home directory et restreignant les droits d’accès. Ce n’est pas idéal, je suis d’accord, mais je voulais tout mettre en place rapidement.
cat <<EOF >> .restic-backup
export AWS_ACCESS_KEY_ID=SCW.....
export AWS_SECRET_ACCESS_KEY=38....
EOF
chmod 600 .restic-backup
Il suffira de sourcer ce fichier pour pouvoir accéder au bucket.
Configuration de restic
Les sauvegardes de restic sont chiffrées et nécessitent la saisie d’un mot de passe.
Au point où on en est on va ajouter ce mot de passe dans notre fichier .restic-backup
.
cat <<EOF >>.restic-backup
export RESTIC_PASSWORD="SUPERMOTDEPASSE"
EOF
Maintenant il faut initialiser le bucket et ensuite on peut faire une première sauvegarde.
source ~/.restic-backup
restic -r s3:https://s3.fr-par.scw.cloud/mon_bucket_a_moi init
restic -r s3:https://s3.fr-par.scw.cloud/mon_bucket_a_moi backup ~/org
Tout doit bien se passer mais on peut vérifier la sauvegarde avec la commande :
restic -r s3:https://s3.fr-par.scw.cloud/mon_bucket_a_moi snapshots
Un snapshot doit être listé.
On peut maintenant automatiser la sauvegarde.
Configuration du cron
Je vais utiliser une unit systemd au niveau de mon utilisateur, pas au niveau du système. Et je veux du coup que la configuration soit dans home-manager dans la partie de mon utilisateur pour ma machine.
Ce sera dans un fichier backup-restic.nix
qui sera importé dans la configuration de ma machine.
Voici le fichier
{ config, pkgs, ... }:
{
home.packages = [ pkgs.restic ];
systemd.user.timers.restic-org = {
Unit.Description = "Timer pour la sauvegarde de ~/org";
Timer = {
OnBootSec = "5m";
OnUnitActiveSec = "1h";
Unit = "restic-org.service";
};
};
systemd.user.services.restic-org = {
Unit = {
Description = "Sauvegarde du répertoire ~/org";
};
Install = {
WantedBy = [ "default.target" ];
};
Service = {
Type = "oneshot";
ExecStart = "${pkgs.writeShellScript "restic-org" ''
set -eu
source /home/montfort/.restic-backup
${pkgs.restic}/bin/restic -r s3:https://s3.fr-par.scw.cloud/restic-org backup ~/org
''}";
};
};
}
On installe le paquet restic
qui va nous servir.
Ensuite la définition du timer au niveau de l’utilisateur.
Les différentes options du Timer
sont celles de l’unit Timer de systemd (cf manpage).
Dans notre cas le timer se déclenche 5m
après le démarrage de la machine et après 1h
quand l’unit est active (il y a le même paramètre dans le cas où l’unit n’est pas active, je ne vois pas trop le cas d’usage).
Et en dernier l’unit à appeler.
La partie systemd.user.services
décrit la commande appelée et donc la commande qui va faire notre sauvegarde.
Rien de particulier si ce n’est la ligne ExecStart
qui nécessite un script.
On peut appeler pkgs.writeShellScript
avec le nom d’un script et le contenu.
Notre script sera créé et le chemin automatiquement passé à ExecStart
.
Le script est aussi simple que vu avant.
On préciser le chemi d’accès au binaire restic par rapport au paquet restic installé.
Il ne reste plus qu’à lancer la commande home-manager
et tout sera en place.
home-manager switch --flake .#montfort@belenos
systemctl --user status restic-org.timer
Reste à faire
Il reste à mieux gérer les mots de passe. Peut-être regarder du côté de nix-sops ou une autre solution.
Il faudra aussi prévoir le nettoyage des snapshots si on ne veut pas exploser le stockage. J’ai identifié une commande dans ce style dans la documentation :
restic -r s3:https://s3.fr-par.scw.cloud/restic-org forget --keep-within-daily 7d --keep-within-weekly 1m --keep-within-monthly 1y --keep-within-yearly 2y --dry-run
A ajouter dans un autre service et timer !