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

Migrer un serveur vers un nouveau VPS

Suivez une bascule répétée : inventaire, reconstruction, dump de la base, baisse du TTL DNS, vérification par IP et changement DNS sans précipitation.

Migrer un serveur vers un nouveau VPS avec une bascule répétée

Pour migrer un serveur vers un nouveau VPS, traitez l’opération comme une bascule répétée, et non comme une simple copie. Installez le nouveau serveur à partir de zéro, synchronisez les données deux fois, vérifiez que le nouveau serveur fonctionne avec sa propre adresse IP avant de modifier le DNS, puis basculez les enregistrements et laissez l’ancien serveur fonctionner jusqu’à ce que vous ayez toutes les garanties nécessaires. Copier les données est la partie la plus simple. L’ordre des opérations détermine si la migration se déroule sans incident ou entraîne des coûts importants.

Ce guide porte sur un serveur Linux qui exécute une application web, une base de données et un certificat TLS (Transport Layer Security). Cela couvre la plupart des configurations sur serveur unique. Deux hôtes sont concernés ; chaque exemple indique donc en commentaire sur quel hôte il doit être exécuté. Les adresses proviennent des plages réservées à la documentation : 198.51.100.10 est l’ancien serveur et 203.0.113.20 le nouveau.

Lisez toute la procédure avant de commencer. La première étape, réduire le TTL du DNS, doit être effectuée plusieurs jours avant l’étape qui vous intéresse réellement.

Faites l’inventaire avant toute construction

Vous ne pouvez pas reconstruire un serveur que vous n’avez pas décrit. Prenez une heure pour noter le rôle de l’ancien serveur, car ce qui casse après une migration est toujours ce dont personne ne se souvenait : une tâche cron, une exception du pare-feu ou un fichier d’environnement situé en dehors du répertoire de l’application.

Exécutez ces commandes sur l’ancien serveur et conservez la sortie dans un emplacement accessible depuis le nouveau.

# old server: packages you asked for, not the dependencies they pulled in
apt-mark showmanual > ~/inv-packages.txt

# old server: what runs now, and what starts at boot
systemctl list-units --type=service --state=running --no-pager > ~/inv-services.txt
systemctl list-unit-files --state=enabled --no-pager >> ~/inv-services.txt
systemctl list-timers --all --no-pager > ~/inv-timers.txt

# old server: what is listening, on which address and port
sudo ss -tulpn > ~/inv-ports.txt

# old server: human accounts, skipping the system ones
awk -F: '$3 >= 1000 && $3 < 65534 {print $1, $3, $6, $7}' /etc/passwd

apt-mark showmanual est la liste qu’il faut conserver, car elle inclut tout ce qui a été installé comme dépendance. Un dpkg --get-selections complet sur un serveur vieux de cinq ans renvoie deux mille lignes et ne vous apprend rien sur l’intention.

Les tâches planifiées se trouvent à deux endroits. Vérifiez donc les deux. Une tâche qui ne s’exécute qu’une fois par mois est celle que vous découvrirez six semaines après la migration.

# old server: per-user crontabs, then the system drop-ins
for u in $(cut -d: -f1 /etc/passwd); do sudo crontab -lu "$u" 2>/dev/null | sed "s/^/$u: /"; done
sudo ls -la /etc/cron.d /etc/cron.daily /etc/cron.hourly

Vérifiez ensuite les éléments qui ne sont pas des fichiers ordinaires : les règles du pare-feu, les certificats, les bases de données et le volume réel de données à déplacer.

# old server
sudo ufw status verbose        # or: sudo nft list ruleset
sudo certbot certificates
sudo -u postgres psql -c '\l'  # or: sudo mysql -e 'SHOW DATABASES;'
sudo du -xh --max-depth=1 / | sort -h

certbot certificates affiche le nom de chaque certificat, les domaines qu’il couvre, sa date d’expiration et les chemins des fichiers sur le disque. Cette sortie constitue votre checklist TLS. du -x reste sur un seul système de fichiers. Il n’explorera donc pas un volume de sauvegarde monté et ne renverra pas un nombre dix fois trop élevé.

