SSD Nodes Learn 🎉 VPS vanaf $5.50/mnd
Gidsen Matt ConnorDoor Matt Connor

Server migreren naar een nieuwe VPS: stappenplan

Migreer uw server naar een nieuwe VPS met een gecontroleerde cutover. Leer hoe u DNS TTL tijdig verlaagt, data synchroniseert en de nieuwe omgeving valideert voor de definitieve switch.

Migratie van een server naar een nieuwe VPS als een geoefende cutover

Behandel de verhuizing van een server naar een nieuwe VPS als een geoefende cutover in plaats van een kopieeractie. Bouw de nieuwe server vanaf nul op, synchroniseer de data twee keer en controleer of de nieuwe server op zijn eigen IP-adres werkt voordat u DNS aanpast. Schakel daarna pas de records om en laat de oude server draaien totdat u zeker bent van de werking. Het kopiëren van de bytes is het eenvoudige gedeelte. De volgorde van de handelingen bepaalt of de verhuizing probleemloos verloopt of kostbaar wordt.

Deze handleiding behandelt één Linux-server waarop een webapplicatie, een database en een TLS (transport layer security) certificaat draaien. Dit dekt de meeste single-server opstellingen. Er zijn twee hosts betrokken, dus bij elk voorbeeld staat in een commentaar op welke host het wordt uitgevoerd. De adressen zijn afkomstig uit de documentatiereeksen: 198.51.100.10 is de oude server, 203.0.113.20 is de nieuwe.

Lees het volledige draaiboek door voordat u begint. De eerste stap, het verlagen van de DNS TTL, moet dagen voor de stap die u daadwerkelijk belangrijk vindt, worden uitgevoerd.

Maak een inventarisatie voordat u begint met bouwen

U kunt een server niet opnieuw opbouwen als u niet heeft beschreven wat deze doet. Besteed een uur aan het noteren van de taken van de oude server, want het onderdeel dat na een migratie kapotgaat, is altijd datgene wat niemand zich herinnerde: een cron job, een firewall-uitzondering of een omgevingsbestand dat buiten de applicatiemap staat.

Voer deze commando's uit op de oude server en bewaar de uitvoer op een plek waar u deze vanaf de nieuwe server kunt inzien.

# 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 is de lijst die u nodig heeft, omdat deze alle pakketten weglaat die als afhankelijkheid zijn geïnstalleerd. Een volledige dpkg --get-selections op een server van vijf jaar oud levert tweeduizend regels op en vertelt u niets over de bedoeling van de installatie.

Geplande taken verbergen zich op twee plekken, dus controleer beide. Een taak die slechts maandelijks wordt uitgevoerd, is de taak die u pas zes weken na de migratie zult ontdekken.

# 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

Kijk vervolgens naar de onderdelen die geen standaardbestanden zijn: firewallregels, certificaten, databases en de hoeveelheid data die u daadwerkelijk verplaatst.

# 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 toont de naam van elk certificaat, de domeinen die het dekt, de verloopdatum en de bestandspaden op de schijf. Die uitvoer is uw TLS-checklist. du -x blijft op één bestandssysteem, waardoor het niet per ongeluk een aangekoppeld back-upvolume meeneemt en een tien keer te groot getal rapporteert.

Twee zaken bevinden zich buiten de server en worden telkens vergeten. Ten eerste elke externe partij die het IP-adres van uw server op een allowlist heeft staan: een betaalprovider, een managed database, een SMTP-relay of een partner-API. De nieuwe server heeft een nieuw adres, dus die allowlists moeten vóór de overschakeling worden bijgewerkt met het nieuwe IP-adres, niet erna. Ten tweede DNS-records die u niet zelf heeft aangemaakt, zoals een MX-record of een SPF-record waarin het oude IP-adres in tekstvorm wordt genoemd.

Waarom u het root-bestandssysteem opnieuw opbouwt in plaats van het oude te klonen

