Semua sistem berjalan normal Amsterdam · Paris · Reykjavík +5 Bayar dengan Kripto
Jaringan & self-hostingMenengahBaca 29 menitDiperbarui 2026-09-06

Migrasikan VPS ke host baru tanpa downtime

Setiap server pasti pindah setidaknya sekali. Mekanismenya adalah bagian yang mudah — kegagalan justru muncul di celah antara tiga jam yang tidak tersinkronkan: DNS, data, dan sesi yang sudah berjalan. Berikut cara menutup celah-celah itu pada hari Selasa pilihan Anda sendiri.

Migrasikan VPS ke host baru tanpa downtime
Di halaman ini
  1. Tiga jam itu, dan kenapa “zero downtime” adalah target yang salah
  2. Apa yang masih dipegang host lama setelah Anda pergi
  3. Jam TTL mulai berjalan seminggu sebelum proses pindah
  4. Menentukan ukuran server baru, dan apa yang perlu dicek sebelum Anda memutuskannya
  5. Langkah demi langkah
  6. Mail tidak ikut migrasi bersama yang lain
  7. Rollback tanpa membuatnya makin buruk
  8. Dekomisioning: rotasi, hapus, verifikasi, baru batalkan
  9. Linimasa yang benar-benar berhasil
  10. Pertanyaan yang sering diajukan

Setiap server yang Anda jalankan pasti akan pindah setidaknya sekali. Host-nya menaikkan harga, atau mulai meminta dokumen yang sebenarnya tidak ingin Anda kirim, atau menerima laporan penyalahgunaan soal tetangga Anda dan men-null-route seluruh /24 selama satu sore. Pertanyaannya bukan soal apakah Anda akan migrasi — melainkan apakah itu terjadi pada pagi hari Selasa pilihan Anda sendiri, atau malam Sabtu yang dipilihkan orang lain untuk Anda.

Mekanismenya bukan bagian yang sulit. Menyalin berkas tinggal rsync, dan itu sudah Anda ketahui. Yang membuat migrasi jadi berantakan adalah soal waktu: ada tiga jam terpisah yang berjalan selama proses pindah, ketiganya tidak tersinkronkan, dan setiap kegagalan sungguhan terjadi di celah di antara ketiganya. Panduan ini soal celah-celah itu — TTL DNS yang seharusnya sudah Anda turunkan seminggu sebelumnya, database yang Anda salin selagi masih ada yang menulis ke dalamnya, sertifikat yang cuma ada di mesin yang baru saja Anda matikan, dan kredensial yang selama ini bisa dibaca oleh host lama.

Perintah-perintah di sini mengasumsikan Debian atau Ubuntu di kedua sisi dan sebuah aplikasi web dengan database, karena itulah yang paling sering dipindahkan orang. Sebuah Nextcloud, game server, bot, atau instance BTCPay semuanya mengikuti bentuk yang sama — cuma langkah data-nya yang berbeda.

Tiga jam itu, dan kenapa “zero downtime” adalah target yang salah

Migrasi bukan satu peristiwa tunggal. Ada tiga penghitung waktu yang berjalan dengan kecepatan berbeda, dan seluruh seninya ada pada mencegah ketiganya saling tumpang tindih dengan buruk:

  • Jam DNS. Sejak Anda mengubah A record, resolver akan terus menjawab dengan alamat lama sampai salinan cache-nya kedaluwarsa. Anda tidak mengendalikan jam ini pada saat cutover — Anda mengendalikannya saat Anda mengatur TTL, berhari-hari sebelumnya.
  • Jam data. Salinan data terakhir Anda adalah potret satu momen. Semua yang ditulis setelah momen itu hanya ada di mesin lama, dan akan hilang kecuali Anda memutar ulang tulisan itu atau mencegahnya terjadi.
  • Jam sesi. Unggahan yang sedang berjalan, WebSocket yang masih terbuka, callback pembayaran yang akan tiba empat puluh detik lagi dari sebuah processor yang me-resolve hostname Anda dua menit yang lalu. Semua ini mendarat di server mana pun yang di-resolve oleh pengirimnya, bukan yang Anda inginkan.

Mengejar zero downtime secara harfiah berarti menjaga ketiganya berjalan bersamaan, yang dalam praktiknya berarti menjalankan aplikasi di dua server yang menulis ke dua database sekaligus. Itu masalah yang sungguh-sungguh sulit, dan itu masalah yang salah untuk dipecahkan demi satu VPS saja. Tujuan yang jujur jauh lebih sempit dan jauh lebih mudah dicapai:

Tidak ada pengunjung yang melihat error, dan tidak ada tulisan yang hilang. Jendela sembilan puluh detik di mana situsnya tetap hidup tapi read-only memenuhi keduanya, dan hampir tidak ada yang akan menyadarinya. Cutover live tanpa jendela maintenance yang diam-diam kehilangan empat puluh menit terakhir kiriman formulir tidak memenuhi keduanya, dan Anda akan mengetahuinya dari pelanggan.

Jadi rencananya adalah: buat jendela read-only sesingkat mungkin, buat itu membosankan, dan buat itu bisa dibalik. Semua yang di bawah ini melayani tiga hal itu.

Apa yang masih dipegang host lama setelah Anda pergi

Bagian ini sering dilewatkan, padahal justru inilah alasan banyak orang migrasi sejak awal, jadi ini layak dijelaskan secara presisi. Selama server Anda hidup di perangkat keras milik orang lain, provider itu berada dalam posisi untuk melihat:

  • Disk-nya, secara penuh. Kecuali volume-nya dienkripsi dengan LUKS dan cuma bisa di-unlock oleh Anda, hypervisor-nya bisa membaca setiap byte-nya — key, token, isi database, semuanya. Bahkan dengan enkripsi, memory dari VM yang sedang berjalan tetap menyimpan key yang sudah di-unlock.
  • Setiap kredensial yang dipakai mesin itu. API token di file environment, password SMTP, secret RPC wallet daemon, SSH public key Anda dan, kalau Anda pernah menempelkan satu ke rescue console, bahkan lebih dari itu.
  • Apa pun yang diminta akun itu. Nama, kartu, alamat, nomor telepon untuk verifikasi SMS, alamat IP tempat Anda login. Kumpulan itu tidak mengecil ketika Anda menutup akunnya, dan di kebanyakan yurisdiksi provider diwajibkan menyimpan sebagian darinya selama bertahun-tahun.