Deux éléments se trouvent à l’extérieur du serveur et sont oubliés à chaque fois. Premièrement, les services tiers qui autorisent l’adresse IP de votre serveur dans une allowlist : une passerelle de paiement, une base de données gérée, un relais SMTP ou une API partenaire. Le nouveau serveur possède une nouvelle adresse. Vous devez donc y ajouter la nouvelle IP avant la bascule, et non après. Deuxièmement, les enregistrements DNS que vous n’avez pas créés vous-même, par exemple un enregistrement MX ou un enregistrement SPF qui mentionne encore l’ancienne IP.

Pourquoi reconstruire plutôt que cloner l’ancien système de fichiers root

Cloner tout le système de fichiers root sur le nouveau VPS semble plus rapide. C’est le cas, jusqu’à ce que ce ne le soit plus. Un système de fichiers root qui est resté en production pendant des années contient des configurations modifiées manuellement que personne n’a documentées, des paquets provenant d’un dépôt qui n’existe plus et une configuration de démarrage conçue pour le matériel virtuel de l’ancienne plateforme. Vous importez tout, y compris la raison de la migration.

La reconstruction est plus lente le premier jour, mais elle coûte moins cher chaque jour suivant. Vous installez la version actuelle, appliquez votre base de hardening, puis copiez uniquement les données : le répertoire de l’application, les configurations des sites, le dump de la base de données, les certificats et les uploads des utilisateurs. Tout ce que vous ne pouvez pas expliquer reste sur l’ancien serveur. Commencez sur le nouveau serveur comme vous le feriez sur n’importe quel serveur, avec les dix premières minutes sur un nouveau VPS, puis ajoutez les services de l’inventaire un par un et vérifiez chacun avant de passer au suivant.

Quand une restauration d’image ou de snapshot est la bonne solution

Il existe une exception claire à la reconstruction. Si l’ancien serveur ne démarre plus, ou si l’application ne peut plus être reconstruite à partir de son code source, la restauration d’une image ou d’un snapshot fourni par l’hébergeur est la solution pragmatique. Elle a toutefois des limites réelles : elle fonctionne au sein d’un même hébergeur, souvent uniquement dans une même famille d’offres, car le disque restauré attend les périphériques virtuels et la nomenclature réseau de cette plateforme.

Un snapshot d’un serveur en fonctionnement présente également le même problème de cohérence qu’une copie au niveau des fichiers d’une base de données active. Considérez la restauration d’image comme une méthode de récupération, et non comme un plan de migration. Lisez pourquoi un snapshot n’est pas la même chose qu’une sauvegarde avant de construire un plan autour de cette méthode.

Comment les fichiers sont transférés : rsync via SSH

Exécutez rsync depuis l’ancien serveur en envoyant les données vers le nouveau. L’envoi est généralement plus simple, car l’ancien serveur contient déjà les données et peut toutes les lire avec sudo.

# old server: dry run first, and read what it says it will do
sudo rsync -aHAX --dry-run --itemize-changes \
  -e 'ssh -i /root/.ssh/id_ed25519' \
  /srv/app/ deploy@203.0.113.20:/srv/app/

# old server: the real bulk pass
sudo rsync -aHAX --info=progress2 \
  -e 'ssh -i /root/.ssh/id_ed25519' \
  /srv/app/ deploy@203.0.113.20:/srv/app/

Les options sont importantes. -a conserve les permissions, les horodatages, les liens symboliques et le propriétaire. -H conserve les liens physiques en tant que tels au lieu de les développer en copies distinctes. -A copie les ACL POSIX (listes de contrôle d’accès) et -X copie les attributs étendus. Sans ces deux dernières options, un fichier qui semble identique peut se comporter différemment, car les labels SELinux et les ACL sont stockés dans les attributs étendus et rien d’autre ne les conserve.

Deux détails sont à l’origine de la plupart des échecs.

Le slash final détermine où les données sont placées. /srv/app/ désigne le contenu de ce répertoire. /srv/app désigne le répertoire lui-même. Si vous vous trompez, vous obtenez /srv/app/app sur le nouveau serveur. L’application démarre ensuite, puis signale des fichiers manquants, car les chemins configurés pointent désormais un niveau trop haut.

