Une lame de serveur noire mate et éclairée dans un centre de données plongé dans l’obscurité, projetant un ruban de particules de données émeraude vers un double filaire lumineux d’elle-même, scellé par un cadenas lumineux
Guide de sauvegarde

Sauvegarder un VPS que vous pouvez vraiment restaurer

Presque tout le monde qui fait tourner un serveur a quelque chose qu’il appelle une sauvegarde. Bien peu l’ont un jour restaurée, et c’est dans l’écart entre ces deux phrases que les données disparaissent pour de bon. Voici comment construire une copie qui survit aux trois choses qui détruisent vraiment les serveurs — vos propres mains, une compromission et un compte que vous cessez de contrôler — sans discrètement accoler une identité vérifiée à une machine anonyme.

Nous conservons trois copies de chaque octet qui fait tourner ce réseau, et nous les avons restaurées, volontairement, un mardi ordinaire, plus souvent que nous n’en avons jamais eu besoin dans l’urgence. Ce n’est pas de la rigueur pour la forme. C’est la seule façon de savoir que ce qui se trouve dans le dépôt est une sauvegarde, et non un dossier de bruit chiffré portant un nom rassurant.

Ce qui suit est délibérément démodé. Cela ne fait intervenir aucun produit de sauvegarde avec tableau de bord, abonnement mensuel ou file d’assistance, parce que chacune de ces choses est un compte, et qu’un compte, c’est un nom, une carte et une juridiction — trois choses que vous avez peut-être pris soin de tenir à distance de ce serveur. Cela fait intervenir une seconde machine, une quarantaine de lignes de shell, et une habitude que presque personne ne garde.

Vous devriez pouvoir en venir à bout en une soirée. Les outils sont ceux de Debian 13 et Ubuntu 24.04 ; tout se transpose aux dérivés RHEL moyennant les substitutions évidentes. Si votre serveur est neuf, faites le durcissement de la première heure avant cette page plutôt qu’après — sauvegarder une machine qui appartient déjà à quelqu’un d’autre revient à préserver son travail à lui.

Ce qui détruit vraiment les données sur un serveur loué

Demandez à n’importe qui pourquoi il fait des sauvegardes, et la réponse est généralement « au cas où le disque lâche ». Sur un VPS moderne, c’est à peu près la chose la moins probable qui puisse vous arriver. Votre volume repose sur du NVMe en grappe redondante, avec un hyperviseur qui vous fera migrer d’un hôte défaillant avant même que vous ne le remarquiez ; la panne de disque est le problème de l’hébergeur, et c’est un problème résolu. Bâtir toute sa stratégie de sauvegarde autour de ça revient à acheter un extincteur pour une maison qui prend l’eau.

Voici ce qui fait réellement perdre leurs données aux gens, à peu près dans l’ordre de fréquence. En premier, et de loin : vous. Un rm -rf avec une variable qui s’est retrouvée vide. Un DROP DATABASE lancé sur le mauvais terminal parce que deux onglets se ressemblaient. Un script de migration exécuté deux fois. Un docker compose down -v où le -v relevait du réflexe. Rien d’exotique là-dedans ; c’est un mardi comme un autre.

Deuxième cause : les applications qui suppriment leurs propres données. Une mise à niveau qui exécute une migration destructrice et échoue à mi-chemin. Un plugin qui vide un répertoire de cache qui, en réalité, n’en était pas un. Une rotation de logs configurée sur le mauvais chemin. Troisième cause, la compromission — et notez que c’est ici le cas où un attaquant veut voir les sauvegardes disparaître, ce qui change la conception du système d’une façon sur laquelle nous revenons plus loin. Quatrième cause, facile à oublier sur un hébergeur no-KYC : perdre le compte. Un solde tombé à zéro pendant votre absence, une entrée de gestionnaire de mots de passe que vous n’avez jamais notée, une adresse e-mail abandonnée. Nous suspendons dans les heures qui suivent un solde à zéro, et détruisons sept jours plus tard ; c’est délibérément impitoyable — c’est cette arithmétique qui nous permet de ne pas vous demander qui vous êtes. Aucun agent du support ne peut retrouver votre identité et faire une exception, puisqu’il n’y a pas d’identité à retrouver.

Cette dernière catégorie est celle qui distingue l’hébergement axé sur la vie privée de l’hébergement classique, et elle devrait façonner votre plan. Chaque mesure qui rend ce serveur difficile à vous attribuer rend aussi difficile, pour n’importe qui — nous y compris —, de vous le rendre. La sauvegarde est ce qui transforme cet arbitrage d’un risque en un choix.

Pourquoi un snapshot n’est pas une sauvegarde

Les snapshots sont formidables, et vous devriez les utiliser. Prenez-en un avant chaque mise à niveau du noyau, chaque migration de base de données, chaque fois que vous êtes sur le point de faire quelque chose que vous préféreriez pouvoir annuler. Ils se restaurent en quelques secondes, ils ne coûtent presque rien, et ils vous sauveront une après-midi une bonne douzaine de fois par an.

Ils ne sont pourtant pas des sauvegardes, pour trois raisons structurelles qu’aucun argument marketing d’hébergeur ne change. Ils vivent dans le même compte : quiconque peut se connecter à votre panneau peut les supprimer, et si le compte cesse de fonctionner, les snapshots cessent d’exister avec lui. Ils vivent dans le même domaine de panne : même hébergeur, même plan de contrôle, souvent la même grappe de stockage — ce qui signifie qu’un seul événement malheureux peut plausiblement emporter à la fois l’original et la copie. Et ils sont opaques : un snapshot d’une machine en fonctionnement capture une base de données en pleine écriture avec exactement la même fidélité qu’il capture tout le reste, si bien que restaurer un snapshot d’un serveur MySQL très sollicité vous donne un scénario de récupération après crash plutôt qu’une base de données propre.