Semua ini tidak jahat — ini cuma konsekuensi dari menjalankan mesin virtual di perangkat keras milik orang lain, di mana pun, termasuk di sini. Yang penting adalah migrasi adalah satu-satunya titik pemutus bersih yang Anda dapatkan. Server baru dimulai dengan key baru, token baru, dan IP baru; kalau Anda membawa serta secret lama, Anda ikut membawa serta eksposur lamanya, dan pemutusannya cuma kosmetik.

Jadi perlakukan setiap secret di mesin lama sebagai sudah bocor secara default, dan terbitkan ulang selama proses pindah. Biayanya cuma satu jam sekali jalan. Melakukannya belakangan, secara terpisah, adalah pekerjaan yang tidak akan pernah benar-benar dikerjakan siapa pun. Dan kalau sebagian alasan Anda pindah adalah karena akunnya sendiri yang jadi sumber kebocoran, membayar akun baru dengan Monero terhadap akun no-KYC adalah langkah yang membuat pemutusan itu nyata, bukan cuma simbolis — meski tetap jujurlah pada diri sendiri soal apa yang benar-benar didapat dan tidak didapat dari itu, yang merupakan topik tersendiri.

Jam TTL mulai berjalan seminggu sebelum proses pindah

Time to live adalah jumlah detik yang boleh dipakai resolver untuk menyimpan record Anda sebelum bertanya lagi. Kalau A record Anda memakai TTL default 3600, maka pada detik Anda mengubahnya, resolver yang baru saja bertanya satu detik sebelumnya akan terus mengirim pengunjung ke server lama selama lima puluh sembilan menit lima puluh sembilan detik berikutnya. Dengan 86400 yang masih dipakai banyak registrar sebagai default, itu jadi satu hari penuh.

Cek apa yang sebenarnya Anda punya — bukan apa yang Anda kira sudah Anda atur:

dig +noall +answer example.com A
dig +noall +answer www.example.com A
dig +noall +answer example.com MX
dig +noall +answer example.com NS

Kolom kedua dari setiap jawaban adalah TTL, yang sedang menghitung mundur. Turunkan setiap record yang terlibat dalam proses pindah ke 300 detik, dan lakukan itu setidaknya dua kali lipat TTL saat ini sebelum cutover Anda: kalau record-nya masih di 86400, perubahan itu sendiri butuh satu hari untuk terlihat secara universal, dan itulah lelucon rekursif di jantung migrasi DNS.

Dua detail yang sering menjebak orang:

  • NS record punya TTL-nya sendiri, biasanya panjang, dan diatur di registrar, bukan di zone Anda. Itu cuma penting kalau Anda juga mengganti nameserver — yang sebaiknya Anda hindari melakukannya di minggu yang sama dengan pindah server. Ganti host, biarkan mengendap, baru ganti provider DNS kalau Anda mau. Dua variabel, dua akhir pekan.
  • “Propagasi DNS” itu tidak ada. Tidak ada yang menyebar; yang ada cache yang kedaluwarsa. Tidak ada antrean untuk ditunggu dan tidak ada tombol yang bisa mendorong update keluar lebih cepat. Satu-satunya tuas adalah TTL, dan pada saat cutover, tuas itu sudah ditarik.

Selagi Anda berada di zone file, catat setiap record yang menunjuk ke alamat IP server, bukan ke sebuah nama. Biasanya ada satu lagi yang tidak Anda ingat: mail, webmail, sebuah @ polos, staging lama, SPF record dengan literal ip4: di dalamnya, dan AAAA record yang Anda tambahkan waktu pertama kali dapat blok IPv6 lalu lupa begitu saja. Masing-masing butuh rencana, dan AAAA adalah kegagalan diam-diam yang klasik — Anda mengubah A record, semuanya terlihat baik-baik saja dari laptop Anda, dan setiap pengunjung dengan IPv6 yang berfungsi terus mendarat di server yang sudah Anda hapus.

Menentukan ukuran server baru, dan apa yang perlu dicek sebelum Anda memutuskannya

Tahan keinginan untuk memesan spesifikasi yang persis sama dengan yang Anda punya sekarang. Anda selama ini membeli berdasarkan angka di invoice, bukan berdasarkan apa yang benar-benar dipakai workload Anda. Luangkan dua menit untuk mengukur dulu:

# peak RAM actually in use, not allocated
free -m
# what has been paging, if anything
vmstat -s | grep -i swap
# real disk consumption, biggest first
du -xh --max-depth=2 / 2>/dev/null | sort -rh | head -20
# load relative to core count
uptime; nproc

Dua aturan praktis ini cukup andal. Kalau load average Anda berada di bawah jumlah core dan swap tidak pernah tersentuh, server-nya tidak dibatasi oleh CPU atau memory dan Anda bisa pindah ke samping atau ke bawah. Kalau disk sudah di atas tujuh puluh persen, tentukan ukuran yang baru berdasarkan apa yang akan Anda butuhkan setahun ke depan, bukan apa yang Anda pakai hari ini — memperbesar volume belakangan adalah migrasi dalam skala mini, dan Anda sedang melakukan salah satunya sekarang juga.

Di sisi kami itu terpetakan dengan rapi: Pup (1 vCPU, 1 GB, 25 GB) menjalankan situs statis, VPN, atau bot kecil; Cub (1 vCPU, 2 GB, 40 GB) adalah server terkecil yang bisa meng-hosting sebuah aplikasi plus database-nya sendiri tanpa paging; Scout (2 vCPU, 4 GB, 70 GB) adalah default yang nyaman untuk situs sungguhan dengan traffic sungguhan; Hunter (4 vCPU, 8 GB, 140 GB) ke atas adalah tempat container, CI, atau beberapa layanan sekaligus dalam satu server mulai jadi masuk akal. Semuanya all-NVMe dengan traffic unlimited, jadi kelebihan bandwidth — salah satu alasan umum orang pindah sejak awal — berhenti jadi variabel. Daftar lengkapnya di sini.

