SSD Nodes Learn 🎉 VPS dès $5.50/mois
Guides Matt ConnorPar Matt Connor

Snapshots, sauvegardes ou clones de VPS : que choisir ?

Un snapshot reste chez votre fournisseur : ce n’est pas une sauvegarde. Découvrez ce que chaque méthode restaure et quoi corriger sur un VPS cloné.

Ce que sont réellement un snapshot, une sauvegarde et un clone

Un snapshot de VPS est une image disque de votre serveur, conservée par votre fournisseur, sur son infrastructure et dans votre compte. Une sauvegarde est une copie indépendante de vos données que vous pouvez restaurer ailleurs, sans l’aide du fournisseur qui détenait l’original. Un clone est une nouvelle instance déployée à partir d’un snapshot. Il démarre donc comme une copie exacte de l’original, y compris son identité.

Ces mécanismes répondent à des besoins différents. Un snapshot permet d’annuler une mise à niveau défectueuse en quelques minutes, mais il ne sert à rien si votre compte est fermé. Une sauvegarde reste disponible même si le fournisseur cesse son activité. Sa restauration prend plus de temps, car il faut d’abord reconstruire la machine. Un clone fournit un deuxième serveur opérationnel en une seule étape. Il crée aussi deux machines qui pensent être la même machine.

Pourquoi un snapshot de VPS n’est pas une sauvegarde

Le problème vient du domaine de défaillance, pas de la qualité de l’image. Un snapshot se trouve sur la plateforme de stockage de votre fournisseur, généralement dans la même région que le serveur d’origine, et toujours dans le même compte. Un seul incident peut toucher le serveur et son snapshot en même temps.

  • Le compte est suspendu, un paiement échoue ou quelqu’un vole les identifiants de connexion.
  • Une personne ou un script disposant d’un accès à l’API supprime l’instance. Chez de nombreux fournisseurs, la suppression d’une instance supprime également ses snapshots. Consultez le comportement documenté par votre fournisseur avant de supposer le contraire.
  • La région rencontre un incident et tout ce qu’elle contient devient inaccessible en même temps.
  • Un processus exécuté avec les privilèges de root sur le serveur trouve le token d’API du fournisseur que vous avez laissé dans /root, puis supprime les snapshots avant de toucher au disque.

Une sauvegarde est la copie qui survit aux quatre situations. Le test tient en une question : si votre compte fournisseur cessait d’exister cet après-midi, que pourriez-vous encore restaurer, et où le restaureriez-vous ? Tout ce qui échoue à ce test est un outil de rollback. Continuez à prendre des snapshots, car rien ne se restaure plus rapidement. Conservez ensuite une deuxième copie sur un stockage que votre fournisseur ne contrôle pas.

L’ancienne règle reste valable : trois copies des données, sur deux types de stockage, dont une hors de la plateforme. Un snapshot chez le fournisseur et un repository restic sur une infrastructure distincte couvrent cette règle avec deux composants.

Pourquoi une snapshot d’une base de données en cours d’exécution peut être incohérente après restauration

Une snapshot fournie par un hébergeur copie le périphérique bloc tel qu’il se trouve à un instant donné. Elle ne demande pas à vos applications de s’arrêter au préalable et ne peut pas voir les données qui se trouvent encore dans le page cache. L’image est donc au mieux cohérente après crash. Elle correspond exactement à l’état du disque si quelqu’un avait débranché le câble d’alimentation.

La plupart des composants gèrent cette situation. ext4 et XFS rejouent leur journal au montage, ce qui permet au système de fichiers de redémarrer. PostgreSQL rejoue son write-ahead log au démarrage, comme l’indique le journal :

LOG:  database system was not properly shut down; automatic recovery in progress

InnoDB fait de même et affiche ses propres messages de crash recovery au démarrage. Cette récupération correspond au fonctionnement prévu de la base de données. Une snapshot d’un seul volume PostgreSQL ou MySQL peu sollicité se restaure donc généralement correctement.