Het klonen van een volledig root-bestandssysteem naar de nieuwe VPS lijkt sneller, en dat is het ook, totdat het dat niet meer is. Een root-bestandssysteem dat jarenlang in productie is geweest, bevat handmatig gewijzigde configuraties die niemand heeft gedocumenteerd, pakketten uit een repository die niet meer bestaat, en een boot-configuratie die is gebouwd voor de virtuele hardware van het oude platform. U importeert dit alles, inclusief de reden waarom u aan het migreren was.

Opnieuw opbouwen is op de eerste dag langzamer, maar daarna elke dag goedkoper. U installeert de huidige release, past uw basisbeveiliging toe en kopieert vervolgens alleen de data: de applicatiemap, de siteconfiguraties, de database-dump, de certificaten en de gebruikersuploads. Alles wat u niet kunt verklaren, verhuist niet mee. Start de nieuwe server zoals u elke server zou starten, met de eerste tien minuten op een nieuwe VPS, voeg daarna één voor één de services uit de inventaris toe en controleer elke service voordat u de volgende toevoegt.

Wanneer het herstellen van een image of snapshot de juiste keuze is

Er is één eerlijke uitzondering op het opnieuw opbouwen van een server. Als de oude server niet opstart, of als de applicatie er een is die niemand meer vanaf de broncode kan compileren, dan is het herstellen van een image of snapshot van de provider het pragmatische antwoord. Dit heeft duidelijke beperkingen: het werkt binnen één provider en vaak alleen binnen één type abonnement, omdat de herstelde schijf de virtuele apparaten en netwerknaamgeving van dat specifieke platform verwacht.

Een snapshot van een actieve server brengt bovendien hetzelfde consistentieprobleem met zich mee als elke andere kopie op bestandsniveau van een actieve database. Beschouw het herstellen van een image als een herstelmethode en niet als een migratieplan, en lees waarom een snapshot niet hetzelfde is als een backup voordat u hierop een plan baseert.

Hoe bestanden worden verplaatst: rsync over SSH

Voer rsync uit vanaf de oude server en push de data naar de nieuwe. Pushen is doorgaans eenvoudiger, omdat de oude server de data al bezit en deze volledig kan lezen onder 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/

De flags zijn van belang. -a behoudt rechten, tijdstempels, symbolische links en eigenaarschap. -H behoudt harde links als harde links in plaats van ze uit te breiden naar afzonderlijke kopieën. -A kopieert POSIX ACL's (access control lists) en -X kopieert uitgebreide attributen. Zonder deze laatste twee kan een bestand dat identiek lijkt, zich anders gedragen, omdat SELinux-labels en ACL's in uitgebreide attributen staan en nergens anders worden vastgelegd.

Twee details veroorzaken de meeste fouten in dit proces.

De afsluitende slash bepaalt waar de data terechtkomt. /srv/app/ betekent de inhoud van die map. /srv/app betekent de map zelf. Als u dit verkeerd doet, eindigt u met /srv/app/app op de nieuwe server; de applicatie start dan wel, maar meldt vervolgens ontbrekende bestanden omdat de geconfigureerde paden nu één niveau te ondiep zijn.

Onder sudo is de tilde de home-map van root. Het schrijven van -e 'ssh -i ~/.ssh/id_ed25519' binnen een sudo rsync zoekt naar de sleutel in /root/.ssh, niet in uw eigen home-map. Als de sleutel daar niet staat, toont SSH Permission denied (publickey), geeft rsync rsync: connection unexpectedly closed weer en sluit af met een non-zero exitcode. Schrijf het pad naar de sleutel volledig uit. Als die authenticatiemelding blijft verschijnen nadat u het pad heeft gecorrigeerd, dan heeft de publickey-fout een korte lijst met oorzaken en zijn de maprechten op de nieuwe server het volgende punt om te controleren.

Eigenaarschap vereist één beslissing. Wanneer u rsync als root uitvoert, koppelt het standaard eigenaar en groep op naam. Een bestand dat eigendom is van www-data op de oude server, wordt dus eigendom van www-data op de nieuwe server, zelfs als de numerieke UID (user ID) verschilt. Dit is wat u wilt bij een herbouw. Voeg --numeric-ids alleen toe wanneer u een bestandssysteem kopieert waarvan de accounts niet bestaan op de doelserver. Controleer het resultaat daarna met ls -ln, omdat een bestand dat eigendom is van een UID zonder bijbehorend account als een kaal nummer wordt weergegeven en elke service die het probeert te lezen, wordt geweigerd.