Lalu, sebelum Anda memindahkan satu byte pun, cek tiga hal soal mesin yang baru saja Anda dapatkan. Masing-masing murah sekarang dan mahal setelah cutover:

  • Reputasi IP-nya. Alamat daur ulang dengan riwayat milik orang lain akan membuat mail Anda ditolak dan pengunjung Anda di-challenge. Punya kami sudah disaring dan disegmentasi berdasarkan risiko sebelum diterbitkan, tapi sekarang ini layanan Anda yang berjalan di atasnya, jadi verifikasi sendiri — versi lima menitnya ada di sini. Lakukan ini sebelum DNS-nya dialihkan, saat jawabannya masih tidak berbiaya apa pun bagi Anda.
  • Reverse DNS. Kalau server ini akan pernah mengirim mail, PTR record-nya harus me-resolve ke sebuah hostname yang me-resolve balik ke IP yang sama. rDNS custom tersedia atas permintaan; minta itu sekarang supaya sudah mengendap pada saat cutover.
  • Rute dari lokasi pengguna Anda. Sebuah mtr dari mesin di wilayah pengguna Anda memberi tahu Anda lebih banyak soal pilihan yurisdiksi daripada datasheet mana pun. Latency yang Anda ukur sendiri lebih baik daripada latency yang cuma Anda asumsikan.