La vieille règle du 3-2-1 — trois copies, sur deux types de support, dont une hors site — est généralement récitée sans remarquer que la clause du milieu ne veut rien dire sur une infrastructure louée. Vous n’avez pas deux types de support. Vous avez un périphérique bloc virtuel, et un autre périphérique bloc virtuel, et les deux sont le SAN de quelqu’un d’autre. Ce qui survit à la traduction vers un VPS, c’est la partie qui comptait vraiment depuis le début : au moins une copie doit se trouver quelque part qu’un seul événement malheureux ne peut pas atteindre. Un hébergeur différent, ou au minimum une région différente, des identifiants différents, un compte différent, et — si la raison pour laquelle vous hébergez offshore est juridique plutôt que technique — une juridiction différente, pour qu’une seule et même décision de justice ne puisse pas s’abattre sur les deux copies à la fois.

La destination fait partie de votre modèle de menace

Voici la section que les autres tutoriels de sauvegarde n’ont pas, et c’est celle qui compte le plus si vous avez payé ce serveur en Monero.

Le conseil par défaut, partout sur internet, est de pousser vos sauvegardes vers un stockage objet : Backblaze B2, Amazon S3, Wasabi, un Google Drive via rclone. C’est bon marché, c’est durable, ça marche. Cela défait aussi, en une seule commande, une bonne partie de ce que vous étiez en train de faire. Ouvrir ce compte a exigé une carte et, en général, une pièce d’identité. Dès l’envoi du premier snapshot, cet hébergeur détient un enregistrement horodaté associant votre nom et vos coordonnées de paiement à l’adresse IP de votre serveur, rafraîchi toutes les heures, pour toujours. Ce n’est pas avec nous que vous avez vérifié votre identité ; c’est avec eux — et vous avez alors tracé un trait entre les deux.

La seconde moitié du problème est pire, et c’est celle que les gens ratent. La clé API qui autorise ces envois est un fichier sur le serveur de production. Quiconque obtient root sur cette machine — ou acquiert légalement le disque — n’obtient pas seulement vos données. Il obtient un identifiant qui résout, en un seul appel API, vers une identité de facturation. Le serveur anonyme est devenu un panneau indicateur pointant vers votre banque.

Rien de tout cela ne rend le stockage objet mauvais en soi. Cela en fait une décision plutôt qu’un choix par défaut. Trois portes de sortie, classées par ordre décroissant de fidélité à ce que vous cherchiez au départ :

  • Un second VPS no-KYC, idéalement dans une juridiction différente de la production, payé depuis le même solde crypto. La destination hérite des propriétés d’anonymat de la source au lieu de les contredire. C’est ce que nous faisons nous-mêmes, et ce que suppose le reste de ce guide.
  • Un hébergeur de stockage qui accepte la crypto sans identité. Cela existe, ce sont des acteurs plus modestes ; vérifiez que le circuit de paiement est réellement dénué d’identité avant de faire confiance au discours marketing, et vérifiez le tarif de sortie de données avant de le découvrir en pleine restauration.
  • Une machine que vous possédez physiquement, effectuant un pull via WireGuard depuis votre propre connexion. Excellent pour l’anonymat, médiocre pour la disponibilité, et cela signifie que votre vitesse de restauration est celle de l’upload de votre connexion domestique. Raisonnable comme troisième copie, faible comme copie unique.

Quel que soit votre choix, le compte qui détient les sauvegardes ne devrait partager ni identifiants, ni adresse e-mail, ni méthode de récupération avec le compte qui détient la production. Tout l’enjeu est qu’une seule connexion compromise ne doive pas atteindre les deux. C’est la même discipline que garder ses identités séparées ailleurs, appliquée au coin le moins glamour du système.

Push, pull, et la raison pour laquelle les ransomwares trouvent vos sauvegardes

Presque tous les tutoriels de sauvegarde produisent la même architecture : une tâche cron sur le serveur de production qui s’authentifie auprès d’un dépôt distant et y écrit. C’est simple, ça marche, et cela a une propriété que personne ne mentionne — le serveur de production détient un identifiant capable de supprimer le dépôt tout entier. Purger les anciens snapshots exige des droits de suppression, si bien que la clé qui fait tourner votre tâche nocturne est aussi la clé qui vide le coffre.

Réfléchissez à ce que cela signifie pendant une compromission. Un attaquant avec root sur la machine n’a pas besoin de chercher vos sauvegardes ; vous lui avez obligeamment laissé un identifiant fonctionnel et un fichier de configuration nommant le dépôt. Recenser puis détruire les sauvegardes avant de déclencher quoi que ce soit de visible n’est pas un raffinement hypothétique — c’est une pratique standard, parce que c’est ce qui transforme un incident en négociation. Votre tâche nocturne, c’était la reconnaissance.

Il existe trois architectures, et toute la différence entre elles tient à quelle machine détient quelle clé.

Le push simple est celui décrit ci-dessus. La production dispose des droits lecture-écriture-suppression. Pratique, et qui échoue complètement dans exactement le scénario où vous avez le plus besoin d’une sauvegarde. Ne l’utilisez que si la seule menace qui vous préoccupe vraiment, ce sont vos propres doigts.