Voer de bulk-kopie dagen van tevoren uit, terwijl de oude server nog verkeer afhandelt. Herhaal dit zo vaak als u wilt: rsync verstuurt alleen wat is gewijzigd, waardoor de tweede run minuten duurt in plaats van uren. De laatste run, binnen het cutover-venster, voegt --delete toe zodat bestanden die op de oude server zijn verwijderd, ook op de nieuwe server verdwijnen.

# 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 verwijdert bestanden op de bestemming die niet meer op de bron staan. Een verkeerd bronpad in combinatie met --delete maakt dus de doelmap leeg. Voer het daarom elke keer eerst uit met --dry-run. Lange overdrachten stoppen ook wanneer de SSH-sessie van uw laptop wegvalt; start ze daarom binnen tmux of screen op de oude server. Voeg --bwlimit=20M toe als de kopie de verbinding verzadigt terwijl de oude server nog gebruikers bedient.

Hoe de database verhuist: een native dump

Een database is geen map met bestanden, ook al lijkt dat wel zo. Het is een verzameling bestanden plus een in-memory status en een write-ahead log, die alleen consistent zijn op de momenten die de database zelf definieert. Gebruik daarom de eigen tool van de database.

PostgreSQL vereist twee dumps, omdat rollen clusterbreed zijn en pg_dump deze niet bevat:

# 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

Slaat u globals.sql over, dan worden alle tabellen hersteld, maar kan geen enkele applicatierol ze lezen, omdat de GRANT-statements verwijzen naar een gebruiker die niet bestaat. -Fc schrijft het aangepaste archiefformaat, dat alleen door pg_restore kan worden gelezen en waarmee u later specifieke tabellen kunt herstellen. Herstel naar dezelfde major-versie of een nieuwere versie. Teruggaan, bijvoorbeeld van 17 naar 16, wordt niet ondersteund; pg_restore weigert het archief met een unsupported-version foutmelding in de bestandsheader voordat er gegevens worden geschreven.

MySQL en MariaDB gebruiken één commando, met vier opties die niet standaard zijn ingeschakeld:

# 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 maakt een consistente snapshot zonder schrijfacties te blokkeren, maar alleen voor InnoDB-tabellen. Een MyISAM-tabel in dezelfde database wordt gekopieerd zonder deze garantie; controleer dus uw storage engines voordat u de dump vertrouwt. --routines, --triggers en --events staan standaard uit, wat betekent dat een standaard dump uw data herstelt maar uw stored procedures en scheduled events stilletjes achterlaat. Databasegebruikers en hun rechten bevinden zich in de mysql systeemdatabase, die een --databases appdb dump nooit aanraakt; maak deze dus opnieuw aan op de nieuwe server met CREATE USER en GRANT. MariaDB 11 levert dezelfde tool als mariadb-dump en behoudt mysqldump als een symbolische link, dus beide namen werken vanaf augustus 2026.

SQLite is één enkel bestand; dit kopiëren terwijl de applicatie schrijft, resulteert in een corrupt bestand. Gebruik de veilige methode:

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

Ongeacht de engine: controleer de dump voordat u deze vertrouwt. Een dump die voortijdig is gestopt omdat de schijf vol was, wordt zonder foutmeldingen hersteld, tot aan het punt waar het bestand werd afgekapt.

# 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;'

Waarom u een actieve database niet kunt synchroniseren met rsync

rsync kopieert bestand voor bestand. Een actieve database schrijft naar meerdere bestanden tegelijk, waardoor het eerste bestand al verouderd is tegen de tijd dat rsync het laatste bestand bereikt. De kopie bevat pagina's van verschillende tijdstippen, een toestand waarin de database zich nooit heeft bevonden. Het resultaat is een server die weigert op te starten, of in het ergste geval: een server die wel start, een week lang correcte antwoorden geeft en vervolgens crasht wanneer een query uiteindelijk de beschadigde pagina bereikt. Er is tussentijds geen waarschuwing.