Langkah demi langkah

  1. Turunkan semua TTL, berhari-hari sebelum Anda berencana pindah

    Ini yang pertama karena ini satu-satunya langkah dengan masa tunggu wajib. Semua yang lain bisa dikerjakan dalam satu sore; yang ini tidak bisa dipercepat, dan melewatkannya adalah yang mengubah cutover lima menit jadi cutover dua hari.

    Login ke tempat zone Anda berada dan atur TTL ke 300 pada setiap record yang akan berubah: A apex-nya, AAAA-nya, www, mail, dan apa pun lain yang menunjuk ke literal IP. Lalu konfirmasi dari luar, karena panel kontrol dan kenyataan kadang tidak sepakat:

    dig +noall +answer example.com A @1.1.1.1
    dig +noall +answer example.com AAAA @1.1.1.1
    dig +noall +answer www.example.com A @8.8.8.8

    Angka sebelum IN adalah TTL yang tersisa. Query lagi semenit kemudian: seharusnya sedang menghitung mundur dari 300, bukan dari angka yang lebih besar. Kalau masih menghitung mundur dari 3600, nilai lamanya masih ter-cache dan Anda tinggal menunggu — dan itulah persisnya kenapa ini dilakukan pada hari minus tujuh, bukan pada pagi hari saat pindah.

    Biarkan TTL tetap di 300 selama migrasi dan selama seminggu setelahnya, supaya rollback Anda juga cepat. Kembalikan ke angka yang masuk akal — 3600 sudah cukup baik — begitu server lama sudah tidak ada lagi.

  2. Inventarisasi server lama sebelum menyalin apa pun

    Anda bukan sedang memigrasikan sebuah disk, Anda sedang memigrasikan sebuah sistem yang sedang berjalan, dan bagian-bagian yang sering dilupakan orang tidak pernah ada di /var/www. Itu adalah cron job yang berjalan setiap tanggal empat, aturan firewall yang ditambahkan saat ada insiden, package yang diinstal dari repository pihak ketiga dua tahun lalu. Tangkap state mesin itu sebagai teks, dan salin teks itu bersama semua yang lain:

    mkdir -p /root/mig
    dpkg --get-selections > /root/mig/packages.txt
    systemctl list-units --type=service --state=running --no-pager > /root/mig/services.txt
    systemctl list-timers --all --no-pager > /root/mig/timers.txt
    crontab -l > /root/mig/cron-root.txt 2>/dev/null
    for u in $(cut -d: -f1 /etc/passwd); do crontab -lu "$u" 2>/dev/null | sed "s/^/[$u] /"; done > /root/mig/cron-users.txt
    ss -tlnp > /root/mig/listening.txt
    nft list ruleset > /root/mig/firewall.txt 2>/dev/null || iptables-save > /root/mig/firewall.txt
    cp -a /etc/hosts /etc/fstab /root/mig/
    du -xh --max-depth=2 / 2>/dev/null | sort -rh | head -40 > /root/mig/disk.txt

    Sekarang baca listening.txt baris demi baris dan pastikan setiap port sudah dijelaskan. Berkas itu adalah jawaban definitif untuk “server ini sebenarnya melakukan apa”, dan hasilnya rutin mengejutkan — sebuah metrics exporter, salinan staging yang terlupakan, sebuah database yang listening di interface publik yang seharusnya tidak pernah begitu.

    Tulis daftar exclude Anda di saat yang sama, supaya sync pertama tidak menghabiskan satu jam untuk data yang tidak Anda inginkan:

    cat > /root/mig/excludes <<'EOF'
    /dev
    /proc
    /sys
    /run
    /tmp
    /var/tmp
    /var/cache
    /var/lib/apt/lists
    /swapfile
    /var/lib/docker/overlay2
    /var/lib/mysql
    /var/lib/postgresql
    **/node_modules
    **/.cache
    EOF

    Perhatikan bahwa direktori database memang sengaja dikecualikan. Itu punya langkahnya sendiri, dan menyalinnya di sini adalah kesalahan yang justru dicegah oleh keberadaan langkah enam.

  3. Deploy server baru dan harden dulu sebelum menyimpan apa pun

    Pesan server-nya, pilih lokasinya, dan pakai versi mayor OS yang sama dengan yang lama kalau bisa. Memigrasikan host sekaligus berpindah dari Debian 12 ke Debian 13 dalam satu operasi berarti kalau ada yang rusak Anda tidak akan tahu perubahan mana yang menyebabkannya. Pindah dulu, upgrade belakangan.

    Sebelum ada apa pun yang sensitif mendarat di situ, berikan mesin itu hardening sepuluh menit: SSH cuma dengan key, login root dimatikan, firewall default-deny, unattended security upgrades. Butuh sepuluh menit sekarang dan benar-benar merepotkan kalau harus diterapkan belakangan di sekitar layanan yang sudah live.

    Lalu buat sebuah key yang cuma ada untuk migrasi ini, di server lama, supaya mencabut akses migrasi belakangan tidak pernah berarti menyentuh login Anda sendiri:

    # on the OLD server
    ssh-keygen -t ed25519 -f /root/.ssh/id_migrate -C 'migration' -N ''
    cat /root/.ssh/id_migrate.pub

    Masukkan public key itu ke /root/.ssh/authorized_keys di server baru, lalu pastikan arah pergerakannya — lama push ke baru, jadi kredensialnya tetap tinggal di mesin yang akan Anda tinggalkan dan mati bersamanya:

    ssh -i /root/.ssh/id_migrate root@NEW_IP 'hostname; df -h /; free -m'

    Terakhir, masukkan IP baru ke /etc/hosts server lama dengan nama seperti newbox. Setiap perintah berikutnya jadi lebih singkat dan, yang lebih berguna, lebih sulit diarahkan ke mesin yang salah pada jam satu dini hari.

  4. Cek IP baru sebelum mempercayakan apa pun ke situ

    Sekarang Anda punya alamat yang belum pernah dipakai siapa pun untuk layanan Anda sebelumnya, dan ini momen terakhir di mana menemukan masalah dengannya masih gratis. Tiga pengecekan, lima menit:

    Blocklist. Jalankan alamatnya lewat pengecekan multi-RBL — prosedur lengkap dan cara membaca hasilnya ada di sini. Kena hit di policy list seperti Spamhaus PBL itu normal untuk IP datacenter dan hampir tidak berarti apa-apa untuk traffic web. Kena hit di SBL atau XBL itu baru serius, dan waktu untuk mengangkatnya adalah sekarang, bukan setelah pengguna Anda sudah ada di situ.

    Reverse DNS. Cek alamat itu menjawab dengan apa hari ini:

    dig +short -x NEW_IP

    Kalau server ini akan mengirim mail, minta PTR record yang Anda inginkan dan pastikan itu cocok dengan hostname yang A record-nya menunjuk balik ke IP yang sama. Forward dan reverse harus sepakat; ketidakcocokan lebih buruk daripada nama generik.

    Keterjangkauan dan rute. Pastikan port yang Anda butuhkan benar-benar terbuka ujung ke ujung, dari luar, alih-alih mengasumsikan firewall Anda adalah satu-satunya hal di jalurnya:

    # from a third machine, or your laptop
    nc -vz NEW_IP 22
    mtr -rwc 20 NEW_IP

    Output mtr adalah yang layak disimpan. Loss di hop terakhir itu penting; loss di hop perantara biasanya cuma router yang menurunkan prioritas ICMP dan tidak berarti apa-apa. Kalau latency dari wilayah pengguna Anda jauh lebih buruk daripada host lama, lebih baik ketahui itu sekarang, selagi berubah pikiran masih cuma berbiaya satu pesanan dan tanpa kehilangan data.

  5. Salin filesystem dengan rsync — dan dry-run dulu

    Sekarang transfer massalnya. Lakukan dalam dua pass: salinan penuh pertama berhari-hari sebelumnya, sebutuh apa pun waktu yang diperlukan, lalu pass delta singkat belakangan yang cuma memindahkan apa yang berubah. Selalu dry-run dulu — output-nya adalah daftar persis apa yang akan terjadi, dan membacanya sekali sudah menyelamatkan lebih banyak migrasi daripada kebiasaan lain mana pun di sini.

    # on the OLD server, dry run
    rsync -aHAXx --numeric-ids --info=progress2 --dry-run \
      --exclude-from=/root/mig/excludes \
      -e 'ssh -i /root/.ssh/id_migrate' \
      /var/www/ root@newbox:/var/www/

    Lalu perintah yang sama tanpa --dry-run. Ulangi untuk setiap direktori yang penting: /etc secara selektif, bukan seluruhnya, /home, /srv, /opt, dan di mana pun aplikasi Anda sebenarnya menyimpan uploads-nya.

    Flag-flag itu pantas dipakai. -a mempertahankan permission, ownership, timestamp, dan symlink; -H menjaga hard link; -A dan -X membawa ACL dan extended attribute, yang dibutuhkan direktori uploads Anda kalau pernah ada yang mengatur itu; -x mencegah rsync mengembara ke filesystem lain yang ter-mount. --numeric-ids adalah yang sering dilewatkan orang dan disesali: tanpa itu, rsync memetakan ownership berdasarkan nama, dan kalau www-data punya UID berbeda di kedua server, setiap berkas tiba dengan pemilik yang salah dengan cara yang merepotkan untuk diurai.

    Dua peringatan. Menyalin /etc secara utuh ke sistem yang sedang berjalan akan menimpa konfigurasi jaringan mesin baru, fstab-nya, dan SSH host key-nya — salin konfigurasi spesifik yang Anda butuhkan, bukan direktorinya. Dan simpan --delete hanya untuk pass terakhir: itu tepat untuk membuat server baru cocok persis dengan yang lama, dan destruktif kalau Anda sudah membuat sesuatu di tujuan.

    Begitu pass penuh pertama selesai, bandingkan kedua sisi supaya Anda tahu itu sudah melakukan apa yang Anda kira:

    du -sh /var/www
    ssh -i /root/.ssh/id_migrate root@newbox 'du -sh /var/www'
  6. Pindahkan database dengan dump, jangan pernah dengan salinan berkas

    Ini langkah yang menentukan apakah migrasi Anda membosankan atau tak terlupakan. Direktori data sebuah database cuma konsisten kalau server-nya berhenti. Salin itu secara live dan Anda dapat sekumpulan berkas yang terlihat baik, ter-transfer dengan baik, dan kalau di-restore jadi database yang korup secara halus dan permanen — sering kali tanpa error sampai berminggu-minggu kemudian.

    Dump dengan benar. Untuk MySQL atau MariaDB, --single-transaction adalah yang memberi Anda snapshot konsisten tanpa mengunci semuanya:

    mysqldump --single-transaction --quick --routines --triggers --events \
      --default-character-set=utf8mb4 --databases appdb \
      | zstd -T0 > /root/mig/appdb.sql.zst

    Untuk PostgreSQL, custom format-nya sepadan — itu terkompresi, dan memungkinkan Anda restore secara selektif kalau perlu:

    pg_dump -Fc -Z6 appdb > /root/mig/appdb.dump

    Kirim ke server baru dan restore:

    scp -i /root/.ssh/id_migrate /root/mig/appdb.sql.zst root@newbox:/root/
    # on the NEW server
    zstd -dc /root/appdb.sql.zst | mysql
    # postgres equivalent
    pg_restore -d appdb -j4 /root/appdb.dump

    Lalu verifikasi, karena “restore-nya selesai” dan “datanya memang ada di situ” adalah dua klaim yang berbeda. Bandingkan row count pada tabel-tabel yang penting, di kedua sisi:

    mysql -N -e "SELECT COUNT(*) FROM appdb.orders; SELECT COUNT(*) FROM appdb.users;"

    Dua hal yang bersembunyi di dalam dump: character set dan collation, yang jadi sumber karakter beraksen yang berantakan — kalau database lama memakai utf8, bukan utf8mb4, putuskan secara sadar apakah proses pindah ini juga jadi momen untuk memperbaikinya; dan user database beserta grant-nya, yang tidak disertakan oleh mysqldump --databases. Buat ulang user dan password aplikasinya secara eksplisit di server baru, lalu ingat bahwa connection string di konfigurasi Anda harus disesuaikan.

    Kalau aplikasi Anda memakai SQLite, berkasnya adalah database-nya dan aturan yang sama berlaku — jangan salin itu secara live. Pakai sqlite3 app.db ".backup /root/mig/app.db", yang mengambil salinan konsisten dengan aman.

  7. Nyalakan stack-nya dan gladi bersih di balik hosts-file override

    Server baru sekarang sudah punya berkas-berkas dan data-nya. Nyalakan semuanya dan uji di bawah hostname aslinya — selagi seluruh dunia lain masih dengan senang hati memakai server lama. Ini trik paling berharga dalam seluruh prosedur ini dan cuma berbiaya satu baris.

    Di laptop Anda sendiri, tambahkan IP server baru ke /etc/hosts (atau C:\Windows\System32\drivers\etc\hosts):

    203.0.113.10   example.com www.example.com

    Browser Anda sekarang me-resolve domain aslinya ke server baru, dan tidak ada browser lain yang begitu. Setiap URL benar, setiap cookie domain cocok, setiap redirect dan callback path berperilaku persis seperti yang akan terjadi setelah cutover — yang justru tidak akan terungkap kalau Anda menguji lewat subdomain sementara seperti new.example.com, karena separuh dari yang bisa rusak dalam migrasi bergantung pada hostname.

    Untuk satu pengecekan cepat tanpa mengubah apa pun, curl bisa melakukan hal yang sama secara inline:

    curl -sSI --resolve example.com:443:203.0.113.10 https://example.com/
    curl -sS --resolve example.com:80:203.0.113.10 http://example.com/ -o /dev/null -w '%{http_code}\n'

    Jelajahi seluruh aplikasinya, bukan cuma halaman depan: login, kirim formulir, unggah berkas, picu mail reset password, muat halaman admin, panggil endpoint yang dipanggil payment processor. Lalu baca error log meskipun semuanya terlihat baik-baik saja — PHP extension yang hilang, file mode yang salah di direktori cache, dan user database yang belum ada semuanya muncul di situ sebelum muncul di layar.

    Ingat untuk menghapus baris hosts-nya setelahnya. Semua orang pernah lupa sekali, lalu menghabiskan dua puluh menit bertanya-tanya kenapa rollback-nya kelihatan tidak berhasil.

  8. Buat TLS berfungsi di server baru sebelum Anda mengalihkan apa pun

    Sertifikat terikat pada nama, bukan pada alamat IP, jadi tidak ada apa pun dari sebuah migrasi yang membatalkan sertifikat yang sudah Anda punya. Yang bermasalah adalah penerbitannya: HTTP-01 challenge yang biasa dipakai meminta Let's Encrypt mengambil sebuah berkas lewat port 80 di nama yang sedang disertifikasi, dan nama itu masih menunjuk ke server lama. Ayam dan telur ini adalah keseluruhan kesulitannya, dan ada tiga cara bersih untuk keluar darinya.

    Salin sertifikat yang sudah ada. Paling sederhana dan biasanya paling tepat. Private key dan chain-nya berpindah seperti berkas lain mana pun:

    rsync -aHAX -e 'ssh -i /root/.ssh/id_migrate' \
      /etc/letsencrypt/ root@newbox:/etc/letsencrypt/

    Server baru bisa langsung melayani TLS yang valid, dan renewal-nya mulai berfungsi sendiri begitu DNS menunjuk ke situ. Pastikan timer-nya aktif di sana: systemctl list-timers | grep certbot.

    Pakai DNS-01 challenge. Membuktikan kendali atas domain lewat sebuah TXT record, bukan lewat request HTTP, jadi ini berfungsi dari server yang belum ditunjuk apa pun. Ideal kalau Anda ingin sertifikat yang benar-benar independen di server baru sebelum cutover, dan satu-satunya opsi untuk wildcard.

    Terbitkan setelah beralih. Valid, tapi ini meninggalkan celah di mana situsnya sudah live di IP baru tanpa sertifikat, yang untuk apa pun yang memakai HSTS bukan sekadar peringatan yang bisa diklik lewat oleh pengunjung Anda. Cuma masuk akal untuk domain yang benar-benar baru yang belum pernah dikunjungi siapa pun.

    Apa pun yang Anda pilih, verifikasi langsung terhadap IP baru sebelum cutover, memakai trik --resolve yang sama:

    curl -sSI --resolve example.com:443:203.0.113.10 https://example.com/ | head -1
    echo | openssl s_client -connect 203.0.113.10:443 -servername example.com 2>/dev/null \
      | openssl x509 -noout -subject -dates

    Cek tanggalnya dan pastikan subject-nya mencakup setiap nama yang Anda layani, termasuk www. Dan kalau Anda memakai HSTS dengan max-age yang panjang, perlakukan sertifikatnya sebagai satu hal yang harus benar sebelum beralih, bukan sesudahnya — header itu adalah janji yang sudah Anda buat ke setiap pengunjung yang kembali.

  9. Cutover-nya: bekukan tulisan, delta terakhir, alihkan record-nya

    Sepuluh menit kerja sungguhan, dan satu-satunya bagian yang punya jam berjalan di atasnya. Lakukan di pagi hari, di zona waktu Anda sendiri, pada hari Anda tidak sedang sibuk dengan hal lain. Jangan pernah di hari Jumat.

    Bekukan. Masukkan aplikasi lama ke mode maintenance atau read-only. Hentikan worker, konsumer antrean, dan cron job — apa pun yang menulis tanpa browser yang terhubung. Sejak titik ini, tidak ada yang baru ditulis di server lama, dan itulah yang membuat semua yang terjadi setelahnya aman:

    # on the OLD server
    systemctl stop app-worker.service
    systemctl stop cron
    touch /var/www/maintenance.flag

    Delta terakhir. Satu rsync lagi, sekarang dengan --delete supaya tujuannya cocok persis, dan satu dump lagi. Dengan pass pertama sudah selesai berhari-hari sebelumnya, ini cuma memindahkan sangat sedikit dan cuma butuh beberapa detik:

    rsync -aHAXx --numeric-ids --delete --exclude-from=/root/mig/excludes \
      -e 'ssh -i /root/.ssh/id_migrate' /var/www/ root@newbox:/var/www/
    mysqldump --single-transaction --quick --routines --triggers --events \
      --default-character-set=utf8mb4 --databases appdb | zstd -T0 \
      | ssh -i /root/.ssh/id_migrate root@newbox 'zstd -dc | mysql'

    Cek. Row count di kedua sisi, satu pass lagi lewat aplikasinya lewat hosts-file override, dan lepaskan maintenance flag dari server baru.

    Alihkan. Ubah A record ke IP baru. Ubah AAAA record-nya juga — ini cara paling umum sebuah cutover cuma berhasil separuh. Konfirmasi dari resolver yang tidak Anda kendalikan:

    dig +short example.com A @1.1.1.1
    dig +short example.com AAAA @1.1.1.1

    Lalu pantau kedua mesin. Traffic seharusnya muncul di server baru dalam satu-dua menit dan memudar dari server lama dalam lima menit berikutnya:

    tail -f /var/log/nginx/access.log        # on both, side by side

    Biarkan aplikasi lama tetap dalam mode maintenance, alih-alih mematikannya. Pengunjung yang tersisa dan sampai ke situ akan melihat halaman yang sopan, bukan connection error, dan Anda tetap punya mesin yang siap untuk rollback yang mungkin tidak akan Anda butuhkan.

  10. Pantau selama seminggu, baru dekomisioning dengan benar

    Migrasi belum selesai begitu DNS sudah ter-resolve. Itu selesai begitu satu siklus penuh billing dan cron sudah berlalu tanpa kejutan.

    Untuk beberapa jam pertama, pantau error rate, bukan uptime — sebuah server bisa saja sepenuhnya up dan tetap mengembalikan 500 untuk sepertiga request-nya:

    journalctl -u nginx -u php8.4-fpm -f
    awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head

    Lalu telusuri daftar singkat ini, karena inilah yang benar-benar rusak setelah pindah dan tidak satu pun dari ini akan mengumumkan dirinya sendiri: cron job dan systemd timer yang berjalan di server baru (systemctl list-timers dicocokkan dengan inventaris yang Anda ambil di langkah dua); mail keluar yang benar-benar sampai dan tidak mendarat di spam; backup terjadwal yang menunjuk ke server baru, bukan masih mengarsipkan server lama; pihak ketiga mana pun yang punya alamat IP Anda di allowlist — payment processor, sebuah API, firewall milik partner; dan job bulanan yang cuma membuktikan dirinya pada tanggal satu.

    Biarkan server lama tetap berjalan, dalam mode maintenance, tidak disentuh, selama setidaknya seminggu. Itu adalah rollback Anda sekaligus salinan referensi Anda, dan itu bernilai lebih daripada beberapa dolar biayanya. Lalu tutup dengan urutan ini: rotasi setiap secret yang bisa dibaca olehnya, ambil satu arsip terenkripsi terakhir ke lokasi ketiga, timpa direktori aplikasi dan database-nya, jalankan rutinitas destroy atau reinstall milik provider, dan baru batalkan — setelah mengecek tanggal perpanjangannya, karena satu bulan ekstra asuransi rollback biasanya trade yang lebih baik.

    Terakhir, kembalikan TTL ke 3600 sekarang karena Anda tidak lagi butuh reversibilitas lima menit, dan perbarui dokumentasi apa pun yang Anda simpan dengan alamat barunya. Anda di masa depan, pada suatu jam 2 dini hari nanti, akan sangat berterima kasih karena runbook-nya cocok dengan server yang sebenarnya.