Les situations dans lesquelles la cohérence après crash ne suffit pas sont bien réelles, et ce sont celles qui causent les problèmes les plus graves. Si vos données sont réparties sur deux volumes, le disque root et le disque de données séparé sont capturés à des instants différents. Les fichiers de données et le répertoire des journaux peuvent donc être incohérents, et la récupération ne dispose d’aucun journal correct à rejouer. Tout fichier qu’une application écrit sans appeler fsync, par exemple un upload reçu partiellement ou un fichier de file d’attente, peut être restauré tronqué. Les données que l’application conserve en mémoire et écrit périodiquement ne se trouvent tout simplement pas dans l’image.

Écrivez donc un dump sur le disque avant de prendre la snapshot. L’image contient ainsi un fichier dont vous savez qu’il est cohérent en interne, quel que soit l’état des fichiers de données actifs.

sudo -u postgres pg_dumpall --clean --file=/var/backups/pg-$(date +%F).sql
sudo mysqldump --single-transaction --routines --all-databases > /var/backups/mysql-$(date +%F).sql

--single-transaction fournit un dump cohérent des tables InnoDB sans bloquer les écritures, car le dump s’exécute dans une transaction repeatable-read unique. Il ne couvre pas les tables MyISAM, qui nécessitent un verrou ou l’arrêt du serveur. Vérifiez que le dump n’est ni vide ni tronqué avant de lui faire confiance : tail -n 1 /var/backups/mysql-$(date +%F).sql sur un mysqldump complet se termine par un commentaire Dump completed.

Si vous disposez d’un volume de données séparé, vous pouvez le geler pendant les quelques secondes nécessaires à la snapshot :

sudo fsfreeze -f /srv
# take the snapshot from your provider's panel or API
sudo fsfreeze -u /srv

Ne gelez qu’un volume de données. Ne gelez jamais /. Un système de fichiers root gelé bloque toutes les écritures sur la machine, y compris celles du shell que vous utiliseriez pour saisir la commande de dégel. Vous vous retrouvez donc bloqué et devez attendre un hard reset.

La partie hors site : restic ou Borg

Le snapshot est la moitié rapide. La copie hors site est celle qui vous protège contre la perte de votre fournisseur. restic est un bon choix par défaut, car il déduplique les données, les chiffre côté client et écrit vers un object storage compatible S3, SFTP ou un simple répertoire. Un VPS de stockage comme cible hors site convient bien ici, car les repositories de sauvegarde ont surtout besoin de capacité, et non d’IOPS.

sudo apt update && sudo apt install -y restic
sudo sh -c 'umask 077; head -c 24 /dev/urandom | base64 > /root/.restic-pass'
sudo chmod 600 /root/.restic-pass
sudo cat /root/.restic-pass

Copiez maintenant cette passphrase dans un gestionnaire de mots de passe, sur un appareil qui n’est pas ce serveur. Un repository restic ne peut pas être ouvert sans elle et il n’existe aucune procédure de récupération. Si la seule copie du mot de passe se trouvait sur la machine que vous venez de perdre, la sauvegarde n’est plus qu’un contenu chiffré inutilisable.

export RESTIC_REPOSITORY="s3:https://s3.example.com/vps-backups"
export RESTIC_PASSWORD_FILE=/root/.restic-pass
export AWS_ACCESS_KEY_ID="..."
export AWS_SECRET_ACCESS_KEY="..."
sudo -E restic init
sudo -E restic backup /etc /srv /var/backups
sudo -E restic snapshots

sudo -E conserve ces variables, car sans lui root obtient un environnement vierge et restic indique qu’aucun emplacement de repository n’a été spécifié. restic snapshots doit lister l’exécution que vous venez de lancer, avec son hôte et ses chemins. Vérifiez régulièrement le repository lui-même et relisez une partie des données au lieu de vérifier uniquement sa structure :

