Sauvegarde quotidienne du serveur principal vers le Raspberry Pi avec Plakar : dépôt chiffré et dédupliqué, transport SFTP.
Fonctionnement
| Élément | Valeur |
|---|---|
| Machine sauvegardée | Serveur principal |
| Dépôt | SSD USB du Raspberry Pi |
| Transport | SFTP |
| Déclenchement | Cron, chaque nuit à 3 h 30 |
| Rétention | 30 jours glissants |
| Script | /root/backup-plakar.sh |
| Journal | /var/log/backup-plakar.log, avec rotation par logrotate |
Chaque exécution :
- exporte toutes les bases en SQL dans <APPDATA>/dumps ;
- sauvegarde les données des conteneurs, la bibliothèque Immich et le contenu de Joplin, en excluant les fichiers bruts des bases ;
- supprime les instantanés de plus de 30 jours.
Mise en place du dépôt
Sur le Raspberry Pi (dépôt)
Utilisateur dédié, sans shell :
sudo mkdir -p <CHEMIN_DEPOT>
sudo chown plakar:plakar <CHEMIN_DEPOT>
sudo install -d -m 700 -o plakar -g plakar /srv/plakar/.ssh
Limitation au SFTP, dans /etc/ssh/sshd_config.d/plakar.conf :
ForceCommand internal-sftp
AllowTcpForwarding no
X11Forwarding no
Même en cas de vol de la clé, elle ne donne ni shell ni tunnel : seulement un accès SFTP.
Sur le serveur principal (source)
Clé SSH dédiée, sans phrase de passe puisqu'elle sert à la tâche cron :
Contenu de /root/.ssh/plakar_matrix.pub à copier dans /srv/plakar/.ssh/authorized_keys sur le Pi (propriétaire plakar, droits 600).
/root/.ssh/config :
Host <HOTE_DEPOT>
User plakar
IdentityFile /root/.ssh/plakar_matrix
La ligne Ciphers limite, pour toutes les connexions SSH de root, les algorithmes de chiffrement à des variantes modernes.
Première connexion, pour valider l'empreinte du Pi (sinon la tâche cron échouera) :
Phrase secrète du dépôt et création :
sudo plakar -keyfile /root/.plakar-pass at "sftp://plakar@<HOTE_DEPOT>:<CHEMIN_DEPOT>" create
Restaurer si le serveur principal est perdu
Le dépôt peut s'ouvrir directement sur le Raspberry Pi, où Plakar est aussi installé, avec la phrase secrète récupérée dans le gestionnaire de mots de passe :
sudo plakar at <CHEMIN_DEPOT> restore -to /tmp/restore <ID_INSTANTANE>
Plakar demande alors la phrase secrète de façon interactive.
Script
#!/bin/bash
set -euo pipefail
umask 077
# Alertes Telegram
. /root/.backup-telegram
notifier() {
curl -fsS -m 10 "https://api.telegram.org/bot$TG_TOKEN/sendMessage" \
-d chat_id="$TG_CHAT" --data-urlencode text="$1" >/dev/null || true
}
attention() { echo "ATTENTION: $1" >&2; notifier "⚠️ Sauvegarde : $1"; }
trap 'notifier "❌ Sauvegarde interrompue à la ligne $LINENO"' ERR
REPO="sftp://<UTILISATEUR>@<HOTE_DEPOT>:<CHEMIN_DEPOT>"
KEYFILE="<FICHIER_PHRASE_SECRETE>"
DUMPS="<APPDATA>/dumps"
mkdir -p "$DUMPS"
# Dumps MariaDB/MySQL
for c in xwiki-mariadb-db passbolt-db castopod-test-db; do
docker exec "$c" sh -c 'exec mysqldump -uroot -p"${MYSQL_ROOT_PASSWORD:-$MARIADB_ROOT_PASSWORD}" --all-databases' \
> "$DUMPS/$c.sql" 2>/dev/null \
|| docker exec "$c" sh -c 'exec mariadb-dump -uroot -p"${MYSQL_ROOT_PASSWORD:-$MARIADB_ROOT_PASSWORD}" --all-databases' \
> "$DUMPS/$c.sql" 2>/dev/null \
|| attention "dump $c échoué"
done
# Nextcloud : dump via l'utilisateur applicatif
docker exec "$(docker ps -q -f name=nextcloud_db)" sh -c 'exec mariadb-dump -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DATABASE"' \
> "$DUMPS/nextcloud.sql" 2>/dev/null \
|| attention "dump nextcloud échoué"
# Dumps PostgreSQL
for c in joplin-db flus-db wallabag-db immich_postgres vikunja-db jellystat-db n8n-postgres dawarich_db; do
docker exec "$c" sh -c 'exec pg_dumpall -U "$POSTGRES_USER"' \
> "$DUMPS/$c.sql" 2>/dev/null \
|| attention "dump $c échoué"
done
# Sauvegarde, sans core dumps, binlogs ni fichiers bruts des bases
plakar --concurrency 2 -keyfile "$KEYFILE" at "$REPO" backup \
-ignore "**/joplin-app/core.*" \
-ignore "**/Nextcloud/DB/**" \
-ignore "**/log/mysql/**" \
-ignore "**/xwiki/mariadb/**" \
-ignore "**/store.bak.*/**" \
<APPDATA> \
<BIBLIOTHEQUE_IMMICH> \
<CONTENU_JOPLIN>
# Rétention : 30 jours glissants
plakar -keyfile "$KEYFILE" at "$REPO" rm -before 30d -apply
notifier "✅ Sauvegarde terminée"
{{/code}}
Tâche cron, /etc/cron.d/backup-plakar :
Ajouter une base
Ajouter le nom du conteneur dans la boucle MariaDB ou PostgreSQL du script, puis exclure ses fichiers bruts avec un -ignore s'ils se trouvent dans <APPDATA>.
Vérifier
grep ATTENTION /var/log/backup-plakar.log
sudo plakar -keyfile <FICHIER_PHRASE_SECRETE> at <REPO> ls
Restaurer
Restaurer un instantané complet dans un dossier temporaire :
Réinjecter une base MariaDB :
Réinjecter une base PostgreSQL (dump complet de l'instance) :
Incidents connus
| Symptôme | Cause | Solution |
|---|---|---|
| Verrou restant après une exécution interrompue | Le processus a été coupé en cours | Supprimer le verrou orphelin avant de relancer |
| Avertissements VFS | Cache local incohérent | Vider ~/.cache/plakar de root |
| Transfert coupé (EOF SFTP) sur de gros fichiers | Lien Wi-Fi du dépôt instable | Économie d'énergie Wi-Fi désactivée sur le Pi ; passer à --concurrency 1 pour une première sauvegarde volumineuse |
| Déconnexion du SSD pendant la sauvegarde | Pont USB en mode UAS | Voir la configuration SSD sur la page Raspberry Pi |