Mail tidak ikut migrasi bersama yang lain

Kalau server lama mengirim mail — bahkan cuma untuk reset password — perlakukan itu sebagai migrasi kedua yang lebih lambat, berjalan berdampingan dengan migrasi utama. Deliverability adalah sistem reputasi, dan reputasi itu melekat pada alamat IP dan domain, bukan pada software yang Anda salin.

Empat record menentukan apakah mail Anda dibaca atau dibuang, dan tiga di antaranya berisi hal-hal yang berubah begitu servernya berubah:

  • SPF mendaftar siapa saja yang boleh mengirim mail atas nama domain Anda. Kalau punya Anda berisi literal ip4:, itu sekarang sudah salah. Tambahkan IP baru sebelum cutover dan hapus yang lama seminggu setelahnya — kedua alamat sama-sama diotorisasi selama beberapa hari tidak berbiaya apa pun dan menutupi masa tumpang tindihnya.
  • DKIM menandatangani pesan dengan sebuah private key. Salin key itu bersama konfigurasi lainnya dan selector-nya akan terus berfungsi. Kalau malah membuat key baru, Anda harus menerbitkan selector baru dan menunggunya, jadi salin saja kecuali Anda punya alasan untuk tidak melakukannya.
  • DMARC memberi tahu penerima apa yang harus dilakukan kalau dua hal di atas gagal. Kalau Anda memakai p=reject, SPF yang rusak selama masa transisi bukan cuma peringatan, itu penghapusan diam-diam. Pertimbangkan menurunkannya ke p=none untuk minggu migrasi dan mengembalikannya setelah selesai.
  • PTR adalah reverse record di atas. IP baru punya PTR generik sampai Anda memintanya diubah, dan beberapa provider besar langsung menolak mail dari nama reverse yang generik.