Er zijn twee veilige manieren om de bestanden zelf te verplaatsen. Stop de database, kopieer de bestanden en start de database opnieuw: dit is correct, eenvoudig en kost u de duur van de kopieeractie aan downtime. Of gebruik de tool die is ontworpen voor een fysieke kopie van een actieve server. Voor PostgreSQL is dat pg_basebackup, die coördineert met de server zodat de kopie consistent is:

# 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

Hiervoor is een rol met het REPLICATION-attribuut en een bijbehorende pg_hba.conf-vermelding op de oude server vereist, dus het vergt meer configuratie dan een dump. Dit is de moeite waard wanneer de database zo groot is dat een dump en restore niet binnen uw tijdsvenster passen. Voor een normale migratie van een enkele server geniet de dump de voorkeur.

Bouw de certificaten opnieuw op vóór de overgang, niet erna

Een TLS-certificaat is gekoppeld aan de domeinnaam, niet aan het IP-adres, waardoor het certificaatbestand zelf zonder problemen kan worden verplaatst. Wat echter niet soepel verloopt, is de vernieuwing. De standaard HTTP-01 challenge van Certbot vraagt de certificaatautoriteit om een bestand op te halen via poort 80 op de naam die wordt gecertificeerd. Totdat DNS naar de nieuwe server wijst, komt dat verzoek aan op de oude server en mislukt de vernieuwing op de nieuwe server.

De eerste optie is om de bestaande certificaten en hun vernieuwingsstatus te kopiëren. Ze blijven geldig tot de vervaldatum, ongeacht op welke server ze staan.

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

Elk bestand onder /etc/letsencrypt/renewal/ benoemt de authenticator-plugin die het certificaat heeft uitgegeven. Installeer daarom dezelfde plugin op de nieuwe server (bijvoorbeeld python3-certbot-nginx), anders mislukt de eerste vernieuwing met een melding over een onbekende authenticator. Controleer of vernieuwing werkt voordat u ervan afhankelijk bent:

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

De tweede optie is om een nieuw certificaat uit te geven op de nieuwe server met behulp van de DNS-01 challenge. Deze bewijst controle via een TXT-record en raakt poort 80 nooit aan. Dit werkt vóór de migratie, terwijl de naam nog naar de oude server wijst, wat het de nettere keuze maakt als u uw DNS-provider kunt automatiseren. Certificaten uitgeven met de DNS-01 challenge behandelt de configuratie van de plugin en de inloggegevens.

Controleer in beide gevallen wat de nieuwe server daadwerkelijk presenteert, zonder de DNS te wijzigen:

# 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 verstuurt SNI (server name indication), wat ervoor zorgt dat de webserver de juiste virtual host kiest. Laat u dit weg, dan krijgt u het standaardcertificaat voor dat IP-adres en een mismatch die eruitziet als een serieus probleem, maar dat niet is.

Verlaag de DNS TTL dagen voor de migratie

DNS is het punt waar een zorgvuldige migratie vaak alsnog misgaat, omdat de vertraging ingebakken zit en u deze op de dag zelf niet kunt verkorten. Een resolver die uw A-record heeft gecachet, blijft dit serveren gedurende de looptijd van de TTL (time to live) die het heeft ontvangen. Het verlagen van de TTL heeft nu geen effect op een resolver die het record tien minuten geleden met de oude waarde heeft gecachet: deze houdt de oude waarde vast voor de rest van de oude TTL-duur en leert pas daarna de nieuwe, kortere waarde. Verlaag de TTL daarom ten minste één volledige oude TTL-periode vóór de migratie. Eén dag van tevoren is de veilige marge. Als de onderliggende techniek nieuw voor u is, biedt de uitleg over records, resolvers en caching de nodige achtergrondinformatie.

De onderstaande getallen zijn een rekenkundig resultaat van de TTL zelf, geen meting.

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
  }
]