Avec sudo, le tilde désigne le répertoire personnel de root. Écrire -e 'ssh -i ~/.ssh/id_ed25519' dans un sudo rsync recherche la clé dans /root/.ssh, et non dans votre propre répertoire personnel. Si la clé ne s’y trouve pas, SSH affiche Permission denied (publickey), rsync affiche rsync: connection unexpectedly closed et se termine avec un code différent de zéro. Indiquez le chemin complet de la clé. Si ce message d’authentification continue de s’afficher après la correction du chemin, l’échec publickey a une courte liste de causes et les permissions des répertoires sur le nouveau serveur sont le prochain point à vérifier.

Pour les propriétaires, vous devez prendre une décision. Lorsqu’il s’exécute en tant que root, rsync fait correspondre par défaut le propriétaire et le groupe selon leur nom. Un fichier appartenant à www-data sur l’ancien serveur appartient donc à www-data sur le nouveau serveur, même si l’UID (identifiant utilisateur) numérique est différent. C’est le comportement souhaité pour une reconstruction. Ajoutez --numeric-ids uniquement si vous copiez un système de fichiers dont les comptes n’existent pas sur la cible. Vérifiez ensuite le résultat avec ls -ln, car un fichier appartenant à un UID sans compte correspondant s’affiche sous la forme d’un simple nombre et chaque service qui le lit se voit refuser l’accès.

Effectuez la copie initiale plusieurs jours à l’avance, pendant que l’ancien serveur continue de servir le trafic. Répétez-la aussi souvent que nécessaire : rsync n’envoie que les modifications, donc la deuxième passe prend quelques minutes au lieu de plusieurs heures. Lors de la passe finale, pendant la fenêtre de bascule, ajoutez --delete afin que les fichiers supprimés sur l’ancien serveur soient également supprimés sur le nouveau.

# old server: final pass, inside the window, after the app has stopped writing
sudo rsync -aHAX --delete --info=progress2 \
  -e 'ssh -i /root/.ssh/id_ed25519' \
  /srv/app/ deploy@203.0.113.20:/srv/app/

--delete supprime sur la destination les fichiers qui n’existent plus dans la source. Un chemin source incorrect associé à --delete peut donc vider le répertoire de destination. Exécutez d’abord la commande avec --dry-run, à chaque fois. Les transferts longs échouent également lorsque la session SSH de votre ordinateur portable est interrompue. Lancez-les donc dans tmux ou screen sur l’ancien serveur. Ajoutez --bwlimit=20M si la copie sature la liaison alors que l’ancien serveur sert encore les utilisateurs.

Déplacement de la base de données : un dump natif

Une base de données n’est pas un répertoire de fichiers, même si elle y ressemble. Elle se compose de fichiers, d’un état en mémoire et d’un write-ahead log. Elle n’est cohérente qu’aux instants définis par le système de base de données lui-même. Utilisez son outil dédié.

PostgreSQL nécessite deux dumps, car les rôles sont définis au niveau du cluster et pg_dump ne les inclut pas :

# old server
sudo -u postgres pg_dumpall --globals-only -f /var/backups/globals.sql
sudo -u postgres pg_dump -Fc -f /var/backups/appdb.dump appdb
# new server: restore in this order
sudo -u postgres psql -f /var/backups/globals.sql
sudo -u postgres createdb -O appuser appdb
sudo -u postgres pg_restore -d appdb --no-owner /var/backups/appdb.dump

Si vous ignorez globals.sql, toutes les tables sont restaurées, mais aucun rôle applicatif ne peut les lire, car les instructions GRANT font référence à un utilisateur inexistant. -Fc écrit l’archive au format custom. Seul pg_restore peut la lire, et ce format permet de restaurer ultérieurement certaines tables. Restaurez la base dans la même version majeure ou dans une version plus récente. La restauration vers une version antérieure, par exemple de 17 vers 16, n’est pas prise en charge. pg_restore rejette l’archive avec une erreur de version non prise en charge dans l’en-tête du fichier, avant d’écrire quoi que ce soit.