Ekspektasi yang jujur: IP yang benar-benar baru mulai tanpa reputasi sama sekali, dan itu tidak sama dengan reputasi yang baik. Volume-nya naik bertahap selama berhari-hari, bukan berjam-jam. Kalau mail itu penting bagi Anda, biarkan server lama tetap hidup dan mengirim selama seminggu setelah pindah, alih-alih beralih dalam satu langkah — dan kalau itu penting untuk bisnis Anda, relay khusus adalah jawaban yang lebih baik daripada kedua server itu.

Rollback tanpa membuatnya makin buruk

Inti dari rencana rollback bukan karena Anda memperkirakan akan memakainya. Intinya adalah dengan memilikinya, Anda bisa melakukan cutover dengan tenang jam 10 pagi, bukan dengan gugup jam 2 dini hari, dan ketenangan itulah yang sebenarnya mencegah kesalahan.

Rollback Anda sederhana, dan tetap sederhana persis selama database lama masih menjadi otoritas: kembalikan A record-nya. Dengan TTL 300 detik Anda pulih dalam lima menit. Jendela itu — antara saat beralih dan tulisan pertama yang cuma ada di server baru — adalah undo gratis Anda, dan itulah kenapa server lama tetap berjalan, tidak disentuh dan tidak dihapus, selama setidaknya seminggu.