Le push append-only conserve la même forme mais retire le verbe dangereux. Le dépôt est servi par quelque chose qui comprend le protocole et refuse les suppressions : rest-server --append-only pour restic, ou borg serve --append-only forcé depuis authorized_keys. La production peut créer de nouveaux snapshots et ne peut pas supprimer les anciens. La purge se fait plus tard, depuis ailleurs, avec une autre clé. C’est une amélioration considérable pour une vingtaine de minutes de travail, et pour la plupart des gens, c’est le bon point d’arrêt.

Le pull inverse la connexion. L’hôte de sauvegarde va chercher ce dont il a besoin sur la production via SSH, et fait tourner l’outil de sauvegarde localement, sur son propre disque. La production ne détient absolument aucun identifiant de sauvegarde — il n’y a rien à trouver sur cette machine, parce qu’elle ne sait même pas où vivent ses sauvegardes. C’est le montage le plus solide, et c’est celui que construit le pas-à-pas ci-dessous.

Soyons honnêtes sur ce que coûte le pull, parce que ce n’est pas gratuit. Vous avez déplacé la clé plutôt que de l’éliminer : l’hôte de sauvegarde détient désormais une clé SSH vers la production, si bien qu’une compromission de l’hôte de sauvegarde se propage en avant, jusqu’au système en production. C’est un meilleur compromis — l’hôte de sauvegarde ne fait tourner aucun service, n’expose rien d’autre que SSH, et constitue une cible bien plus réduite qu’un serveur web public — mais c’en est un, et vous refermez l’essentiel de l’écart restant en forçant cette clé vers une commande en lecture seule, si bien qu’elle ne peut servir à rien d’autre qu’à lire des fichiers.

Choisir l’outil : restic, Borg ou rsync tout simple

Trois outils couvrent l’essentiel des cas, et le choix est bien moins déchirant que ne le suggèrent les fils de discussion des forums.

restic chiffre par défaut, déduplique entre les snapshots, parle SFTP, S3, REST et une douzaine d’autres backends, et se présente comme un unique binaire statique que vous pouvez déposer sur n’importe quoi. Son format de dépôt est adressé par contenu, si bien qu’un snapshot est peu coûteux et qu’une donnée identique n’est stockée qu’une seule fois, quel que soit le nombre de machines qui l’envoient. Les coûts sont réels mais modestes : il veut une mémoire proportionnelle à l’index du dépôt, et une exécution interrompue peut laisser un verrou périmé que l’exécution suivante refuse de franchir tant que vous ne le levez pas avec restic unlock. C’est la recommandation par défaut, et c’est ce qu’utilisent les étapes ci-dessous.

Borg déduplique mieux, compresse mieux, et se montre nettement plus rapide sur des dépôts comptant des millions de petits fichiers. Sa contrepartie, c’est le couplage : Borg doit être installé aux deux extrémités, les versions doivent se correspondre de près, un dépôt est vraiment conçu pour un seul client, et il n’a pas de backend de stockage objet natif sans couche intermédiaire. Si votre source est un gros spool de mails ou un système de fichiers plein de petits fichiers, et que vous contrôlez les deux machines, Borg utilisera deux fois moins d’espace. Son mode --append-only est aussi l’implémentation la plus propre de cette idée, des deux outils.

rsync n’est pas un outil de sauvegarde, et prétendre le contraire est la façon dont on finit avec une copie fidèlement miroitée d’un répertoire corrompu. Il n’a ni versioning, ni déduplication, ni chiffrement au repos ; rsync --delete propage votre erreur vers la copie à la vitesse du câble. C’est néanmoins le bon outil pour déplacer des octets entre deux machines que vous contrôlez, ce qui est précisément le rôle qu’il joue dans une architecture pull, restic se chargeant du versioning et du chiffrement une fois les octets arrivés. Utilisez chacun pour ce qu’il est.

Une chose à ne pas faire : bricoler votre propre solution avec tar et un nom de fichier horodaté. Cela fonctionne pendant environ quatre mois, jusqu’au jour où le disque se remplit parce que rien n’a jamais expiré, ou jusqu’au jour où vous découvrez qu’une copie complète chaque nuit d’un jeu de données de 40 Go représente 1,2 To de stockage par mois, payé pour conserver trente exemplaires presque identiques les uns des autres.

Quoi inclure — et les bases de données qui vous trahiront

Le réflexe, c’est de sauvegarder tout le système de fichiers. Résistez-y. Un système de fichiers racine, ce sont surtout des paquets de distribution que vous pouvez réinstaller en quatre-vingt-dix secondes, et les inclure coûte du stockage, du temps de transfert et, pire, de l’attention — une sauvegarde de 40 Go que personne ne veut tester est moins utile qu’une sauvegarde de 900 Mo restaurée chaque trimestre.

Ce qui ne peut vraiment pas être reconstruit tient en peu de choses : /etc (toute votre configuration, et la raison pour laquelle une reconstruction prend une heure plutôt qu’un week-end), /home et /root, /srv et /var/www, l’état applicatif sous /var/lib/ et /opt/, les volumes Docker nommés, les unités cron et systemd que vous avez écrites, et vos dumps de bases de données. Laissez de côté /proc, /sys, /dev, /run, /tmp, /var/cache, les fichiers d’échange, les sockets et /var/lib/docker/overlay2 — ce dernier se reconstruit à partir de votre fichier compose, et c’est souvent le plus gros répertoire du disque, à lui seul.

Voici maintenant la partie qui ruine discrètement les restaurations. Copier le répertoire de données d’une base pendant qu’elle tourne produit un ensemble de fichiers qui a toutes les chances d’être inutilisable. Le moteur conserve un état en mémoire, écrit dans plusieurs fichiers selon un ordre qui compte, et votre copie parcourt cette arborescence sur plusieurs minutes, attrapant différents fichiers à différents instants. InnoDB s’en remettra parfois par récupération après crash, et parfois non ; la panne refait surface des mois plus tard, pendant une restauration qui se déroule déjà, par ailleurs, un mauvais jour.