MySQL et MariaDB utilisent une seule commande, avec quatre options qui ne sont pas activées par défaut :

# old server
sudo mysqldump --single-transaction --routines --triggers --events \
  --databases appdb > /var/backups/appdb.sql
# new server
sudo mysql < /var/backups/appdb.sql

--single-transaction prend un snapshot cohérent sans bloquer les écritures, mais uniquement pour les tables InnoDB. Une table MyISAM dans la même base de données est copiée sans cette garantie. Vérifiez donc vos storage engines avant de faire confiance au dump. --routines, --triggers et --events sont désactivées par défaut. Un dump standard restaure donc vos données, mais laisse silencieusement de côté vos stored procedures et vos scheduled events. Les utilisateurs de la base de données et leurs grants résident dans la base système mysql. Un dump --databases appdb ne la sauvegarde jamais. Recréez-les donc sur le nouveau serveur avec CREATE USER et GRANT. MariaDB 11 fournit le même outil sous le nom mariadb-dump et conserve mysqldump comme lien symbolique. Les deux noms fonctionnent donc en août 2026.

SQLite tient dans un fichier unique. Le copier pendant que l’application écrit produit un fichier incohérent. Utilisez sa méthode sûre :

# old server
sqlite3 /var/lib/app/app.db ".backup '/var/backups/app.db'"

Quel que soit le moteur, vérifiez le dump avant de lui faire confiance. Un dump interrompu parce que le disque est plein sera restauré sans erreur, jusqu’au point exact où il a été tronqué.

# old server: a complete mysqldump ends with a line reading "-- Dump completed on ..."
tail -n 3 /var/backups/appdb.sql

# new server: after restore, count rows in a table whose size you know
sudo mysql -e 'SELECT COUNT(*) FROM appdb.orders;'

Pourquoi vous ne pouvez pas utiliser rsync avec une base de données en fonctionnement

rsync copie les fichiers un par un. Une base de données en fonctionnement écrit simultanément dans plusieurs fichiers. Lorsque rsync atteint le dernier fichier, le premier n’est donc déjà plus à jour. La copie contient des pages correspondant à des instants différents. La base de données n’a jamais été dans cet état. Le résultat est soit un serveur qui refuse de démarrer, soit, dans le pire des cas, un serveur qui démarre, fournit des réponses correctes pendant une semaine, puis échoue lorsqu’une requête atteint enfin la page endommagée. Aucun avertissement n’apparaît entre-temps.

Il existe deux méthodes sûres pour déplacer les fichiers eux-mêmes. Arrêtez la base de données, copiez les fichiers, puis redémarrez-la : c’est correct et simple, mais l’interruption de service dure le temps de la copie. Vous pouvez aussi utiliser l’outil conçu pour effectuer une copie physique d’un serveur en fonctionnement. Pour PostgreSQL, il s’agit de pg_basebackup. Cet outil se coordonne avec le serveur afin de garantir la cohérence de la copie :

# new server: pull a physical copy from the old one
pg_basebackup -h 198.51.100.10 -U replicator -D /var/lib/postgresql/16/main -X stream -P

Cette méthode nécessite un rôle doté de l’attribut REPLICATION et une entrée pg_hba.conf correspondante sur l’ancien serveur. Sa configuration est donc plus complexe que celle d’un dump. Elle est utile lorsque la base de données est suffisamment volumineuse pour qu’un dump et une restauration ne tiennent pas dans la fenêtre de maintenance. Pour une migration classique entre serveurs uniques, le dump reste préférable.

Recréez les certificats avant la bascule, pas après

Un certificat TLS est lié au nom de domaine, et non à l’adresse IP. Le fichier de certificat lui-même peut donc être transféré sans difficulté. Le renouvellement, en revanche, ne se transfère pas correctement. Le challenge HTTP-01 par défaut de Certbot demande à l’autorité de certification de récupérer un fichier sur le port 80, au nom de domaine certifié. Tant que le DNS pointe vers l’ancien serveur, cette requête y aboutit et le renouvellement échoue sur le nouveau serveur.