Yang merusak semua ini adalah split-brain: tulisan yang mendarat di kedua mesin. Sekarang tidak ada satu pun database yang benar, dan menyelaraskannya secara manual lebih buruk daripada downtime apa pun yang tadinya ingin Anda hindari. Tiga kebiasaan ini mencegahnya sepenuhnya:

  • Masukkan aplikasi lama ke mode read-only atau maintenance di awal jendela waktu, alih-alih mempercayai DNS sudah berhenti mengirim traffic. DNS cuma petunjuk; layanan yang berhenti adalah fakta.
  • Setelah beralih, pantau access log server lama, bukan yang baru. Request yang masih tiba di situ adalah para pengunjung yang tersisa, dan begitu aliran itu berhenti, migrasinya benar-benar selesai. tail -f /var/log/nginx/access.log adalah satu-satunya tool yang dibutuhkan.
  • Begitu Anda menerima tulisan sungguhan pertama di server baru, rollback bukan lagi soal mengubah DNS — itu jadi soal restore. Sadari betul kapan Anda melewati batas itu, dan ucapkan itu keras-keras kalau Anda berdua yang mengerjakannya.

Tetapkan aturan berhenti untuk diri sendiri sebelum mulai: kalau stack barunya tidak melayani dengan benar dalam, katakanlah, tiga puluh menit, kembalikan record-nya, ambil kembali malam Anda, dan perbaiki tanpa ada jam yang berjalan. Migrasi jadi buruk ketika orang terus memaksa maju karena berbalik terasa seperti kegagalan. Padahal tidak; itu opsi yang murah, dan cuma tersedia untuk waktu yang benar-benar terbatas.

Dekomisioning: rotasi, hapus, verifikasi, baru batalkan

Seminggu setelah cutover, server lama adalah salinan lengkap, yang masih berjalan, tidak terawasi, dari data Anda, di atas infrastruktur yang sudah tidak lagi Anda perhatikan. Pada titik itu, server itu juga adalah mesin dengan patch paling tertinggal yang Anda miliki. Selesaikan pekerjaannya dengan urutan ini:

  • Rotasi semua yang bisa dibaca oleh server lama. Secret aplikasi, API token, password database, kredensial SMTP, signing secret webhook, password RPC wallet apa pun. Anggap saja sudah bocor, karena Anda tidak bisa membuktikan sebaliknya. Kalau Anda membuat SSH key baru khusus untuk migrasi, inilah saatnya authorized key lama dikeluarkan.
  • Ambil satu arsip terakhirsnapshot restic atau Borg yang terenkripsi ke target yang bukan salah satu dari kedua mesin itu. Anda akan membutuhkannya tepat satu kali, enam minggu kemudian, untuk sebuah berkas yang tidak ada yang ingat.
  • Timpa data-nya. Di VPS Anda tidak bisa memverifikasi media fisiknya, jadi lakukan apa yang bisa Anda lakukan: shred atau timpa direktori aplikasi dan database-nya, lalu biarkan rutinitas reinstall atau destroy milik provider berjalan. Enkripsi saat disimpan sejak awal adalah yang membuat ini murah; tanpanya, Anda bergantung pada kebijakan penghapusan milik orang lain.
  • Verifikasi, baru batalkan. Pastikan server baru sudah melayani semuanya selama seminggu penuh, termasuk cron bulanan yang tidak pernah dipikirkan siapa pun, dan pastikan tidak ada apa pun di server lama yang masih ter-resolve. Baru batalkan — dan cek dulu tanggal perpanjangannya, karena membayar satu bulan ekstra sebagai asuransi rollback sering kali lebih cerdas daripada menghemat delapan dolar.

Hapus akun lamanya sendiri paling akhir, dan cuma setelah Anda benar-benar yakin. Tiket support, invoice, dan sub-layanan aneh yang terlupakan cenderung ada di situ, dan akun yang tidak bisa Anda login lagi adalah tempat yang canggung untuk menyadari ada DNS record yang lupa Anda pindahkan.

Linimasa yang benar-benar berhasil

Kalau disebar dalam satu minggu, semua ini tidak menegangkan. Kalau dipadatkan dalam satu malam, semuanya jadi menegangkan.

  • Hari −7. Turunkan semua TTL ke 300. Lakukan inventarisasi server lama. Pesan server baru dan cek IP-nya, rDNS-nya, dan rute-nya.
  • Hari −5. Harden server baru. Instal stack-nya. rsync penuh pertama, yang paling lambat — setiap pass berikutnya cuma memindahkan delta-nya.
  • Hari −3. Restore dump database ke server baru dan nyalakan aplikasinya. Uji semuanya lewat hosts-file override. Perbaiki apa yang rusak selagi belum ada yang dipertaruhkan, karena nanti pasti ada.
  • Hari −1. Terbitkan TLS di server baru. Pastikan certificate chain-nya, dan kalau Anda memakainya, pastikan HSTS tidak mengubah kesalahan kecil jadi sesuatu yang tidak bisa diklik. Tambahkan IP baru ke SPF. Cek ulang bahwa semua TTL benar-benar sudah turun.
  • Hari 0, pagi. Mode maintenance di server lama. Sinkronisasi delta terakhir. Dump dan restore terakhir. Cek row-count. Alihkan A record — dan AAAA-nya. Pantau kedua access log.
  • Hari +1 sampai +7. Server lama tetap hidup, tidak disentuh. Pantau log, mail, dan reputasi IP baru. Biarkan job bulanan berjalan setidaknya sekali kalau bisa.
  • Hari +7. Rotasi secret, arsip terakhir, hapus, verifikasi, batalkan.