sudo -E restic check --read-data-subset=5%
sudo -E restic restore latest --target /tmp/restore-check
sudo -E restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune

Une sauvegarde qui n’a pas été testée reste une supposition. Effectuez au moins une restauration vers un autre VPS, mesurez sa durée et notez-la, car cette durée correspond à votre véritable objectif de reprise. Borg constitue l’autre choix fiable et stocke son repository via SSH plutôt que dans un object storage ; les compromis sont présentés dans la comparaison entre restic et BorgBackup.

À corriger avant qu’un VPS cloné soit utilisé en production

Un clone est une réplique exacte. C’est son intérêt, mais aussi son problème. Tout ce qui rendait l’original unique est dupliqué, et les doublons entrent en conflit.

Régénérez les clés d’hôte SSH. Le clone contient les fichiers /etc/ssh/ssh_host_* de l’original. Les deux serveurs présentent donc la même identité d’hôte. Toute personne qui en contrôle un peut usurper l’identité de l’autre auprès de chaque client ayant accepté cette clé. SSH ne génère aucun avertissement, car il s’agit de la clé attendue par le client.

sudo rm -f /etc/ssh/ssh_host_*
sudo ssh-keygen -A
sudo systemctl restart ssh
ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub

ssh-keygen -A écrit une nouvelle clé pour chaque type attendu par le daemon. L’empreinte affichée par la dernière commande doit être différente de celle de l’original. Votre session actuelle reste active, car le redémarrage de sshd ne ferme pas les connexions établies. Effectuez cette opération avant toute connexion au clone. Si vous attendez, chaque client qui faisait déjà confiance à la clé héritée reçoit WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! et doit d’abord exécuter ssh-keygen -R <host>.

Réinitialisez l’identifiant de la machine. /etc/machine-id est un identifiant unique que systemd génère une seule fois, au premier démarrage, et que le clone conserve.

sudo truncate -s 0 /etc/machine-id
sudo rm -f /var/lib/dbus/machine-id
sudo ln -s /etc/machine-id /var/lib/dbus/machine-id
sudo reboot

Un fichier /etc/machine-id vide indique à systemd de générer une nouvelle valeur au prochain démarrage. C’est pourquoi vous tronquez le fichier au lieu de le supprimer. Sa duplication provoque deux problèmes. Sur les images qui obtiennent leur adresse via DHCP, systemd-networkd dérive par défaut l’identifiant du client DHCP de l’identifiant de la machine. Les deux clones demandent donc un bail comme s’ils étaient le même client, et le serveur leur attribue la même adresse. De plus, journald associe chaque entrée à l’identifiant de la machine. Un collecteur de journaux centralisé classe donc les deux serveurs sous une seule machine. Exécutez cat /etc/machine-id après le redémarrage et vérifiez que la valeur a changé.

Modifiez le nom d’hôte.

sudo hostnamectl set-hostname web-02
grep 127.0.1.1 /etc/hosts

hostnamectl écrit /etc/hostname et applique immédiatement le nom. La commande ne modifie pas /etc/hosts. Modifiez donc la ligne 127.0.1.1 pour qu’elle corresponde. Sinon, le nouveau nom ne sera résolu nulle part. Chaque appel à sudo attendra l’échec de la résolution et affichera sudo: unable to resolve host web-02: Name or service not known.

Faites tourner tous les identifiants intégrés à l’image. Le clone contient les secrets de l’original. Deux machines peuvent donc désormais agir comme l’original. Vérifiez les fichiers authorized_keys SSH, les tokens d’API du fournisseur et du DNS, les fichiers .env des applications, les mots de passe des bases de données, les clés privées TLS, les tokens d’inscription de la supervision et le mot de passe du dépôt restic. Cette commande en trouve la plupart :