Passez plutôt par le moteur pour le dump, puis sauvegardez ce dump :

# MariaDB / MySQL — InnoDB gets a consistent snapshot from one transaction
mariadb-dump --single-transaction --quick --routines --triggers --events \
  --all-databases | zstd -T0 > /var/backups/db/all-$(date -u +%F).sql.zst

# PostgreSQL — pg_dump is consistent by design; grab roles separately
pg_dumpall --globals-only > /var/backups/db/globals.sql
pg_dump -Fc -Z6 mydb    > /var/backups/db/mydb.dump

# SQLite — never cp a live database; WAL mode makes that a torn file
sqlite3 /var/lib/app/app.db ".backup /var/backups/db/app.db"

Deux notes de bas de page qui valent le coup. --single-transaction ne vous donne la cohérence que pour InnoDB — si une table est encore en MyISAM, elle est copiée hors de la transaction et peut être incohérente avec le reste, donc convertissez ces tables ou verrouillez-les. Et une fois que vous faites des dumps, excluez le répertoire de données actif de la passe de fichiers. Sauvegarder les deux revient à stocker une grosse copie déchirée à côté de la bonne, et à donner à une future restauration deux candidats dont l’un est silencieusement erroné.

Les conteneurs ne changent pas le principe, seulement le chemin : lancez le dump avec docker compose exec -T db mariadb-dump … et sauvegardez le fichier obtenu, pas le volume qui se trouve dessous.

Où vit la clé de chiffrement

Le chiffrement côté client est la seule raison pour laquelle il est acceptable de stocker vos données sur une machine qui n’est pas celle dont elles proviennent. restic comme Borg chiffrent avant que quoi que ce soit ne quitte la source, si bien que l’hôte de sauvegarde ne détient que du texte chiffré et peut être traité comme un stockage non fiable. Cette propriété vaut exactement ce que vaut votre gestion de la clé, et pas un iota de plus.

Le mode d’échec est d’une banalité déprimante. Le mot de passe du dépôt se trouve dans /etc/restic/env sur le serveur de production, ce qui est correct et nécessaire pour l’automatisation. Puis c’est la production que vous perdez — détruite, saisie, ou simplement disparue avec le compte — et vous voilà face à plusieurs centaines de gigaoctets de blocs chiffrés, avec la réalisation naissante que l’unique copie de la clé se trouvait à l’intérieur de la chose même contre la perte de laquelle vous cherchiez à vous protéger.

Donc : le mot de passe sur le serveur est une copie de travail, jamais l’original de référence. Cet original vit quelque part qui survit au serveur — un gestionnaire de mots de passe dont le coffre est lui-même sauvegardé ailleurs, ou noté sur papier dans un tiroir, ou les deux. Notez à côté l’emplacement du dépôt et la commande de restauration exacte, parce qu’une phrase de passe sans contexte est une énigme que vous résoudrez sous stress dans dix-huit mois. Et prenez cinq minutes pour la vérifier : depuis une machine différente, avec seulement ce qui se trouve dans le gestionnaire de mots de passe, lancez restic snapshots contre le dépôt. Si cela fonctionne, vous avez une sauvegarde. S’il faut quoi que ce soit qui n’existe que sur la production, vous avez un dossier très coûteux.

Les deux outils prennent en charge plusieurs clés sur un même dépôt (restic key add), ce qui est la façon propre de donner accès à la tâche de purge ou à un second administrateur sans partager la phrase de passe d’origine. Et si le disque de production est chiffré avec LUKS, gardez les deux secrets véritablement séparés — stocker la phrase de passe restic à l’intérieur du volume LUKS, et la phrase de passe LUKS à l’intérieur du dépôt restic, forme une boucle qui échoue de façon fermée des deux côtés.

Rétention : le piège de ne garder qu’une semaine

La rétention ressemble à une question de coût de stockage, mais c’est en réalité une question de délai de détection. Le chiffre qui compte n’est pas la quantité de disque que vous voulez dépenser ; c’est le temps pendant lequel un problème peut passer inaperçu dans votre système. Quelle que soit cette durée, votre plus ancienne sauvegarde doit être plus vieille qu’elle.

Sept snapshots quotidiens semblent généreux et se révèlent maigres en pratique. Une table corrompue que personne n’interroge, une suppression lente causée par une tâche cron mal réglée, une intrusion restée silencieuse pendant un mois avant de faire quoi que ce soit de visible — tout cela met couramment plus d’une semaine à remonter à la surface, et si votre historique ne descend qu’à sept jours, alors chaque snapshot que vous détenez est déjà contaminé. Le temps de séjour des intrusions réelles se mesure régulièrement en semaines. Des snapshots mensuels bon marché sont la défense spécifique contre cela, et la déduplication les rend vraiment très bon marché : un mensuel conservé pendant un an n’ajoute qu’une fraction d’une copie complète, parce que seuls les blocs réellement modifiés sont stockés deux fois.

restic forget \
  --keep-daily 7 --keep-weekly 5 --keep-monthly 12 --keep-yearly 2 \
  --prune

Cette échelle — une semaine de jours, un mois de semaines, un an de mois, quelques années d’années — représente environ vingt-six snapshots et, sur des données typiques, bien moins du double de la taille d’une seule copie complète. C’est le réglage par défaut que nous défendrions, sauf raison précise de s’en écarter.