Een A-record dat is gepubliceerd met een TTL van 3600 seconden kan gebruikers naar het oude IP-adres blijven sturen gedurende 60 minuten nadat u het heeft gewijzigd. Verlaag dit naar 300 seconden en dat worst-case scenario daalt naar 5 minuten. Beschouw deze cijfers als een ondergrens, niet als een garantie. Sommige resolvers hanteren een eigen minimale TTL en negeren kortere waarden, en sommige applicatie-runtimes cachen een opgelost adres voor de gehele levensduur van het proces. Een client die is gestart vóór uw wijziging, zal het adres mogelijk nooit opnieuw opvragen totdat deze opnieuw wordt opgestart.

Raadpleeg het autoritatieve antwoord, niet uw eigen cache, wanneer u controleert of de lagere TTL actief is:

# 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

Het tweede veld van die antwoordregel is de TTL in seconden. Loop vervolgens de records na die vaak worden vergeten: het AAAA-record als de oude server IPv6 had, de www-naam wanneer dit een afzonderlijk A-record is in plaats van een CNAME, elk MX-record dat naar de server zelf wijst, een SPF-record dat het oude IP-adres bevat, en het reverse DNS (PTR) record op het nieuwe adres. Stel het PTR-record in via het configuratiescherm van uw provider vóór de migratie als de server e-mail verstuurt; ontvangende mailservers controleren dit namelijk, en een ontbrekend PTR-record leidt tot geweigerde e-mail, uren nadat alles in orde leek.

Verifieer de nieuwe server op het IP-adres voordat u DNS aanpast

U kunt de volledige applicatie op de nieuwe server testen terwijl DNS nog naar de oude server wijst. Overschrijf de naamresolutie voor één verzoek:

# 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 wijzigt alleen de bestemming van de verbinding. Het TLS-certificaat wordt nog steeds gecontroleerd op basis van de werkelijke naam, waardoor u zowel het certificaat als de service valideert. %{ssl_verify_result} geeft 0 weer wanneer de keten is geverifieerd.

Om de site in een browser te doorlopen, overschrijft u de naamresolutie voor uw gehele machine door één regel toe te voegen aan /etc/hosts op uw laptop, of aan C:\Windows\System32\drivers\etc\hosts op Windows:

203.0.113.20 example.com www.example.com

Doorloop vervolgens de applicatie zoals een gebruiker dat zou doen. Log in. Laad een pagina die gegevens uit de database leest. Verstuur een formulier dat naar de database schrijft. Upload een bestand en bevestig dat het op de schijf is opgeslagen. Activeer de functionaliteit die e-mail verstuurt en controleer of deze aankomt, aangezien uitgaande SMTP vanaf een nieuw IP-adres vaak voor verrassingen zorgt. Verwijder de regel uit het hosts-bestand zodra u klaar bent. Als u deze laat staan, zult u onnodig tijd besteden aan het debuggen van een site die voor iedereen anders perfect bereikbaar is.

De migratie, stap voor stap

  1. Dagen van tevoren: verlaag de TTL, voer de bulk rsync uit, bouw de nieuwe server en test deze via een hosts-override.
  2. Op de dag zelf, voor het onderhoudsvenster: voeg het nieuwe IP-adres toe aan elke whitelist van derden en bevestig dat de back-uptaak van de nieuwe server is geconfigureerd en naar uw repository wijst.
  3. Open het venster: zet de applicatie op de oude server in de onderhoudsmodus zodat deze geen schrijfacties meer accepteert.
  4. Maak de laatste database-dump en voer vervolgens de laatste rsync-pass uit met --delete.
  5. Herstel de dump op de nieuwe server en start de services.
  6. Test opnieuw via --resolve en de hosts-override, inclusief één daadwerkelijke schrijfactie.
  7. Wijzig de A- en AAAA-records naar het nieuwe IP-adres.
  8. Monitor beide servers. Het access log van de oude server toont wie er nog steeds aankomt; dit aantal zou gedurende de TTL naar nul moeten dalen.
  9. Schakel de onderhoudspagina uit.
  10. Laat de oude server minimaal een week draaien zonder wijzigingen aan te brengen.