sudo grep -rIlE 'PASSWORD|SECRET|TOKEN|API_KEY' /etc /srv /opt /home 2>/dev/null
sudo find / -name '.env' -not -path '/proc/*' -not -path '/sys/*' 2>/dev/null

Si le clone est une copie de test qui ne servira jamais de trafic, révoquez les identifiants au lieu de les faire tourner. Un serveur de staging qui contient un token d’API de production actif est un serveur de production moins bien mis à jour.

Désactivez les tâches qui s’exécutent maintenant en double. Deux serveurs utilisant le même crontab sollicitent les mêmes systèmes externes à la même minute.

systemctl list-timers --all
sudo crontab -l
sudo ls -l /etc/cron.d /etc/cron.daily

Le cas de restic mérite une explication, car il altère votre politique de rétention au lieu d’échouer simplement. restic associe le nom d’hôte à chaque snapshot, et restic forget --keep-daily 7 applique sa politique par hôte. Deux machines qui indiquent le même nom d’hôte sont traitées comme un seul hôte. Les sept snapshots « quotidiens » peuvent donc tous provenir du clone, tandis que les snapshots de l’original sont supprimés. Corrigez le nom d’hôte avant la première sauvegarde ou arrêtez le timer sur le clone. Le cas de certbot est plus simple : deux serveurs qui renouvellent les mêmes noms atteignent la limite de certificats en double de l’autorité de certification. L’exécution perdante échoue avec une erreur indiquant que trop de certificats ont déjà été émis pour cet ensemble précis de noms. Un clone dont le domaine pointe encore vers l’original ne peut de toute façon pas réussir un challenge HTTP. Désactivez donc le renouvellement sur ce clone.

Traitez le cas de l’agent de supervision. La plupart des agents s’identifient avec le nom d’hôte ou avec un fichier d’ID écrit lors de l’installation. Deux agents signalés comme un seul hôte mélangent donc leurs métriques dans une série unique. Les graphiques CPU affichent alors des valeurs produites par aucune machine réelle, et les alertes deviennent instables. Arrêtez et supprimez l’agent du clone, ou inscrivez-le de nouveau sous le nouveau nom d’hôte en suivant la procédure documentée par votre fournisseur.

Vérifiez la configuration réseau qui contient l’adresse de l’original. Si l’image contient une adresse statique dans netplan, le clone revendique une adresse IP appartenant à une autre machine.

ip -br addr
sudo grep -r addresses /etc/netplan/

Supprimez l’état de cloud-init si ce clone devient un template.

sudo cloud-init clean --logs

Cette opération supprime l’état de cloud-init sous /var/lib/cloud. Au démarrage suivant, les modules du premier démarrage s’exécutent de nouveau, notamment la génération des clés d’hôte SSH lorsqu’aucune clé n’est présente. Certaines versions proposent également un flag pour réinitialiser l’identifiant de la machine. Exécutez cloud-init clean --help sur votre propre image pour voir ce qu’elle prend en charge, au lieu de vous fier à une liste de flags trouvée ailleurs.

Quand utiliser quelle méthode

Annuler une mise à niveau risquée : prenez un snapshot. Prenez-le quelques minutes avant la modification, effectuez la mise à niveau, puis restaurez l’image en cas de problème. La restauration supprime toutes les écritures effectuées depuis le snapshot. Sur un serveur qui reçoit du trafic en production, faites donc d’abord un dump de la base de données et déterminez précisément quelle fenêtre de données vous pourriez perdre. Pour un do-release-upgrade sur une machine que vous pouvez mettre hors ligne pendant dix minutes, le snapshot suffit à lui seul.

Migrer vers une offre plus grande : déployez un clone. Créez le clone à partir d’un snapshot sur l’offre la plus grande, vérifiez les éléments d’identité listés plus haut, puis testez-le sur sa propre adresse IP avant de déplacer le moindre trafic. Réduisez le TTL DNS un jour à l’avance pour accélérer la bascule, et laissez l’original fonctionner jusqu’à ce que la nouvelle machine ait reçu du trafic réel. Vérifiez d’abord que l’offre la plus grande est réellement plus rapide pour votre charge de travail, en utilisant la même méthode de benchmark sur les deux serveurs, car un plus grand nombre de vCPU sur un matériel plus sollicité ne constitue pas toujours une mise à niveau.