Deux remarques opérationnelles. forget sans --prune ne retire que les étiquettes, si bien que l’espace n’est pas récupéré tant que vous n’avez pas purgé — ce qui surprend ceux qui observent un disque qui refuse de rétrécir. Et --prune exige des droits de suppression sur le dépôt, donc dans une architecture append-only ou pull, cela ne tourne pas sur le serveur de production. Cela tourne sur l’hôte de sauvegarde, ou depuis votre ordinateur portable, avec une clé que la production n’a jamais vue. Cette séparation est tout l’enjeu ; ne la défaites pas par confort à la toute dernière étape.

L’automatiser, sans l’échec silencieux

Le désastre classique en matière de sauvegarde, ce n’est pas une tâche qui plante. C’est une tâche qui cesse de tourner sans le dire à personne, découverte onze mois plus tard par quelqu’un qui en avait besoin. Chaque élément ci-dessous existe pour rendre ce scénario précis impossible.

Utilisez un timer systemd plutôt que cron. Vous obtenez de vrais logs dans le journal, avec les codes de sortie qui vont avec, Persistent=true pour qu’une exécution manquée pendant que la machine était éteinte ait lieu au prochain démarrage plutôt que d’être perdue pour toujours, et RandomizedDelaySec pour qu’une flotte de machines ne débarque pas toutes ensemble sur l’hôte de sauvegarde à 3h00 pile. La notification d’échec de cron, c’est un e-mail vers une boîte locale qui, sur un serveur moderne, ne va précisément nulle part.

# /etc/systemd/system/backup.timer
[Unit]
Description=Nightly encrypted backup

[Timer]
OnCalendar=*-*-* 03:17:00
RandomizedDelaySec=1800
Persistent=true

[Install]
WantedBy=timers.target

Ajoutez ensuite un dead man’s switch, la ligne à elle seule la plus précieuse de tout ce guide. Tout à la fin du script — après le succès de la sauvegarde, pas avant — effectuez une requête HTTPS vers un moniteur qui s’attend à avoir de vos nouvelles chaque jour, et qui alerte quand ce n’est pas le cas. Cela inverse la logique de notification : au lieu de compter sur un échec pour générer un message, c’est l’absence elle-même qui devient l’alarme. Une tâche morte depuis trois jours devient alors un message dans votre boîte de réception plutôt qu’une découverte en pleine crise. Auto-hébergez le moniteur sur l’hôte de sauvegarde si vous préférez ne pas créer un compte tiers de plus ; cela tient en quelques lignes et un timer qui lui est propre.

Enfin, les petits risques opérationnels, que nous avons tous rencontrés au moins une fois. Une exécution interrompue laisse un verrou, et chaque exécution suivante échoue avec un message que vous arrêtez de lire après la quatrième nuit — traitez restic unlock délibérément, pas par réflexe. Un disque de destination plein fait échouer toutes les tâches jusqu’à ce que quelqu’un regarde ; alertez sur l’espace libre, pas seulement sur le statut de la tâche. Une clé SSH qui expire, une clé d’hôte renouvelée, une règle nftables ajoutée pendant un travail sans rapport — chacune coupera silencieusement le pull. Et systemctl enable --now, pas seulement start : un timer qui n’a jamais été activé fonctionne à merveille jusqu’au premier redémarrage, et ne tourne plus jamais ensuite.

L’exercice de restauration

Tout ce qui précède n’est que préparation. Voici la partie qui transforme cela en une véritable sauvegarde, et c’est la partie que presque tout le monde saute.

Une fois par trimestre, déployez un VPS neuf — le Starter à 5 $/mois suffit largement, et la facturation est horaire, calculée à la seconde près, donc tout l’exercice coûte quelques centimes. Restaurez dedans en utilisant uniquement ce que vous auriez dans un vrai désastre : l’adresse du dépôt, la phrase de passe tirée de votre gestionnaire de mots de passe, et la procédure écrite. N’utilisez délibérément rien qui vienne de la production, parce que dans le scénario que vous répétez, la production n’existe pas. Relancez l’application, pointez une entrée de fichier hosts vers la nouvelle IP, cliquez un peu partout. Puis détruisez la machine.

# on a throwaway machine, with nothing but the passphrase
export RESTIC_REPOSITORY=sftp:[email protected]:/srv/restic/prod
restic snapshots                      # can you even see the history?
restic restore latest --target /restore
restic check --read-data-subset=10%   # verify stored blocks, not just metadata

Ce que cela révèle n’est jamais ce à quoi vous vous attendiez. C’est le fichier de configuration qui se trouvait dans un répertoire que la liste d’inclusion ne couvrait pas. Le dump de base de données qui affiche zéro octet depuis cinq semaines parce qu’un mot de passe a changé et que le script n’a jamais vérifié son code de sortie. L’application qui refuse de démarrer parce qu’un secret vit dans une variable d’environnement détenue par l’orchestrateur et ne s’est jamais trouvé sur le système de fichiers. L’enregistrement DNS non documenté. Le certificat qu’il faut réémettre avant que quoi que ce soit ne réponde sur le port 443. Chacun de ces cas est un correctif de dix minutes un après-midi tranquille, et deux vilaines heures à trois heures du matin.