La première option consiste à copier les certificats existants ainsi que leur état de renouvellement. Ils restent valides jusqu’à leur date d’expiration, quel que soit le serveur qui les détient.

# old server
sudo rsync -aHAX -e 'ssh -i /root/.ssh/id_ed25519' \
  /etc/letsencrypt/ root@203.0.113.20:/etc/letsencrypt/

Chaque fichier dans /etc/letsencrypt/renewal/ indique le plugin d’authentification qui a émis le certificat. Installez donc le même plugin sur le nouveau serveur (python3-certbot-nginx, par exemple), sinon le premier renouvellement échouera avec un message indiquant qu’un authentificateur est inconnu. Vérifiez que le renouvellement fonctionne avant de vous y fier :

# new server, after DNS has moved
sudo certbot renew --dry-run

La deuxième option consiste à émettre un nouveau certificat sur le nouveau serveur avec le challenge DNS-01. Celui-ci prouve que vous contrôlez le domaine au moyen d’un enregistrement TXT et n’utilise jamais le port 80. Cette méthode fonctionne avant la migration, tant que le nom se résout encore vers l’ancien serveur. C’est donc le choix le plus simple si vous pouvez automatiser votre fournisseur DNS. Émettre des certificats avec le challenge DNS-01 décrit la configuration du plugin et des identifiants.

Dans les deux cas, vérifiez ce que le nouveau serveur présente réellement, sans modifier le DNS :

# your laptop
echo | openssl s_client -connect 203.0.113.20:443 -servername example.com 2>/dev/null \
  | openssl x509 -noout -subject -dates -issuer

-servername envoie le SNI (indication du nom du serveur), ce qui permet au serveur web de sélectionner le bon virtual host. Si vous l’omettez, vous obtenez le certificat par défaut associé à cette IP et une erreur de correspondance qui ressemble à un vrai problème, mais qui n’en est pas un.

Réduisez le TTL DNS plusieurs jours avant la bascule

Le DNS est souvent la cause d’un échec lors d’une migration pourtant bien préparée, car le délai est inhérent au fonctionnement du cache et vous ne pouvez pas le réduire le jour de la bascule. Un resolver qui a mis en cache votre enregistrement A continue de le servir pendant toute la durée du TTL (time to live) qu’il a reçu. Réduire le TTL maintenant ne change rien pour un resolver qui a mis l’enregistrement en cache il y a dix minutes avec l’ancienne valeur : il conserve cette valeur pendant le reste de l’ancien TTL, puis apprend seulement ensuite la nouvelle valeur, plus courte. Réduisez donc le TTL au moins une période complète correspondant à l’ancien TTL avant la bascule. Une journée à l’avance est la solution confortable. Si ces mécanismes sont nouveaux pour vous, la présentation des enregistrements, des resolvers et de la mise en cache fournit le contexte nécessaire.

Les valeurs ci-dessous sont calculées à partir du TTL lui-même, et non mesurées.

ChartHow long a stale IP can survive, by record TTL
The data behind this chart
[
  {
    "label": "TTL 3600 s (common default)",
    "ttl_seconds": 3600,
    "worst_case_stale_minutes": 60
  },
  {
    "label": "TTL 900 s",
    "ttl_seconds": 900,
    "worst_case_stale_minutes": 15
  },
  {
    "label": "TTL 300 s (lowered for cutover)",
    "ttl_seconds": 300,
    "worst_case_stale_minutes": 5
  },
  {
    "label": "TTL 60 s (short window)",
    "ttl_seconds": 60,
    "worst_case_stale_minutes": 1
  }
]

Un enregistrement A publié avec un TTL de 3600 secondes peut continuer à envoyer les utilisateurs vers l’ancienne adresse IP pendant 60 minutes après sa modification. Réduisez-le à 300 secondes pour ramener ce délai maximal à 5 minutes. Considérez ces valeurs comme un minimum, et non comme une garantie. Certains resolvers imposent leur propre TTL minimum et ignorent les valeurs plus courtes. Certains runtimes d’application mettent aussi une adresse résolue en cache pendant toute la durée de vie du processus. Un client démarré avant votre modification peut donc ne plus effectuer de nouvelle résolution avant son redémarrage.