Créer un template : prenez un snapshot d’une machine nettoyée. Installez et sécurisez un serveur, puis supprimez tout ce qui lui est propre avant de créer son image. Supprimez les host keys, videz le machine ID, retirez tout authorized_keys personnel et tous les identifiants, puis nettoyez cloud-init. Prenez ensuite le snapshot. Chaque instance déployée à partir de cette image génère sa propre identité lors du premier démarrage. La liste de contrôle ci-dessus n’est donc plus nécessaire. Associez-la à la procédure standard des dix premières minutes sur un nouveau VPS afin que le template contienne déjà les opérations que vous devriez sinon répéter.

FAQ

Un instantané VPS est-il une sauvegarde ?

Non, car il partage le même domaine de panne que le serveur dont il provient. L’instantané est stocké chez votre fournisseur, dans votre compte, généralement dans la même région. Une suspension du compte, le vol d’une clé API ou la suppression accidentelle de l’instance peuvent supprimer le serveur et ses instantanés en une seule action. Chez de nombreux fournisseurs, la suppression d’une instance supprime également ses instantanés par conception. Un instantané est le moyen de rollback le plus rapide dont vous disposez. Continuez donc à en créer et conservez une seconde copie chiffrée sur une infrastructure que votre fournisseur ne contrôle pas.

Dois-je arrêter ma base de données avant de créer un instantané ?

Pas toujours, mais vous devez accepter le résultat obtenu. Un instantané créé par un fournisseur est cohérent après incident, ce qui signifie que l’image correspond à l’état qu’aurait eu le disque après une coupure de courant. PostgreSQL et InnoDB récupèrent cet état au démarrage, et PostgreSQL journalise database system was not properly shut down; automatic recovery in progress pendant cette récupération. La récupération n’est pas garantie lorsque vos données s’étendent sur deux volumes capturés à des instants différents, ou lorsqu’une application écrit sans fsync. Écrivez d’abord un pg_dumpall ou un mysqldump --single-transaction sur le disque, afin que l’image contienne un fichier dont vous savez qu’il est cohérent.

Pourquoi deux serveurs clonés entrent-ils en conflit pour la même adresse IP ?

Parce qu’ils partagent /etc/machine-id. Sur les images qui utilisent DHCP, systemd-networkd construit par défaut l’identifiant de son client DHCP à partir de l’identifiant de machine. Les deux clones demandent donc un bail avec le même identifiant, et le serveur DHCP attribue la même adresse aux deux. Tronquez /etc/machine-id à zéro octet, supprimez /var/lib/dbus/machine-id, recréez le lien symbolique vers /etc/machine-id, puis redémarrez afin que systemd génère une nouvelle valeur. L’autre cause fréquente est une adresse statique inscrite dans /etc/netplan/, que le clone a copiée telle quelle. Vérifiez avec ip -br addr.

Quel est le moyen le plus rapide de vérifier qu’un clone peut être mis en production sans risque ?

Comparez quatre éléments avec le serveur d’origine. Exécutez ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub sur les deux serveurs et vérifiez que les empreintes diffèrent. Exécutez cat /etc/machine-id sur les deux serveurs et vérifiez que les valeurs diffèrent. Exécutez hostnamectl status et vérifiez que le nom est nouveau et qu’il se résout, afin que sudo n’affiche aucun avertissement. Exécutez ensuite systemctl list-timers --all et arrêtez chaque timer qui communique avec un système partagé, comme les sauvegardes, le renouvellement des certificats ou un agent de supervision, jusqu’à ce que vous ayez déterminé quelle machine exécute cette tâche.