Un VPS se perd rarement d'un coup. Le plus souvent, c'est un rm -rf lancé
dans le mauvais dossier, une mise à jour qui casse une application, ou une base vidée par
un script mal écrit. Pour ces cas, il faut deux choses : un point de restauration récent,
et une copie qui ne dépend pas de la machine ni de son hébergeur.
Cet article décrit ce que FFxF sauvegarde pour vous, comment restaurer, et comment monter vous-même une copie hors site avec restic. La partie restic a été testée de bout en bout sur deux VM Nano à l'heure sous Debian 13 : sauvegarde de 1 Gio, suppression d'un dossier, restauration, puis vérification de chaque fichier. Les durées et les sorties sont les vraies.
1. Ce que FFxF sauvegarde pour vous
Chaque VM a droit à deux types de sauvegardes. Les deux copient le disque entier de la machine vers un serveur de sauvegarde distinct de l'hyperviseur (Proxmox Backup Server).
| Sauvegardes manuelles | Sauvegardes automatiques | |
|---|---|---|
| Prix | incluses | 3 CAD par mois et par VM |
| Déclenchement | vous, depuis la console | chaque nuit |
| Nombre gardé | jusqu'à 7 | les 7 dernières nuits |
| Suppression | par vous, pour libérer une place | rotation automatique, vous ne pouvez pas les effacer |
| Machine arrêtée ? | non, la copie se fait à chaud | |
Dans la console, ouvrez la machine, puis Sauvegardes et
Créer une sauvegarde. Donnez-lui un nom qui dit pourquoi elle existe
(avant-maj-php, par exemple). Seuls les blocs qui ont changé depuis la
sauvegarde précédente sont stockés : la deuxième et les suivantes vont plus vite que la
première. Les sauvegardes automatiques ne comptent pas dans vos 7 places.
Créer une sauvegarde ne se fait que dans la console. L'API
sait les lister, les restaurer et supprimer celles que vous avez prises, avec la portée
backups.write pour les deux dernières.
2. Avant la première : installez l'agent QEMU
Une sauvegarde à chaud copie un disque en cours d'écriture. Avec l'agent QEMU dans la VM, l'hyperviseur gèle les systèmes de fichiers quelques instants au départ de la copie : ce qui est écrit sur le disque est alors cohérent. Sans l'agent, vous obtenez l'équivalent d'une coupure de courant, que ext4 sait rattraper, mais pas toujours une base de données.
Sur notre machine de test Debian 13, le canal de l'agent était bien présent, mais le paquet n'était pas installé. Notre image Debian 13 l'installe désormais (corrigé après ce test) ; sur une machine plus ancienne ou un autre système, vérifiez :
$ dpkg -l qemu-guest-agent
dpkg-query: no packages found matching qemu-guest-agent
$ ls /dev/virtio-ports/
org.qemu.guest_agent.0
$ sudo apt-get install -y qemu-guest-agent
$ systemctl is-active qemu-guest-agent
active
Pour une base de données, n'en restez pas là : un pg_dump ou un
mysqldump planifié avant la sauvegarde vous donne un fichier que vous pouvez
recharger ailleurs, sans restaurer toute la machine.
3. Restaurer : tout le disque, d'un bloc
Depuis la page Sauvegardes, Restaurer demande de cocher une confirmation explicite : la restauration remplace tout le disque actuel. La machine est arrêtée pendant l'opération, puis repart dans l'état de la sauvegarde. Par l'API, la liste d'une machine sans sauvegarde ressemble à ceci :
$ curl -s -H "Authorization: Bearer $FFXF_TOKEN" \
https://api.ffxf.net/v1/vms/315/backups
{"data":[],"meta":{"automatic_enabled":false,"retention":7}}
Chaque entrée de data porte un id, un type
(manual ou automatic), une date et une taille. La restauration
reprend cet id tel quel et répond avec une action à suivre :
$ curl -s -X POST -H "Authorization: Bearer $FFXF_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
"https://api.ffxf.net/v1/vms/315/backups/<id>/restore"
Le piège est là : on ne récupère pas un dossier seul. Si vous avez supprimé
/srv/app/uploads à 15 h et que la sauvegarde date de la nuit, restaurer la
machine efface aussi tout ce qui a été écrit ailleurs depuis. Pour reprendre un fichier
sans tout remettre en arrière, il vous faut une copie au niveau des fichiers, ce que fait
la section suivante.
4. La copie hors site avec restic
restic chiffre, déduplique et envoie vos fichiers vers un dépôt : un serveur SFTP, un stockage compatible S3, un disque. Pour le test, le dépôt est une deuxième VM Nano qui n'accepte qu'une chose : du SFTP, enfermé dans un dossier.
Sur la machine qui reçoit les copies :
sudo useradd --create-home --shell /usr/sbin/nologin sauvegarde
sudo install -d -m 755 -o root -g root /srv/sftp
sudo install -d -m 700 -o sauvegarde -g sauvegarde /srv/sftp/restic
sudo install -d -m 700 -o sauvegarde -g sauvegarde /home/sauvegarde/.ssh
sudo install -m 600 -o sauvegarde -g sauvegarde restic.pub /home/sauvegarde/.ssh/authorized_keys
sudo tee /etc/ssh/sshd_config.d/sauvegarde.conf <<'EOF'
Match User sauvegarde
ForceCommand internal-sftp
ChrootDirectory /srv/sftp
AllowTcpForwarding no
X11Forwarding no
EOF
sudo sshd -t && sudo systemctl reload ssh
restic.pub est la clé publique créée sur la machine à sauvegarder, avec
sudo ssh-keygen -t ed25519 -N "" -f /root/.ssh/restic. Toujours sur cette
machine, en root, un alias SSH vers le dépôt, puis le mot de passe du dépôt et
l'initialisation :
# /root/.ssh/config
Host depot
HostName 2001:db8:100::5c
User sauvegarde
IdentityFile /root/.ssh/restic
# en root
apt-get install -y restic
openssl rand -base64 32 > /root/.restic-pass && chmod 600 /root/.restic-pass
export RESTIC_REPOSITORY=sftp:depot:/restic
export RESTIC_PASSWORD_FILE=/root/.restic-pass
restic init
Le chroot fait que le dépôt s'appelle /restic vu du client. Première
sauvegarde : 2 002 fichiers témoins (2 000 petits fichiers, un fichier aléatoire de
1 Gio, un fichier de configuration), plus /etc :
$ time restic backup /srv/app /etc
no parent snapshot found, will read all files
Files: 2565 new, 0 changed, 0 unmodified
Dirs: 161 new, 0 changed, 0 unmodified
Added to the repository: 1.003 GiB (1.001 GiB stored)
processed 2565 files, 1.002 GiB in 0:26
snapshot 6a6ad570 saved
real 0m26.571s
26,6 secondes, dont 19 de calcul : sur un seul vCPU, c'est le chiffrement qui limite, pas le réseau. Le fichier aléatoire ne se compresse pas, d'où 1,001 Gio stockés. Après l'ajout de trois fichiers, la sauvegarde suivante ne lit que ce qui a changé :
Files: 3 new, 0 changed, 2565 unmodified
Added to the repository: 732.947 KiB (136.792 KiB stored)
processed 2568 files, 1.002 GiB in 0:00
real 0m1.005s
5. On casse, on restaure, on vérifie
Avant de casser quoi que ce soit, l'empreinte de chaque fichier témoin a été notée avec
sha256sum dans /root/temoin.sha256. Ensuite, la suppression :
$ sudo rm -rf /srv/app/uploads
$ ls /srv/app
config
$ time restic restore latest --target / --include /srv/app/uploads
restoring snapshot 2f2d626d of [/srv/app /etc] at 2026-11-03 16:10:10.034756322 +0000 UTC by root@blog-04-sauvegardes-src to /
Summary: Restored 2007 / 2005 files/dirs (1.000 GiB / 1.000 GiB) in 0:09
real 0m10.775s
$ cd /srv/app && sha256sum -c /root/temoin.sha256 | grep -c ': OK'
2002
Le dossier revient en 10,8 secondes, les 2 002 empreintes concordent, et rien d'autre sur la machine n'a bougé. C'est la différence avec une restauration de disque : vous choisissez ce qui revient.
Il reste à rendre la copie régulière. Un service et une minuterie systemd, avec les
variables dans /etc/restic.env (mode 600) :
# /etc/restic.env
RESTIC_REPOSITORY=sftp:depot:/restic
RESTIC_PASSWORD_FILE=/root/.restic-pass
HOME=/root
# /etc/systemd/system/restic-backup.service
[Unit]
Description=Copie hors site restic
Wants=network-online.target
After=network-online.target
[Service]
Type=oneshot
EnvironmentFile=/etc/restic.env
ExecStart=/usr/bin/restic backup /srv/app /etc
ExecStart=/usr/bin/restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
# /etc/systemd/system/restic-backup.timer
[Unit]
Description=Copie hors site restic, chaque nuit
[Timer]
OnCalendar=*-*-* 04:30
RandomizedDelaySec=30m
Persistent=true
[Install]
WantedBy=timers.target
$ sudo systemctl daemon-reload
$ sudo systemctl enable --now restic-backup.timer
$ sudo systemctl start restic-backup.service
$ systemctl show restic-backup.service -p Result
Result=success
$ sudo restic check
no errors were found
Notre machine Debian 13 était réglée sur UTC : 04:30 veut donc dire 04:30 UTC, vérifiez
avec systemctl list-timers. forget --prune garde 7 copies quotidiennes,
4 hebdomadaires et 6 mensuelles, et libère le reste.
6. La règle 3-2-1, appliquée
Trois copies de vos données, sur deux supports différents, dont une hors site. Pour une VM chez FFxF, cela donne :
- Copie 1 : le disque de la VM, en production.
- Copie 2 : les sauvegardes FFxF, sur un serveur de sauvegarde séparé, pour revenir vite après une fausse manœuvre.
- Copie 3 : le dépôt restic, ailleurs que chez nous : chez un autre hébergeur, dans un stockage objet, ou sur un NAS à la maison.
Notre test mettait le dépôt sur une deuxième VM FFxF, dans le même centre de données : c'est pratique pour vérifier la mécanique, ce n'est pas une copie hors site. Gardez aussi le mot de passe du dépôt hors de la machine sauvegardée, dans un gestionnaire de mots de passe : sans lui, le dépôt est illisible, y compris pour vous.
7. Les limites, et ce que ça coûte
- Détruire la VM détruit ses sauvegardes. Manuelles comme automatiques, elles sont supprimées avec la machine. Avant de résilier, copiez ce qui compte ailleurs.
- Une facture impayée aussi. Au 14e jour de retard, la VM et ses sauvegardes sont détruites (conditions, section 2.6).
- Ce n'est pas un plan de reprise. Nos sauvegardes visent l'erreur d'exploitation. Elles sont sur la même infrastructure que la VM, d'où la copie 3.
- Tout ou rien. La restauration FFxF remplace le disque entier. Pas de restauration d'un fichier seul, ni vers une autre machine.
- Rétention courte. 7 sauvegardes manuelles au plus, 7 nuits pour les automatiques. Pour remonter six mois en arrière, c'est restic qui s'en charge.
- restic se surveille. Un dépôt plein ou une clé SSH changée font
échouer le service, et personne ne le voit si rien ne le surveille. Lancez
restic checkde temps en temps et restaurez réellement un dossier une fois par trimestre.
Côté prix : les sauvegardes manuelles sont incluses, l'option automatique coûte 3 CAD par mois et par VM. Un Nano qui sert de dépôt revient à 0,014 CAD l'heure en IPv6 seulement, soit 6,50 CAD par mois au forfait mensuel, avec 20 Go de disque. Nos deux machines de test ont vécu quelques minutes et coûté une heure chacune, soit 0,028 CAD.