Consultez la réponse faisant autorité, et non votre propre cache, pour vérifier que la réduction du TTL est active :

# your laptop: ask the zone's own nameserver, so no cache is involved
dig +short NS example.com
dig +noall +answer @$(dig +short NS example.com | head -n1) example.com A

Le deuxième champ de cette ligne de réponse est le TTL en secondes. Vérifiez ensuite les enregistrements souvent oubliés : l’enregistrement AAAA si l’ancien serveur utilisait IPv6, le nom www lorsqu’il s’agit d’un enregistrement A distinct et non d’un CNAME, tout enregistrement MX pointant vers le serveur lui-même, un enregistrement SPF qui contient l’ancienne adresse IP, ainsi que l’enregistrement DNS inverse (PTR) de la nouvelle adresse. Configurez le PTR dans le panneau de contrôle de votre provider avant la bascule si le serveur envoie des e-mails, car les serveurs de réception vérifient cet enregistrement et un PTR manquant peut entraîner le rejet des e-mails plusieurs heures après que tout le reste semble fonctionner.

Vérifiez le nouveau serveur sur son adresse IP avant de modifier le DNS

Vous pouvez tester l’application complète sur le nouveau serveur pendant que le DNS pointe encore vers l’ancien. Remplacez la résolution de nom pour une requête :

# your laptop: force one name to the new IP, for this request only
curl -sS --resolve example.com:443:203.0.113.20 \
  -o /dev/null -w '%{http_code} %{ssl_verify_result}\n' https://example.com/

--resolve modifie uniquement la destination de la connexion. Le certificat TLS est toujours vérifié avec le vrai nom. Cette commande valide donc le certificat et le service. %{ssl_verify_result} affiche 0 lorsque la chaîne de certificats est valide.

Pour parcourir le site dans un navigateur, remplacez la résolution de nom sur toute votre machine en ajoutant une ligne à /etc/hosts sur votre ordinateur portable, ou à C:\Windows\System32\drivers\etc\hosts sous Windows :

203.0.113.20 example.com www.example.com

Parcourez ensuite l’application comme le ferait un utilisateur. Connectez-vous. Chargez une page qui lit des données dans la base de données. Envoyez un formulaire qui écrit dans la base de données. Téléversez un fichier et vérifiez qu’il est bien écrit sur le disque. Déclenchez l’envoi d’un e-mail et vérifiez qu’il arrive, car le SMTP sortant depuis une nouvelle adresse IP réserve souvent une surprise. Supprimez la ligne dans le fichier hosts dès que vous avez terminé. Si vous la laissez en place, vous risquez de passer une heure à déboguer un site que tous les autres utilisateurs voient parfaitement.

Le basculement, étape par étape

  1. Quelques jours avant : réduisez le TTL, exécutez le rsync initial, préparez le nouveau serveur et testez-le avec une surcharge du fichier hosts.
  2. Le jour J, avant l’intervention : ajoutez la nouvelle IP à toutes les allowlists de services tiers, puis vérifiez que la tâche de sauvegarde du nouveau serveur est configurée et pointe vers votre dépôt.
  3. Au début de l’intervention : activez le mode maintenance de l’application sur l’ancien serveur afin qu’il cesse d’accepter les écritures.
  4. Effectuez le dump final de la base de données, puis exécutez le dernier passage de rsync avec --delete.
  5. Restaurez le dump sur le nouveau serveur et démarrez les services.
  6. Testez de nouveau via --resolve et la surcharge du fichier hosts, en effectuant notamment une écriture réelle.
  7. Modifiez les enregistrements A et AAAA pour les faire pointer vers la nouvelle IP.
  8. Surveillez les deux serveurs. Le journal d’accès de l’ancien serveur indique qui s’y connecte encore, et ce nombre devrait diminuer jusqu’à zéro pendant la durée du TTL.
  9. Désactivez la page de maintenance.
  10. Laissez l’ancien serveur en fonctionnement sans le modifier pendant au moins une semaine.