Notez combien de temps l’exercice a pris, de bout en bout. Ce chiffre — pas la fréquence des sauvegardes — est votre véritable temps de récupération, et c’est la seule réponse honnête quand on vous demande combien de temps durerait une panne. Ajoutez aussi restic check --read-data-subset=5% à un timer mensuel : cela lit et vérifie un échantillon tournant des blocs réellement stockés, et pas seulement l’index, ce qui permet de repérer une corruption silencieuse tant qu’il existe encore une bonne copie de repli. Si vous déménagez un jour le serveur entier vers un autre hébergeur, une restauration répétée, c’est aussi la majeure partie de la migration déjà faite.

  1. Faites l’inventaire de ce qui ne peut vraiment pas être reconstruit

    Avant tout outillage, écrivez la liste. Parcourez la machine et demandez-vous, pour chaque répertoire : si celui-ci disparaissait, pourrais-je le recréer depuis un gestionnaire de paquets, un dépôt git ou un fichier compose ? Si oui, il n’a rien à faire dans la sauvegarde. Ce qui reste est généralement bien plus réduit qu’on ne l’imagine — configuration, données utilisateur, état applicatif, dumps de bases de données.

    # the fast way to find what is actually big and stateful
    du -x -h -d2 / 2>/dev/null | sort -rh | head -30
    docker volume ls    # named volumes are state; overlay2 is not

    Transformez le résultat en deux fichiers explicites, /etc/restic/include.txt et /etc/restic/exclude.txt. Des listes explicites valent mieux que des expressions find astucieuses, parce qu’elles sont relisables, et parce qu’un nouveau répertoire apparaissant sur le serveur devrait être une décision délibérée plutôt qu’une inclusion silencieuse.

  2. Déployez la cible de sauvegarde dans une juridiction différente

    Commandez un second VPS dans une région différente de celle où tourne la production — si la production est à Paris, placez la copie à Reykjavík ou à Bucarest. L’idée est qu’aucun événement, légal ou physique, ne puisse atteindre les deux machines à la fois. Un Starter à 5 $/mois embarque 80 Go de NVMe, ce qui, après déduplication, tient un très long historique pour un petit serveur typique ; le cycle de facturation à 12 mois divise ce prix par deux. Payez-le depuis le même solde crypto, pour que la destination hérite de l’anonymat de la source au lieu de le contredire.

    Donnez-lui un compte séparé de la production si vous voulez une isolation complète des identifiants. Puis durcissez-le exactement comme n’importe quelle autre machine — SSH par clés uniquement, pare-feu à refus par défaut — et n’installez rien d’autre dessus. La valeur de cette machine, c’est d’être ennuyeuse : pas de serveur web, aucun port ouvert au-delà de SSH, rien à exploiter depuis internet.

  3. Créez une porte en lecture seule depuis l’hôte de sauvegarde vers la production

    Voici l’étape qui transforme tout cela en pull. Sur l’hôte de sauvegarde, générez une clé dédiée. Installez ensuite sa moitié publique sur la production, avec une commande forcée, de sorte que la clé ne puisse faire qu’une seule chose : lire des fichiers. Elle ne peut ni ouvrir un shell, ni rediriger un port, ni écrire quoi que ce soit.

    # on the backup host
    ssh-keygen -t ed25519 -a 100 -f ~/.ssh/pull_prod -C "pull@backup"
    
    # on production, in /root/.ssh/authorized_keys — one line
    command="/usr/bin/rrsync -ro /",restrict ssh-ed25519 AAAAC3Nz… pull@backup

    rrsync est fourni avec rsync (/usr/bin/rrsync sur Debian 13 ; /usr/share/doc/rsync/scripts/rrsync sur les versions plus anciennes), et -ro le force à refuser tout ce qui n’est pas une lecture. restrict désactive en un seul mot le port forwarding, l’agent forwarding, l’allocation de PTY et X11. Vérifiez que la cage tient avant d’en dépendre — ssh -i ~/.ssh/pull_prod root@production doit échouer à vous donner un shell.

  4. Faites les dumps de bases sur la production, selon leur propre planning

    La production conserve une seule responsabilité : produire des dumps cohérents dans un répertoire de dépôt temporaire que le pull viendra récupérer. Cela ne nécessite aucun identifiant de sauvegarde, ce qui est précisément pourquoi l’architecture fonctionne.

    # /usr/local/sbin/dump-db.sh   (chmod 700)
    set -euo pipefail
    D=/var/backups/db; install -d -m 700 "$D"
    mariadb-dump --single-transaction --quick --routines --triggers --events \
      --all-databases | zstd -T0 > "$D/all.sql.zst.tmp"
    mv "$D/all.sql.zst.tmp" "$D/all.sql.zst"

    Remarquez l’écriture vers un fichier temporaire suivie d’un renommage : cela signifie que le pull ne peut jamais récupérer un dump à moitié écrit, quel que soit le minutage. set -euo pipefail n’est pas de la décoration — sans cela, un mariadb-dump qui échoue envoie un flux vide dans zstd, qui réussit malgré tout, et vous obtenez un fichier compressé parfaitement valide qui ne contient rigoureusement rien. C’est la façon la plus courante qu’une sauvegarde a de devenir silencieusement inutile. Faites-le tourner depuis son propre timer, une demi-heure avant le pull.

  5. Rapatriez les données vers l’hôte de sauvegarde

    Sur l’hôte de sauvegarde, rsyncez la liste d’inclusion de la production vers une arborescence de dépôt temporaire. Seuls les blocs modifiés traversent le réseau, donc après la première exécution, c’est rapide et peu coûteux.

    # /usr/local/sbin/pull.sh   (chmod 700, runs on the BACKUP host)
    set -euo pipefail
    [email protected]
    # -r is spelled out on purpose: with --files-from, -a does NOT imply
    # recursion, and without it you silently copy empty directories.
    rsync -aHAX -r --delete --numeric-ids \
      -e "ssh -i /root/.ssh/pull_prod -o BatchMode=yes" \
      --files-from=/etc/backup/include.txt \
      --exclude-from=/etc/backup/exclude.txt \
      "$SRC:/" /srv/staging/prod/

    -aHAX préserve les hardlinks, les ACL et les attributs étendus, et --numeric-ids garde une notion de propriétaire cohérente entre des machines dont les /etc/passwd diffèrent. --delete est sûr ici précisément parce que le répertoire de dépôt temporaire n’est pas la sauvegarde — l’historique versionné vit dans le dépôt restic construit à l’étape suivante, si bien qu’une suppression qui se propage dans ce répertoire temporaire reste récupérable depuis le snapshot de la veille.

  6. Initialisez le dépôt et conservez la clé hors ligne

    Toujours sur l’hôte de sauvegarde, créez un dépôt restic local et sauvegardez-y l’arborescence de dépôt temporaire. Local signifie pas de réseau sur le chemin critique, aucun identifiant distant à voler, et une restauration qui tourne à la vitesse du disque.

    apt install -y restic
    install -d -m 700 /etc/backup
    openssl rand -base64 32 > /etc/backup/pass   # write this into your password manager NOW
    chmod 600 /etc/backup/pass
    
    export RESTIC_REPOSITORY=/srv/restic/prod
    export RESTIC_PASSWORD_FILE=/etc/backup/pass
    restic init

    Copiez cette phrase de passe dans un gestionnaire de mots de passe, et notez juste à côté le chemin du dépôt et la commande de restauration. Puis prouvez-le : depuis une troisième machine, en utilisant uniquement le gestionnaire de mots de passe, lancez restic -r sftp:backup@…:/srv/restic/prod snapshots. Si cela liste des snapshots, la clé est véritablement récupérable. S’il faut quoi que ce soit qui n’existe que sur l’un des deux serveurs, corrigez cela maintenant plutôt que de le découvrir plus tard.

  7. Planifiez tout ça, et faites du silence une alarme

    Enveloppez le pull, l’exécution de restic et la purge dans un seul script, et pilotez-le depuis un timer systemd. Notez que forget --prune peut sans risque tourner ici, parce que l’hôte de sauvegarde possède légitimement le dépôt — la production n’a jamais détenu, à aucun moment, d’identifiant de suppression.

    # tail of /usr/local/sbin/backup.sh
    restic backup /srv/staging/prod --tag nightly
    restic forget --keep-daily 7 --keep-weekly 5 --keep-monthly 12 \
                   --keep-yearly 2 --prune
    curl -fsS -m 10 --retry 3 https://hc.example.net/ping/<uuid>  # only on success
    systemctl daemon-reload
    systemctl enable --now backup.timer
    systemctl list-timers backup.timer     # confirm the next run is where you expect

    Le curl ne s’exécute que si toutes les commandes précédentes ont réussi, grâce à set -e. Le moniteur, à l’autre bout, attend un ping quotidien et alerte en son absence, ce qui transforme une tâche qui s’est arrêtée discrètement en un e-mail plutôt qu’en une découverte archéologique. enable --now, pas seulement start — un timer qui n’a jamais été activé survit exactement jusqu’au premier redémarrage.

  8. Faites l’exercice de restauration, et notez combien de temps il a pris

    Placez un rappel récurrent quelque part que vous consultez réellement, une fois par trimestre. Déployez un Starter jetable, restaurez dedans avec rien d’autre que la phrase de passe et la procédure écrite, relancez l’application, vérifiez qu’elle sert de vraies données, détruisez la machine. La facturation horaire fait que tout l’exercice coûte quelques centimes.

    restic restore latest --target /restore
    zstd -dc /restore/var/backups/db/all.sql.zst | mariadb
    systemctl start nginx app
    curl -H 'Host: example.com' http://127.0.0.1/health

    Notez le temps écoulé et chaque surprise rencontrée, puis corrigez ces surprises dans le script de sauvegarde plutôt que dans votre mémoire. Ce temps écoulé est votre véritable objectif de récupération ; tant que vous ne l’avez pas mesuré une fois, tout chiffre que vous avancez n’est qu’une estimation.