De stap voor de onderhoudsmodus wordt vaak overgeslagen, terwijl dit juist de stap is die u beschermt. Zodra de nieuwe database een schrijfactie heeft geaccepteerd, betekent terugdraaien dat u ofwel die schrijfactie verliest, ofwel de nieuwe database moet dumpen en terug moet laden in de oude. Een venster van enkele minuten in alleen-lezenmodus is een kleine prijs. Twee databases die beide schrijfacties hebben verwerkt, leiden tot dagen aan handmatige reconciliatie.

Het rollback-plan

Een rollback is één actie: wijzig de DNS-records terug naar 198.51.100.10. Dit werkt alleen dankzij vier zaken die u eerder heeft uitgevoerd.

  • De oude server draait nog steeds, de services zijn actief en de data is intact. U heeft daar het schrijven gestopt, u heeft de server niet buiten gebruik gesteld.
  • De TTL is nog steeds laag, waardoor de weg terug net zo snel is als de weg vooruit was.
  • U heeft het nieuwe IP-adres toegevoegd aan de allowlists van derden in plaats van het oude adres te vervangen. Verwijdert u het oude adres, dan faalt uw rollback-pad bij de betaalgateway.
  • De nieuwe server heeft geen schrijfacties verwerkt die u niet kunt identificeren, omdat de enige schrijfacties tot nu toe uw eigen testtransacties waren.

Bepaal voordat het onderhoudsvenster opent wat een rollback triggert. Twee triggers zijn voldoende: elke fout die u niet binnen een vastgesteld aantal minuten kunt diagnosticeren, en elk verlies van data. Door deze vooraf vast te leggen, voorkomt u het uur aan giswerk dat een storing van tien minuten verandert in een langdurige uitval.

Controleer of de migratie is geslaagd

Een migratie is niet voltooid zodra de site laadt. Controleer de zaken die pas later falen.

# 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 is het resultaat dat u wilt zien. certbot certificates hoort de verwachte verloopdata te tonen en list-timers hoort elke geplande taak uit uw inventaris weer te geven met een werkelijke volgende uitvoeringstijd, niet een lege waarde.

Start de nieuwe server daarna eenmaal bewust opnieuw op terwijl u toekijkt. Een service die handmatig is gestart en nooit is ingeschakeld, werkt perfect tot de eerste ongeplande herstart om drie uur 's nachts.

# new server
sudo reboot

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

Als de applicatie in containers draait, heeft dezelfde valkuil een andere vorm, omdat een compose stack een expliciet restart policy nodig heeft om na een reboot terug te keren.

De laatste controle is het makkelijkst uit te stellen en het belangrijkst: de back-uptaak. Een migratie die eindigt met een server zonder back-ups heeft het ene risico ingeruild voor het andere. Voer de back-up op de nieuwe server handmatig uit en herstel vervolgens één bestand vanuit die back-up naar een tijdelijke map. Een restic repository waarvan u het herstel daadwerkelijk heeft getest is de versie hiervan die helpt wanneer u het nodig heeft. Als u de oude en nieuwe servers een week lang naast elkaar draait, voorkomt een consistente manier om elke host te bereiken en te configureren dat de twee uit elkaar gaan lopen terwijl beide actief zijn.

Na de overgang: de oude server en de laatste punten

Houd de oude server één tot twee weken aan. Dit kost u één maand van een abonnement dat u toch al wilde opzeggen, en het is uw enige mogelijkheid tot een rollback. Rond daarna de rest af.

  • Het hergebruiken van dezelfde hostnaam in uw ~/.ssh/config voor de nieuwe server levert een WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! op bij de eerste verbinding, omdat die naam nu antwoordt met een andere host key. Verwijder de verouderde vermelding met ssh-keygen -R example.com zodra u zeker weet waarom deze is gewijzigd. Doe dit niet reflexmatig, aangezien dezelfde waarschuwing ook wijst op een onderscheppingsaanval. Een migratie is ook een goed moment om te controleren welke keys toegang hebben tot welke systemen; zie hiervoor SSH key management op een klein serverpark.
  • Maak een laatste snapshot of back-up van de oude server en sla deze op een locatie op die niet bij de oude provider hoort.
  • Verwijder het oude IP-adres uit monitoring-checks, uit SPF-records en uit toegangslijsten van derden, in die volgorde en pas als laatste stap.
  • Zeg het oude abonnement pas op nadat is bevestigd dat de laatste kopie elders leesbaar is.

