💾 Sauvegarde/Restauration dossier (rsync snapshots + lien current)
Sauvegarde/Restauration dossier
Sauvegarde dossier
- Il vérifie l’espace libre sur
/mnt/FreeUSB2To/sauvegardes. - Si le seuil est franchi, il envoie une notification ntfy avec priorité haute et s’arrête.
- Vous recevez donc l’alerte avant que la sauvegarde ne tente d’écrire sur un disque trop plein.
Seuil actuel
Dans le script, la protection est réglée sur :
MIN_FREE_GB=20MIN_FREE_PCT=5
Donc l’alerte part si l’espace libre passe sous 20 Go ou sous 5%.
Notification envoyée
Le message d’alerte utilise ntfy avec :
TitlePriority: highTags: warning,disk- le jeton dans
/etc/backup-sharenfs.env.
Alerte plus tôt
Vous pouvez rendre le seuil plus prudent, par exemple :
MIN_FREE_GB=50- ou
MIN_FREE_PCT=10
C’est souvent préférable sur un disque de sauvegarde, surtout si plusieurs snapshots s’accumulent.
Vérification
Pour tester manuellement la logique d’alerte, lancez :
1
sudo /usr/local/sbin/backup-sharenfs.sh
Si l’espace est trop bas, vous recevrez une notification ntfy immédiatement.
Fichier d’environnement ntfy
/etc/backup-sharenfs.env
1
2
NTFY_URL=https://ntfy.rnmkcy.eu/yan_infos
NTFY_TOKEN=tk_9h2bfxjs0pkbuwsnavc6w0wua5t5x
Protection :
1
2
sudo chown root:root /etc/backup-sharenfs.env
sudo chmod 600 /etc/backup-sharenfs.env
Script complet
- exécution toutes les 30 minutes,
- lancement manuel,
- verrou anti double lancement,
- vérification de montage,
- vérification d’espace disque,
- logs,
- rotation de 30 jours,
- préservation des ACL/xattrs/liens,
- option d’exclusions.
VERBOSE=1activable en manuel,- jeton ntfy dans
/etc/backup-sharenfs.env, currentgéré comme lien symbolique,- suppression correcte de
current, - progression
rsyncvisible en manuel, - mode silencieux pour le timer.
Cette structure suit le schéma classique “snapshots + lien current” utilisé avec
rsync.
/usr/local/sbin/backup-sharenfs.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#!/bin/bash
set -euo pipefail
SRC="/sharenfs/"
BASE="/mnt/backup/sharenfs"
CUR="$BASE/current"
SNAPDIR="$BASE/snapshots"
LOGDIR="$BASE/logs"
EXCLUDE_FILE="/etc/backup-sharenfs.exclude"
ENV_FILE="/etc/backup-sharenfs.env"
LOCK="$BASE/.lock"
DATE="$(date +%F_%H-%M)"
NEW="$SNAPDIR/$DATE"
LOGFILE="$LOGDIR/backup-$DATE.log"
MIN_FREE_GB=20
MIN_FREE_PCT=5
RETENTION_DAYS=30
VERBOSE="${VERBOSE:-0}"
[ -f "$ENV_FILE" ] && . "$ENV_FILE"
notify() {
local title="$1"
local prio="$2"
local tags="$3"
local msg="$4"
[ -n "${NTFY_URL:-}" ] && [ -n "${NTFY_TOKEN:-}" ] || return 0
curl -fsS \
-H "Title: $title" \
-H "Authorization: Bearer $NTFY_TOKEN" \
-H "Priority: $prio" \
-H "Tags: $tags" \
--data-binary "$msg" \
"$NTFY_URL" >/dev/null
}
if ! mountpoint -q /mnt/FreeUSB2To; then
echo "Destination non montée: /mnt/FreeUSB2To"
notify "Backup sharenfs" "high" "warning,usb" "Échec: /mnt/FreeUSB2To n'est pas monté."
exit 1
fi
mkdir -p "$SNAPDIR" "$LOGDIR"
avail_kb="$(df -Pk "$BASE" | awk 'NR==2 {print $4}')"
size_kb="$(df -Pk "$BASE" | awk 'NR==2 {print $2}')"
free_gb=$((avail_kb / 1024 / 1024))
free_pct=$((avail_kb * 100 / size_kb))
if [ "$free_gb" -lt "$MIN_FREE_GB" ] || [ "$free_pct" -lt "$MIN_FREE_PCT" ]; then
msg="Échec: espace disque insuffisant sur $BASE (${free_gb}G libres, ${free_pct}%)."
echo "$msg"
notify "Backup sharenfs" "high" "warning,disk" "$msg"
exit 1
fi
exec 9>"$LOCK"
flock -n 9 || exit 0
RSYNC_OPTS=(
-aHAX
--numeric-ids
--delete
--delete-delay
--partial
--partial-dir=.rsync-partial
--human-readable
--info=progress2
--info=stats2
)
if [ -f "$EXCLUDE_FILE" ]; then
RSYNC_OPTS+=(--exclude-from="$EXCLUDE_FILE")
fi
run_backup() {
echo "=== Backup start: $(date -Is) ==="
if [ -e "$CUR" ]; then
if [ -L "$CUR" ] || [ -f "$CUR" ]; then
rm -f "$CUR"
elif [ -d "$CUR" ]; then
rm -rf "$CUR"
fi
fi
if [ -d "$CUR" ] && [ "$(find "$CUR" -mindepth 1 -maxdepth 1 | wc -l)" -gt 0 ]; then
mkdir -p "$NEW"
rsync "${RSYNC_OPTS[@]}" --link-dest="$CUR" "$SRC" "$NEW/"
else
mkdir -p "$NEW"
rsync "${RSYNC_OPTS[@]}" "$SRC" "$NEW/"
fi
rm -f "$CUR"
ln -s "$NEW" "$CUR"
find "$SNAPDIR" -mindepth 1 -maxdepth 1 -type d -mtime +"$RETENTION_DAYS" -exec rm -rf {} +
echo "=== Backup end: $(date -Is) ==="
}
if [ "$VERBOSE" = "1" ]; then
run_backup 2>&1 | tee "$LOGFILE"
else
run_backup >>"$LOGFILE" 2>&1
fi
notify "Backup sharenfs" "low" "information_source,backup" "Succès: sauvegarde terminée à $(date -Is). Snapshot: $DATE."
Puis :
1
2
sudo chmod 750 /usr/local/sbin/backup-sharenfs.sh
sudo chown root:root /usr/local/sbin/backup-sharenfs.sh
Service systemd
/etc/systemd/system/backup-sharenfs.service
1
2
3
4
5
6
7
8
[Unit]
Description=Backup /sharenfs to local USB snapshots
RequiresMountsFor=/mnt/backup/sharenfs
[Service]
Type=oneshot
EnvironmentFile=/etc/backup-sharenfs.env
ExecStart=/usr/local/sbin/backup-sharenfs.sh
Timer 30 minutes
/etc/systemd/system/backup-sharenfs.timer
1
2
3
4
5
6
7
8
9
10
11
[Unit]
Description=Run /sharenfs backup every 30 minutes
[Timer]
OnBootSec=5min
OnUnitActiveSec=30min
Persistent=true
Unit=backup-sharenfs.service
[Install]
WantedBy=timers.target
Activation :
1
2
sudo systemctl daemon-reload
sudo systemctl enable --now backup-sharenfs.timer
Usage
Manuel, avec affichage de progression :
1
sudo VERBOSE=1 /usr/local/sbin/backup-sharenfs.sh
Manuel, silencieux :
1
sudo /usr/local/sbin/backup-sharenfs.sh
Vérifier le lien current :
1
ls -l /mnt/backup/sharenfs/current
Vous devez voir un lien du type :
1
current -> /mnt/backup/sharenfs/snapshots/2026-06-27_11-29
Test ntfy séparé
1
2
3
4
5
6
7
8
source /etc/backup-sharenfs.env
curl \
-H "Title: Information!" \
-H "Authorization: Bearer $NTFY_TOKEN" \
-H "Priority: low" \
-H "Tags: information_source" \
-d "Notification utilisant un jeton d'accès" \
"$NTFY_URL"
Restauration dossier
- Vérifiez le snapshot à restaurer.
- Arrêtez tout service qui écrit dans
/sharenfssi nécessaire. - Copiez le snapshot vers la destination avec
rsync. - Contrôlez les droits, ACL et fichiers cachés.
- Relancez les services concernés.
Vérifier le snapshot disponible
1
2
ls -l /mnt/FreeUSB2To/sauvegardes/current
ls /mnt/FreeUSB2To/sauvegardes/snapshots
Arrêter les écritures si nécessaire
Si /sharenfs est utilisé par un service, arrêtez-le avant restauration.
Restaurer le dernier état
1
sudo rsync -aHAX /mnt/FreeUSB2To/sauvegardes/current/ /sharenfs/
Restaurer un snapshot précis
Remplacez la date par le snapshot voulu :
1
sudo rsync -aHAX /mnt/FreeUSB2To/sauvegardes/snapshots/2026-06-27_11-29/ /sharenfs/
Restaurer un sous-dossier
1
sudo rsync -aHAX /mnt/FreeUSB2To/sauvegardes/current/mon_dossier/ /sharenfs/mon_dossier/
Restaurer un seul fichier
1
sudo cp -a /mnt/FreeUSB2To/sauvegardes/current/chemin/du/fichier /sharenfs/chemin/du/fichier
Contrôler le résultat
1
2
find /sharenfs | head
df -h /mnt/FreeUSB2To
Relancer les services
Redémarrez ensuite les services qui utilisent /sharenfs.
Test avant remise en production
Pour éviter toute erreur, restaurez d’abord dans un dossier temporaire :
1
2
3
sudo mkdir -p /tmp/restore-test
sudo rsync -aHAX /mnt/FreeUSB2To/sauvegardes/current/ /tmp/restore-test/
ls -l /tmp/restore-test
Point important
current doit être un lien symbolique vers le dernier snapshot, pas un dossier réel. Si besoin, vérifiez avec :
1
ls -l /mnt/FreeUSB2To/sauvegardes/current
Mémo urgence
Voici le mémo d’urgence en 5 lignes :
1
2
3
4
5
sudo systemctl stop service-utilisant-sharenfs
sudo rsync -aHAX /mnt/FreeUSB2To/sauvegardes/current/ /sharenfs/
ls -l /mnt/FreeUSB2To/sauvegardes/current
find /sharenfs | head
sudo systemctl start service-utilisant-sharenfs
Pour un snapshot précis, remplacez current/ par snapshots/AAAA-MM-JJ_HH-MM/.