Comparatif

Où mettre la copie

Chaque destination confrontée aux quatre questions qui la déterminent : ce qu’elle coûte à votre anonymat, ce qu’elle coûte en argent, la vitesse à laquelle vous récupérez vos données, et ce à quoi elle survit.
DestinationCoût pour l’anonymatArgentVitesse de restaurationSurvit à
Second VPS no-KYC, région différenteAucun — payé depuis le même solde crypto, aucune identité nulle part5 $/mois, divisé par deux sur un cycle de 12 moisRapide — de datacentre à datacentre, en 1 à 10 GbpsPerte de compte, compromission, une juridiction, vos propres erreurs
Snapshot de l’hébergeurAucunBon marchéQuelques secondesPresque rien — même compte, même domaine de panne, meurt avec les deux
Stockage objet (B2 / S3 / Wasabi)Élevé — carte et pièce d’identité sur le compte, et la clé API sur votre serveur qui pointe vers luiStockage très bon marché, les frais de sortie mordent pendant une restaurationRapide, si vous acceptez la facture de sortieCompromission et perte de compte, au prix d’un nom attaché à la machine
Hébergeur de stockage acceptant la cryptoFaible, si le circuit de paiement est véritablement sans identité — vérifiez, ne présumez pasModéréTrès variable — vérifiez les limites de sortie avant d’en avoir besoinLa plupart des cas, avec plus de risque de contrepartie qu’un VPS que vous contrôlez
NAS domestique, récupéré via WireGuardAucun — rien ne sort de votre propre réseau ni en clair, ni de façon identifiableMatériel que vous possédez déjàLent — plafonné par le débit montant de votre connexion domestiqueTout, sauf votre maison ; faible comme copie unique, excellent comme troisième copie
Rien / « c’est dans git »AucunGratuitJamaisRien. Git conserve votre code ; il ne conserve ni votre base de données, ni vos fichiers importés, ni votre /etc
FAQ