Prediktor tunggal terbaik dari migrasi yang membosankan adalah bahwa langkah satu terjadi seminggu sebelum langkah lima. Hampir semua yang salah dalam proses pindah server adalah TTL yang masih 86400 pada jam sebelas malam.

Pertanyaan yang sering diajukan

Apakah migrasi VPS benar-benar bisa zero downtime?

Zero yang benar-benar harfiah, dengan tulisan diterima terus-menerus di kedua mesin, membutuhkan replikasi dan database yang shared atau clustered — masalah yang sungguh-sungguh sulit, dan salah untuk dipecahkan demi satu server saja. Yang bisa dicapai, secara andal, adalah tidak ada pengunjung yang melihat error dan tidak ada tulisan yang hilang: sebuah jendela read-only singkat selama sync terakhir, dengan DNS yang sudah memakai TTL 300 detik supaya peralihannya sendiri cuma butuh beberapa menit. Dalam praktiknya itu satu sampai lima menit halaman maintenance, yang untuk hampir semua situs tidak bisa dibedakan dari zero dan jauh lebih aman daripada alternatifnya.

Berapa lama propagasi DNS sebenarnya berlangsung?

Tidak ada propagasi. Tidak ada yang didorong ke mana pun — resolver cuma meng-cache record Anda selama sejumlah detik yang ditentukan TTL Anda, lalu bertanya lagi begitu itu kedaluwarsa. Jadi jawaban yang jujur adalah “selama TTL yang berlaku pada saat Anda membuat perubahan itu”. Dengan TTL 300 yang diatur seminggu sebelumnya, hampir semua orang sudah berada di alamat baru dalam lima menit. Dengan 86400 yang masih jadi default banyak registrar, sebagian resolver terus mengirim traffic ke server lama selama satu hari penuh. Inilah kenapa menurunkan TTL adalah langkah satu, bukan langkah sembilan.

Bisakah saya mempertahankan alamat IP saya saat pindah host?

Tidak bisa, kecuali Anda sendiri memiliki address space-nya dan bisa membuatnya diumumkan oleh provider baru, yang berarti menjadi member RIPE atau ARIN dengan alokasi milik sendiri — realistis untuk sebuah perusahaan, bukan untuk satu server saja. Untuk semua orang lainnya, host baru berarti IP baru, dan itulah persisnya kenapa Anda mengecek reputasi dan reverse DNS-nya sebelum cutover, bukan sesudahnya. Di sisi kami, alamat-alamatnya disaring terhadap Spamhaus dan seratus lebih daftar lainnya serta diterbitkan dari pool yang disegmentasi berdasarkan risiko, bukan didaur ulang dari siapa pun pemilik terakhirnya, tapi memverifikasinya sendiri cuma butuh lima menit dan selalu layak dilakukan.

Sebaiknya saya pakai disk image atau tool migrasi dari provider saja?

Kalau kedua sisinya adalah provider dan hypervisor yang sama, restore image itu tidak masalah dan jauh lebih cepat. Antar provider yang berbeda, itu biasanya jadi jebakan: image-nya membawa konfigurasi jaringan, kernel module, driver, dan asumsi hardware milik mesin lama, dan Anda menghabiskan malam Anda men-debug sebuah sistem yang boot ke mesin yang sudah tidak ada lagi. Instalasi bersih ditambah salinan data dan konfigurasi Anda yang dipikirkan matang-matang memberi Anda server yang benar-benar Anda pahami, dan membuang sampah yang menumpuk dari yang lama. Migrasi adalah kesempatan termurah yang akan pernah Anda dapatkan untuk meninggalkan hal-hal itu di belakang.

Bagaimana dengan database yang terus-menerus ditulisi?

Dua opsi, diurutkan dari yang paling ringan usahanya. Yang sederhana adalah jendela read-only di langkah sembilan: dump --single-transaction dari sebuah database yang sibuk tapi berukuran normal cuma butuh beberapa detik sampai beberapa menit, dan halaman maintenance selama itu adalah trade yang wajar. Yang menyeluruh adalah replikasi — siapkan server baru sebagai replica berhari-hari sebelumnya, biarkan itu tetap sinkron, lalu promosikan itu selama jendela waktunya. Itu mengurangi masa beku jadi cuma beberapa detik, dengan konsekuensi setup yang sungguh-sungguh lebih kompleks. Pilih opsi kedua cuma kalau opsi pertama tidak bisa diterima, dan jangan pernah mengimprovisasinya di malam harinya.

Apakah pindah host akan merusak peringkat pencarian saya?

Tidak dengan sendirinya. Google mengindeks hostname, bukan alamat IP, dan sebuah perpindahan di mana URL dan konten tetap identik sebenarnya tidak terlihat sama sekali. Yang benar-benar merugikan Anda adalah hal-hal yang cenderung menyertai migrasi yang buruk: halaman yang mengembalikan 5xx selagi crawler sedang berkunjung, error sertifikat, sebuah robots.txt yang datang dari salinan staging dengan Disallow: / di dalamnya, atau redirect yang diam-diam berubah bentuk. Cek robots.txt, canonical tag Anda, dan segelintir URL sungguhan segera setelah beralih. Kalau situsnya melayani respons yang sama di IP baru seperti di IP lama, tidak ada apa pun yang perlu dipulihkan.

Apakah sertifikat TLS saya masih berfungsi di server baru?

Ya — sertifikat diterbitkan untuk nama domain, bukan alamat IP, jadi menyalin /etc/letsencrypt langsung memberi Anda sertifikat yang valid di server baru. Yang rumit adalah renewal-nya, bukan validitasnya: HTTP-01 challenge membutuhkan domainnya menunjuk ke mesin yang sedang melakukan renewal, jadi sampai Anda mengalihkan DNS, renewal di situ akan gagal. Salin sertifikatnya sebelum cutover, alihkan, lalu pastikan timer renewal-nya berjalan sukses di server baru. Kalau Anda butuh sertifikat independen sebelum beralih — atau sebuah wildcard — pakai DNS-01 challenge sebagai gantinya.

Deploy VPS offshore dalam waktu sekitar satu menit

Tanpa KYC, dibayar kripto, semua NVMe. Pilih paket, bayar dengan Monero atau koin besar lainnya, dapatkan root dalam sekitar 60 detik.

Fenrir berjaga