FAQ

Hoe lang duurt het om een server naar een nieuwe VPS te migreren?

De voor de gebruiker zichtbare downtime bestaat doorgaans uit de laatste database-dump, de laatste rsync-run en het starten van de services; voor een kleine applicatie is dit tien tot dertig minuten. De totale doorlooptijd is langer, omdat de DNS TTL ten minste één oude-TTL-periode voor de overstap moet worden verlaagd; een dag van tevoren is veiliger. Plan het kopiëren van de bulkdata ook dagen van tevoren. Dit proces draait tegen een actieve server in, en een latere herhaling verplaatst alleen de wijzigingen sinds de vorige run.

Kan ik een draaiende MySQL- of PostgreSQL-database met rsync kopiëren in plaats van een dump te maken?

Nee. rsync kopieert bestand voor bestand terwijl de database naar meerdere bestanden tegelijk schrijft. De kopie bevat daardoor pagina's van verschillende tijdstippen en vertegenwoordigt een staat die de database nooit heeft gehad. De database weigert mogelijk te starten, of start wel maar faalt later wanneer een query een beschadigde pagina bereikt. Gebruik pg_dump met pg_dumpall --globals-only, of mysqldump --single-transaction, of stop de database eerst en kopieer daarna de bestanden. Voor een groot PostgreSQL-cluster maakt pg_basebackup een consistente fysieke kopie van een draaiende server.

Hoe test ik de nieuwe VPS voordat ik de DNS wijzig?

Overschrijf de naamresolutie op uw eigen machine. Voor een enkel verzoek stuurt curl --resolve example.com:443:203.0.113.20 https://example.com/ de verbinding naar het nieuwe IP-adres, terwijl het certificaat nog steeds wordt gecontroleerd tegen de werkelijke naam. Voor browser-tests voegt u 203.0.113.20 example.com toe aan /etc/hosts op uw laptop, doorloopt u een login, een database-read, een form-write en een file-upload, en verwijdert u daarna de regel. Om alleen het certificaat te inspecteren, voert u openssl s_client -connect 203.0.113.20:443 -servername example.com uit.

Welke TTL moet ik instellen en wanneer moet ik deze verlagen?

Verlaag de A- en AAAA-records naar 300 seconden en doe dit ten minste één volledige oude-TTL-periode voor de overstap. Een resolver die het record vóór uw wijziging heeft gecachet, behoudt de oude waarde voor de rest van de oude TTL; het verlagen van de TTL een uur van tevoren heeft dus geen zin als de oude TTL 86400 was. Verhoog de TTL weer naar de normale waarde enkele dagen na de migratie, zodra de toegangslogs van de oude server stil zijn geworden.

Moet ik het TLS-certificaat kopiëren of een nieuwe aanvragen op de nieuwe server?

Beide opties werken. Het kopiëren van /etc/letsencrypt/ houdt het certificaat geldig tot de bestaande verloopdatum, maar u moet dezelfde certbot-authenticator-plugin op de nieuwe server installeren, anders mislukt de eerste vernieuwing; voer daarom certbot renew --dry-run uit na de DNS-switch om dit te bevestigen. Opnieuw uitgeven is schoner wanneer u de DNS-01 challenge kunt gebruiken, omdat dit controle bewijst via een TXT-record en werkt voordat DNS naar de nieuwe server wijst. De HTTP-01 challenge kan pas op de nieuwe server worden gebruikt nadat de DNS is verplaatst, aangezien het validatieverzoek anders de oude server zou bereiken.