Questions qui méritent une réponse

Un snapshot de l’hébergeur n’est-il pas déjà une sauvegarde ?

Non, et la distinction n’est pas pédante. Un snapshot vit dans le même compte, sous les mêmes identifiants, dans le même domaine de panne que le serveur qu’il copie — il ne survit donc pas à la perte du compte, et quiconque accède à votre panneau peut le supprimer en même temps que l’original. Il est de plus pris sur une machine en fonctionnement, ce qui signifie qu’une base de données très sollicitée est capturée en pleine écriture. Utilisez les snapshots comme un bouton d’annulation avant des changements risqués ; utilisez un dépôt chiffré hors site comme sauvegarde.

restic ou Borg : lequel utiliser ?

restic, sauf raison précise de faire autrement. Il chiffre par défaut, ne nécessite rien d’installé sur la destination, parle tous les backends qui valent la peine, et se présente comme un seul binaire statique. Borg déduplique et compresse mieux, et se montre nettement plus rapide sur des systèmes de fichiers comptant des millions de petits fichiers, mais il doit être installé et synchronisé en version aux deux extrémités, et il est vraiment conçu pour un seul client par dépôt. Gros spool de mails et les deux machines sous votre contrôle : Borg. Tout le reste : restic.

De combien de disque la cible de sauvegarde a-t-elle besoin ?

Pour un dépôt dédupliqué avec l’échelle de rétention de ce guide — 7 quotidiens, 5 hebdomadaires, 12 mensuels, 2 annuels — prévoyez environ deux à trois fois la taille des données que vous sauvegardez réellement, pas de tout le serveur. Vingt-six snapshots ne signifient pas vingt-six copies, parce que seuls les blocs modifiés sont stockés à nouveau. Un petit site avec 15 Go d’état réel tient confortablement sur le Starter à 80 Go, avec des années d’historique en réserve.

Un second VPS ne double-t-il pas ma facture d’hébergement ?

Seulement si la cible de sauvegarde ressemble à la production, ce qu’elle ne devrait pas faire. Elle ne fait tourner aucune application et ne sert aucun trafic ; elle a besoin de disque, pas de CPU. Un Starter à 5 $/mois derrière un serveur de production à 30 $/mois représente un sixième de la facture, et le cycle à 12 mois en retire encore 50 %. Face au coût de tout perdre, c’est la ligne la moins chère de la facture — et la cible double comme machine de répétition pour l’exercice de restauration.

Où le mot de passe du dépôt doit-il vivre ?

Dans un gestionnaire de mots de passe dont le coffre est lui-même sauvegardé ailleurs, ou sur papier, ou les deux — et juste à côté, l’adresse du dépôt et la commande de restauration exacte. La copie dans /etc sur le serveur est une copie de travail pour l’automatisation, jamais l’original de référence. Vérifiez-le correctement : depuis une machine qui n’est ni la production ni l’hôte de sauvegarde, en utilisant uniquement ce qui se trouve dans le gestionnaire de mots de passe, lancez restic snapshots. Si quoi que ce soit d’autre est nécessaire, vous n’avez pas encore de sauvegarde récupérable.

À quelle fréquence les sauvegardes doivent-elles tourner ?

Demandez-vous quelle quantité de travail vous êtes prêt à refaire. Une fréquence nocturne convient à la plupart des serveurs : vous perdez au plus une journée, et une seule exécution par nuit est facile à raisonner. Une base de données très sollicitée en demande davantage — des dumps horaires de la seule base, avec la passe de fichiers complète qui reste nocturne, est la forme habituelle. Au-delà de ce point, la fréquence rapporte moins que le même effort consacré à une rétention plus longue et à un véritable exercice de restauration, là où se trouve le risque réel.

Puis-je sauvegarder un serveur dont le disque est chiffré avec LUKS ?

Oui, et les deux sont complémentaires plutôt que redondants. LUKS protège le disque quand la machine est éteinte ; la sauvegarde vous protège de la suppression, de la corruption et de la perte totale de la machine. Sauvegardez le système de fichiers monté exactement comme vous le feriez pour un disque non chiffré — restic chiffre à nouveau à la sortie, si bien que le dépôt est sûr même sur un stockage non fiable. Gardez les deux secrets dans des endroits véritablement séparés : une phrase de passe LUKS stockée uniquement dans le dépôt restic, ou une phrase de passe restic stockée uniquement dans le volume LUKS, forme une boucle qui échoue de façon fermée des deux côtés.

Si mon serveur est compromis, mes sauvegardes sont-elles en sécurité ?

Cela dépend entièrement d’une décision que vous avez prise des mois plus tôt. Si le serveur de production détient un identifiant avec des droits de suppression sur le dépôt, alors non — un attaquant recense et détruit d’abord les sauvegardes, parce que c’est ce qui transforme un incident en négociation. Si le dépôt est en append-only, ou si l’hôte de sauvegarde fait du pull et que la production ne détient aucun identifiant de sauvegarde, alors l’historique survit, et vous restaurez un snapshot antérieur à l’intrusion. C’est tout l’argument en faveur de l’architecture pull, et la raison de la préférer avant d’en avoir besoin.

Deploy your offshore server.

Choisissez une région. Choisissez un plan. Collez une clé. Payez. Les 47 prochaines secondes sont pour nous.