L’étape du mode maintenance est celle que certains ignorent, alors que c’est elle qui vous protège. Une fois qu’une écriture a été acceptée par la nouvelle base de données, revenir en arrière signifie soit perdre cette écriture, soit exporter la nouvelle base de données et la recharger dans l’ancienne. Une fenêtre en lecture seule de quelques minutes ne coûte presque rien. Deux bases de données ayant toutes les deux accepté des écritures nécessitent plusieurs jours de rapprochement manuel.

Le plan de rollback

Le rollback consiste en une seule action : rétablir les enregistrements DNS sur 198.51.100.10. Cela ne fonctionne que grâce à quatre mesures prises précédemment.

  • L’ancien serveur fonctionne toujours, avec ses services actifs et ses données intactes. Vous y avez arrêté les écritures, mais vous ne l’avez pas mis hors service.
  • Le TTL reste faible. Le retour en arrière est donc aussi rapide que le basculement initial.
  • Vous avez ajouté la nouvelle IP aux listes d’autorisation des services tiers au lieu de remplacer l’ancienne. Si vous supprimez l’ancienne adresse, le rollback échoue au niveau de la passerelle de paiement.
  • Le nouveau serveur n’a reçu aucune écriture impossible à identifier, car les seules écritures effectuées jusqu’à présent sont vos propres transactions de test.

Définissez avant le début de la fenêtre ce qui déclenche un rollback. Deux déclencheurs suffisent : toute erreur que vous ne pouvez pas diagnostiquer dans un délai défini, et toute perte de données, même minime. Les noter à l’avance évite de passer une heure à chercher la cause et de transformer une interruption de dix minutes en longue indisponibilité.

Prouvez que la migration a réussi

Une migration n’est pas terminée lorsque le site se charge. Vérifiez les éléments qui échouent seulement plus tard.

# new server
systemctl --failed
journalctl -p err -b --no-pager | tail -n 40
sudo certbot certificates
sudo systemctl list-timers --all --no-pager

systemctl --failed reporting 0 loaded units listed est le résultat attendu. certbot certificates doit afficher les dates d’expiration attendues, et list-timers doit afficher chaque tâche planifiée de votre inventaire avec une prochaine exécution réelle, et non une valeur vide.

Redémarrez ensuite le nouveau serveur une fois, volontairement, pendant que vous le surveillez. Un service lancé manuellement et jamais activé fonctionne parfaitement jusqu’au premier redémarrage imprévu, à trois heures du matin.

# new server
sudo reboot

# your laptop, once it comes back
curl -sS -o /dev/null -w '%{http_code}\n' https://example.com/

Si l’application s’exécute dans des conteneurs, le même piège se présente différemment, car une stack Compose a besoin d’une politique de redémarrage explicite pour redémarrer après un reboot.

La dernière vérification est la plus facile à remettre à plus tard et la plus importante : la tâche de sauvegarde. Une migration qui se termine avec un serveur non sauvegardé remplace un risque par un autre. Exécutez manuellement la sauvegarde sur le nouveau serveur, puis restaurez un seul fichier depuis cette sauvegarde dans un répertoire temporaire. Un repository restic dont vous avez réellement testé la restauration est la solution utile lorsque vous en avez besoin. Si vous faites fonctionner les anciens et les nouveaux serveurs côte à côte pendant une semaine, une méthode cohérente pour accéder à chaque hôte et le configurer évite qu’ils divergent alors qu’ils sont tous les deux actifs.

Après la bascule : l’ancien serveur et les derniers éléments

Conservez l’ancien serveur pendant une à deux semaines. Cela vous coûte un mois d’une offre que vous alliez résilier, mais c’est votre seul mécanisme de rollback. Terminez ensuite les opérations restantes.

  • La réutilisation du même hostname dans votre ~/.ssh/config pour le nouveau serveur provoque un WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! lors de la première connexion, car ce nom renvoie désormais une autre host key. Supprimez l’entrée obsolète avec ssh-keygen -R example.com uniquement après avoir vérifié pourquoi elle a changé, et non par réflexe : le même avertissement peut signaler une attaque par interception. Une migration est également un bon moment pour vérifier quelles clés peuvent accéder à quelles ressources ; c’est l’objectif de la gestion des clés SSH dans un petit parc.
  • Effectuez un dernier snapshot ou une dernière sauvegarde de l’ancien serveur, puis stockez-la dans un emplacement qui ne dépend pas de l’ancien fournisseur.
  • Supprimez l’ancienne IP des contrôles de monitoring, des enregistrements SPF et des allowlists de services tiers, dans cet ordre et en dernier lieu.
  • Résiliez l’ancienne offre uniquement après avoir confirmé que cette dernière copie est lisible depuis un autre emplacement.

FAQ

Combien de temps faut-il pour migrer un serveur vers un nouveau VPS ?

L’interruption visible par les utilisateurs correspond généralement au dernier dump de la base de données, au dernier passage de rsync et au démarrage du service : comptez dix à trente minutes pour une petite application. La durée totale est plus longue, car il faut réduire le DNS TTL au moins une période correspondant à l’ancien TTL avant la bascule ; prévoir un jour d’avance est plus sûr. Planifiez également la copie initiale des données plusieurs jours à l’avance. Elle s’effectue sur un serveur en production, et une nouvelle exécution ne transfère ensuite que les données modifiées depuis le dernier passage.

Puis-je utiliser rsync sur une base de données MySQL ou PostgreSQL en fonctionnement au lieu de créer un dump ?

Non. rsync copie les fichiers un par un pendant que la base de données écrit simultanément dans plusieurs fichiers. La copie contient donc des pages correspondant à des instants différents et représente un état que la base de données n’a jamais eu. Elle peut refuser de démarrer, ou démarrer puis échouer lorsqu’une requête atteint une page endommagée. Utilisez pg_dump avec pg_dumpall --globals-only, ou mysqldump --single-transaction, ou arrêtez d’abord la base de données avant de copier les fichiers. Pour un cluster PostgreSQL volumineux, pg_basebackup crée une copie physique cohérente d’un serveur en fonctionnement.

Comment tester le nouveau VPS avant de modifier le DNS ?

Forcez la résolution du nom sur votre propre machine. Pour une seule requête, curl --resolve example.com:443:203.0.113.20 https://example.com/ envoie la connexion vers la nouvelle IP tout en vérifiant le certificat avec le véritable nom. Pour tester avec un navigateur, ajoutez 203.0.113.20 example.com à /etc/hosts sur votre ordinateur portable, testez une connexion, une lecture dans la base de données, l’envoi d’un formulaire et le téléversement d’un fichier, puis supprimez la ligne. Pour inspecter uniquement le certificat, exécutez openssl s_client -connect 203.0.113.20:443 -servername example.com.

Quel TTL dois-je définir et quand dois-je le réduire ?

Réduisez les enregistrements A et AAAA à 300 secondes, au moins une période complète correspondant à l’ancien TTL avant la bascule. Un resolver qui a mis l’enregistrement en cache avant votre modification conserve l’ancienne valeur pendant le reste de l’ancien TTL. Le réduire une heure à l’avance ne sert donc à rien si l’ancien TTL était de 86400. Rétablissez votre valeur habituelle quelques jours après la migration, lorsque le journal d’accès de l’ancien serveur ne contient plus de requêtes.

Dois-je copier le certificat TLS ou en créer un nouveau sur le nouveau serveur ?

Les deux solutions fonctionnent. Copier /etc/letsencrypt/ conserve la validité du certificat jusqu’à sa date d’expiration actuelle, mais vous devez installer le même plugin d’authentification certbot sur le nouveau serveur. Sinon, le premier renouvellement échoue. Exécutez donc certbot renew --dry-run après la bascule DNS pour vérifier. Créer un nouveau certificat est plus propre lorsque vous pouvez utiliser le challenge DNS-01, car celui-ci prouve le contrôle au moyen d’un enregistrement TXT et fonctionne avant que le DNS pointe vers le nouveau serveur. Le challenge HTTP-01 ne peut pas être utilisé sur le nouveau serveur avant la migration du DNS, car la requête de validation atteindrait l’ancien serveur.