SSD Nodes Learn 🎉 VPS $5.50/মাস থেকে
নির্দেশিকা Matt Connorদ্বারা Matt Connor

নতুন VPS-এ সার্ভার স্থানান্তরের সঠিক পদ্ধতি

লাইভ সার্ভার নতুন VPS-এ নিন মহড়া করা cutover হিসেবে: আগে DNS TTL কমান, clone না করে rebuild করুন, database dump ও দুইবার sync করে verify করার পর DNS বদলান।

নতুন VPS-এ সার্ভার স্থানান্তরকে মহড়া করা cutover হিসেবে সম্পন্ন করুন

নতুন VPS-এ সার্ভার স্থানান্তর করতে হলে এটিকে শুধু কপি না করে মহড়া করা cutover হিসেবে পরিচালনা করুন। নতুন সার্ভারটি শুরু থেকে তৈরি করুন, ডেটা দুইবার sync করুন, DNS পরিবর্তনের আগে নতুন সার্ভারটি নিজের IP address-এ স্বতন্ত্রভাবে কাজ করছে প্রমাণ করুন, তারপর DNS record পরিবর্তন করুন এবং নিশ্চিত না হওয়া পর্যন্ত পুরোনো সার্ভারটি চালু রাখুন। ফাইল কপি করাই সহজ অংশ। কাজের সঠিক ক্রম বজায় রাখলেই স্থানান্তরটি নির্বিঘ্ন হবে, নতুবা খরচ বেড়ে যেতে পারে।

এই নির্দেশিকায় একটি Linux server, একটি web application, একটি database এবং একটি TLS (transport layer security) certificate চালানো একক সার্ভারের কথা বলা হয়েছে। অধিকাংশ single-server setup-এর জন্য এটি যথেষ্ট। এখানে দুটি host জড়িত, তাই প্রতিটি উদাহরণের comment-এ সেটি কোন host-এ চালাতে হবে তা উল্লেখ করা আছে। ঠিকানাগুলো documentation range থেকে নেওয়া হয়েছে: 198.51.100.10 হলো পুরোনো server, 203.0.113.20 হলো নতুন server।

শুরু করার আগে সম্পূর্ণ runbook পড়ুন। প্রথম ধাপ, DNS TTL কমানো, আপনি যে ধাপটি নিয়ে আসলে কাজ করছেন তার কয়েক দিন আগেই সম্পন্ন করতে হবে।

আপনি কিছু তৈরি করার আগে সম্পূর্ণ তালিকা তৈরি করুন

যে সার্ভারের বিবরণ আপনার কাছে নেই, সেটি পুনর্নির্মাণ করতে পারবেন না। পুরোনো সার্ভারটি কী কাজ করে তা লিখে রাখতে এক ঘণ্টা সময় দিন। কারণ migration-এর পরে যে জিনিসটি প্রায়ই নষ্ট হয়, সেটিই সাধারণত কেউ মনে রাখেনি: একটি cron job, একটি firewall exception, অথবা application directory-এর বাইরে থাকা একটি environment file।

পুরোনো সার্ভারে এগুলো চালান এবং output এমন কোথাও সংরক্ষণ করুন, যেখান থেকে নতুন সার্ভারে তা পড়তে পারবেন।

# 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 তালিকাটি রাখা দরকার, কারণ এতে dependency হিসেবে আসা সবকিছু দেখা যায়। পাঁচ বছর পুরোনো সার্ভারে সম্পূর্ণ dpkg --get-selections চালালে দুই হাজার লাইন output আসতে পারে, কিন্তু কোন package কেন ইনস্টল করা হয়েছিল তা বোঝা যায় না।

Scheduled কাজ দুটি জায়গায় থাকতে পারে, তাই দুটিই পরীক্ষা করুন। মাসে মাত্র একবার চলা job-টিই 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

এরপর সাধারণ file নয় এমন বিষয়গুলো পরীক্ষা করুন: firewall rule, certificate, database এবং আপনি বাস্তবে কত data স্থানান্তর করছেন।

# 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 প্রতিটি certificate-এর নাম, certificate-টি কোন domain কভার করে, expiry date এবং disk-এ থাকা file-এর path দেখায়। এই output-কে TLS checklist হিসেবে ব্যবহার করুন। du -x একই filesystem-এর মধ্যে সীমাবদ্ধ থাকে। তাই এটি mounted backup volume-এর ভেতরে গিয়ে এমন কোনো সংখ্যা দেখাবে না, যা প্রকৃত সংখ্যার দশ গুণ বেশি।

দুটি বিষয় সার্ভারের বাইরে থাকে এবং প্রতিবারই বাদ পড়ে যায়। প্রথমত, যে third party আপনার server-এর IP address allowlist করে: payment gateway, managed database, SMTP relay অথবা partner API। নতুন সার্ভারের address নতুন হবে। তাই cutover-এর আগে allowlist-এ নতুন IP যোগ করুন, পরে নয়। দ্বিতীয়ত, এমন DNS record যেগুলো আপনি নিজে তৈরি করেননি। যেমন একটি MX record, অথবা text-এর মধ্যে পুরোনো IP উল্লেখ করা একটি SPF record।

পুরোনো root filesystem ক্লোন না করে কেন পুনর্নির্মাণ করবেন

পুরো root filesystem নতুন VPS-এ ক্লোন করলে কাজটি দ্রুত মনে হয়। শুরুতে সত্যিই দ্রুত হয়। তবে সব সময় নয়। বহু বছর production-এ থাকা একটি root filesystem-এ এমন হাতে সম্পাদিত configuration থাকে, যার কোনো documentation নেই। এতে এমন repository-এর package-ও থাকতে পারে, যা আর নেই। এ ছাড়া পুরোনো platform-এর virtual hardware অনুযায়ী তৈরি boot setup-ও থাকে। আপনি এসবের সবই import করবেন, এমনকি যে সমস্যার কারণে migration করছেন সেটিও।

প্রথম দিনে পুনর্নির্মাণ ধীর। তবে এরপর প্রতিদিন এর খরচ কমে। আপনি বর্তমান release install করবেন এবং প্রাথমিক hardening প্রয়োগ করবেন। এরপর শুধু data কপি করবেন: application directory, site config, database dump, certificate এবং user upload। যে বিষয় ব্যাখ্যা করতে পারবেন না, তা নতুন সিস্টেমে নেওয়া হবে না। নতুন box-টি যেভাবে যেকোনো box শুরু করতেন, সেভাবেই শুরু করুন—নতুন VPS-এ প্রথম দশ মিনিট দিয়ে। এরপর inventory অনুযায়ী একবারে একটি করে service যোগ করুন এবং পরেরটি যোগ করার আগে প্রতিটি service নিশ্চিতভাবে কাজ করছে কি না যাচাই করুন।

কখন image বা snapshot restore করা সঠিক সিদ্ধান্ত

Rebuild করার একটি বাস্তব ব্যতিক্রম আছে। পুরোনো সার্ভার boot না করলে, অথবা application-টির source থেকে পুনর্নির্মাণ আর সম্ভব না হলে, provider image বা snapshot restore করা বাস্তবসম্মত সমাধান। এর কিছু গুরুত্বপূর্ণ সীমাবদ্ধতা আছে। এটি একটি provider-এর পরিবেশের মধ্যেই কাজ করে, এবং অনেক সময় শুধু একটি plan family-এর মধ্যেই প্রযোজ্য। কারণ restored disk সেই platform-এর virtual device এবং network naming-এর ওপর নির্ভর করে।

চলমান server-এর snapshot-এ live database-এর অন্য যেকোনো file-level copy-এর মতো একই consistency সমস্যা থাকে। Image restore-কে migration plan নয়, recovery route হিসেবে বিবেচনা করুন। কোনো পরিকল্পনা snapshot-এর ওপর ভিত্তি করে তৈরি করার আগে কেন snapshot backup-এর সমতুল্য নয় পড়ুন।

ফাইল কীভাবে স্থানান্তরিত হয়: SSH-এর মাধ্যমে rsync

পুরোনো সার্ভার থেকে rsync চালিয়ে নতুন সার্ভারে ডেটা পাঠান। সাধারণত push পদ্ধতি সহজ, কারণ ডেটা পুরোনো সার্ভারেই রয়েছে এবং সেখানে 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/

Flag-গুলো গুরুত্বপূর্ণ। -a permission, timestamp, symbolic link এবং ownership সংরক্ষণ করে। -H hard link-কে আলাদা copy-তে রূপান্তর না করে hard link হিসেবেই রাখে। -A POSIX ACL (access control list) copy করে এবং -X extended attribute copy করে। শেষের এই দুইটি ছাড়া দেখতে একই রকম কোনো ফাইল ভিন্নভাবে কাজ করতে পারে, কারণ SELinux label এবং ACL extended attribute-এ সংরক্ষিত থাকে এবং অন্য কোনো তথ্য সেগুলো ধরে রাখে না।

এখানে বেশির ভাগ ব্যর্থতার কারণ দুটি বিষয়।

শেষের slash ডেটা কোথায় যাবে তা নির্ধারণ করে। /srv/app/ মানে ওই directory-এর ভেতরের contents। /srv/app মানে directory-টি নিজেই। ভুল হলে নতুন সার্ভারে /srv/app/app তৈরি হবে। এরপর application শুরু হয়ে missing file-এর error দেবে, কারণ configuration-এ নির্ধারিত path এখন এক স্তর বেশি গভীরে চলে গেছে।

sudo-এর অধীনে tilde হলো root-এর home directory। sudo rsync-এর ভেতরে -e 'ssh -i ~/.ssh/id_ed25519' লিখলে key-টি আপনার নিজের home directory-তে নয়, /root/.ssh-এ খোঁজা হবে। সেখানে key না থাকলে SSH Permission denied (publickey) দেখাবে, rsync rsync: connection unexpectedly closed দেখিয়ে non-zero status-এ বন্ধ হবে। Key path সম্পূর্ণভাবে লিখুন। Path ঠিক করার পরও authentication message দেখা গেলে publickey ব্যর্থতার সম্ভাব্য কারণের তালিকা সংক্ষিপ্ত; এরপর নতুন সার্ভারের directory permission পরীক্ষা করুন।

Ownership-এর ক্ষেত্রে একটি সিদ্ধান্ত নিতে হবে। root হিসেবে চালালে rsync default-ভাবে owner এবং group-এর নাম অনুযায়ী mapping করে। তাই পুরোনো সার্ভারে www-data-এর মালিকানাধীন ফাইল নতুন সার্ভারে www-data-এর মালিকানাধীন হবে, যদিও numeric UID (user ID) আলাদা। Rebuild-এর ক্ষেত্রে এটিই সাধারণত প্রত্যাশিত। শুধু তখনই --numeric-ids যোগ করুন, যখন এমন filesystem copy করছেন যার account target-এ নেই। এরপর ls -ln দিয়ে ফলাফল পরীক্ষা করুন। কোনো matching account না থাকা UID-এর মালিকানাধীন ফাইল শুধু একটি সংখ্যা হিসেবে দেখাবে এবং সেটি পড়তে চাওয়া প্রতিটি service access denied পাবে।

পুরোনো সার্ভার এখনও network traffic পরিবেশন করার সময়, কয়েক দিন আগে bulk pass চালান। যতবার ইচ্ছা এটি পুনরায় চালাতে পারেন। rsync শুধু পরিবর্তিত ডেটা পাঠায়, তাই দ্বিতীয় pass ঘণ্টার বদলে কয়েক মিনিটে শেষ হয়। Cutover window-এর মধ্যে final pass চালানোর সময় --delete যোগ করুন, যাতে পুরোনো সার্ভার থেকে মুছে যাওয়া ফাইল নতুন সার্ভার থেকেও মুছে যায়।

# 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 source-এ না থাকা ফাইল destination থেকে মুছে দেয়। তাই ভুল source path-এর সঙ্গে --delete ব্যবহার করলে destination directory খালি হয়ে যেতে পারে। প্রতিবার প্রথমে --dry-run দিয়ে চালান। Laptop-এর SSH session বিচ্ছিন্ন হলেও দীর্ঘ transfer বন্ধ হয়ে যায়। তাই পুরোনো সার্ভারে tmux অথবা screen-এর ভেতরে transfer শুরু করুন। পুরোনো সার্ভার এখনও user-দের service দেওয়ার সময় copy link সম্পূর্ণ ব্যবহার করে ফেললে --bwlimit=20M যোগ করুন।

ডেটাবেস কীভাবে স্থানান্তরিত হয়: native dump

ডেটাবেস শুধু ফাইলের কোনো directory নয়, যদিও দেখতে তেমন মনে হয়। এটি ফাইল, memory-তে থাকা state এবং write-ahead log-এর সমন্বয়; কেবল ডেটাবেস নিজে নির্ধারিত নির্দিষ্ট মুহূর্তগুলোতেই এটি consistent থাকে। তাই ডেটাবেসের নিজস্ব tool ব্যবহার করুন।

PostgreSQL-এর জন্য দুটি dump প্রয়োজন, কারণ role-গুলো cluster-wide এবং pg_dump সেগুলো অন্তর্ভুক্ত করে না:

# 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

globals.sql বাদ দিলে সব table restore হবে, কিন্তু কোনো application role সেগুলো পড়তে পারবে না। কারণ GRANT statement এমন user-কে নির্দেশ করে, যে user-এর অস্তিত্ব নেই। -Fc custom archive format লেখে। এই format শুধু pg_restore পড়তে পারে এবং পরে নির্বাচিত table restore করার সুবিধা দেয়। একই major version বা তার চেয়ে নতুন version-এ restore করুন। উল্টো দিকে, যেমন 17 থেকে 16-এ যাওয়া, supported নয়। কোনো data লেখার আগেই pg_restore file header-এ unsupported-version error দেখিয়ে archive প্রত্যাখ্যান করে।

MySQL এবং MariaDB একটি command ব্যবহার করে, যাতে default হিসেবে সক্রিয় নয় এমন চারটি option দিতে হয়:

# 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 writer-দের block না করে একটি consistent snapshot নেয়, তবে এটি শুধু InnoDB table-এর ক্ষেত্রে প্রযোজ্য। একই database-এর MyISAM table-এ এই নিশ্চয়তা ছাড়াই copy নেওয়া হয়। তাই dump-কে বিশ্বাস করার আগে storage engine পরীক্ষা করুন। --routines, --triggers এবং --events default হিসেবে বন্ধ থাকে। এর অর্থ, সাধারণ dump আপনার data restore করলেও stored procedure এবং scheduled event নীরবে বাদ পড়ে যায়। Database user এবং তাদের grant-গুলো mysql system database-এ থাকে। --databases appdb dump এই database কখনো অন্তর্ভুক্ত করে না। তাই নতুন server-এ CREATE USER এবং GRANT ব্যবহার করে সেগুলো পুনরায় তৈরি করুন। MariaDB 11 একই tool-কে mariadb-dump হিসেবে সরবরাহ করে এবং mysqldump-কে symbolic link হিসেবে রাখে। তাই August 2026 অনুযায়ী যেকোনো নাম ব্যবহার করা যায়।

SQLite একটি single file ব্যবহার করে। Application লেখার সময় সেটি copy করলে file অসম্পূর্ণ অবস্থায় copy হতে পারে। এর জন্য নিজস্ব নিরাপদ পদ্ধতি রয়েছে:

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

যে engine-ই ব্যবহার করুন, dump-কে বিশ্বাস করার আগে তা পরীক্ষা করুন। Disk পূর্ণ হয়ে যাওয়ার কারণে মাঝপথে থেমে যাওয়া dump কোনো error ছাড়াই restore হতে পারে, তবে কেবল যত দূর পর্যন্ত dump লেখা হয়েছিল তত দূর পর্যন্ত।

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

চলমান database-এ কেন rsync ব্যবহার করা যায় না

rsync ফাইল ধরে ধরে কপি করে। চলমান database একই সময়ে একাধিক ফাইলে লিখতে পারে। তাই rsync শেষ ফাইলে পৌঁছানোর আগেই প্রথম ফাইলটি পুরোনো হয়ে যায়। কপিটিতে ভিন্ন ভিন্ন সময়ের page থাকে। database কখনো এমন অবস্থায় ছিল না। ফলাফল হয় এমন server, যা start হতে অস্বীকার করে। আরও খারাপ ক্ষেত্রে server start হয়, এক সপ্তাহ সঠিক উত্তর দেয়, তারপর কোনো query ক্ষতিগ্রস্ত page-এ পৌঁছালে ব্যর্থ হয়। এর আগে কোনো সতর্কতা দেখা যায় না।

নিজস্ব file সরানোর দুটি নিরাপদ উপায় আছে। database বন্ধ করে কপি করুন, তারপর আবার start করুন। এটি সঠিক ও সহজ, তবে copy শেষ না হওয়া পর্যন্ত downtime থাকবে। অথবা চলমান server-এর physical copy তৈরির জন্য ব্যবহৃত tool ব্যবহার করুন। PostgreSQL-এর ক্ষেত্রে সেটি হলো pg_basebackup। এটি server-এর সঙ্গে সমন্বয় করে consistent copy তৈরি করে:

# 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

এর জন্য REPLICATION attribute-সহ একটি role এবং পুরোনো server-এ সামঞ্জস্যপূর্ণ pg_hba.conf entry প্রয়োজন। তাই dump-এর তুলনায় এর setup বেশি। database এত বড় হলে এটি উপযোগী, যখন dump ও restore আপনার নির্ধারিত maintenance window-এর মধ্যে শেষ করা সম্ভব নয়। সাধারণ single-server migration-এর ক্ষেত্রে dump-ই ভালো পদ্ধতি।

Cutover-এর আগে certificate পুনর্নির্মাণ করুন, পরে নয়

TLS certificate IP address-এর সঙ্গে নয়, domain name-এর সঙ্গে যুক্ত থাকে। তাই certificate file নিজে স্থানান্তর করতে সমস্যা হয় না। তবে renewal নির্বিঘ্নে স্থানান্তরিত হয় না। Certbot-এর default HTTP-01 challenge certificate authority-কে certified name-এর port 80-এ একটি file আনতে বলে। DNS নতুন server-কে নির্দেশ না করা পর্যন্ত সেই request পুরোনো server-এ যায়। ফলে নতুন server-এর renewal ব্যর্থ হয়।

প্রথম বিকল্প হলো বিদ্যমান certificate এবং তার renewal state কপি করা। যে server-এই এগুলো রাখা হোক, expiry date পর্যন্ত এগুলো বৈধ থাকে।

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

/etc/letsencrypt/renewal/-এর প্রতিটি file certificate issue করা authenticator plugin-এর নাম উল্লেখ করে। তাই নতুন server-এ একই plugin ইনস্টল করুন, যেমন python3-certbot-nginx। তা না হলে unknown authenticator সংক্রান্ত message দেখিয়ে প্রথম renewal ব্যর্থ হবে। এর ওপর নির্ভর করার আগে renewal কাজ করছে কি না যাচাই করুন:

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

দ্বিতীয় বিকল্প হলো DNS-01 challenge ব্যবহার করে নতুন server-এ নতুন certificate issue করা। এই challenge একটি TXT record-এর মাধ্যমে নিয়ন্ত্রণের প্রমাণ যাচাই করে এবং port 80 ব্যবহার করে না। Migration-এর আগেই এটি কাজ করে, যখন name এখনও পুরোনো server-এ resolve হয়। তাই DNS provider স্বয়ংক্রিয়ভাবে পরিচালনা করতে পারলে এটি বেশি উপযুক্ত। DNS-01 challenge ব্যবহার করে certificate issue করা-এ plugin ও credential configuration-এর বর্ণনা আছে।

যে বিকল্পই ব্যবহার করুন, DNS পরিবর্তন না করেই নতুন server আসলে কী উপস্থাপন করছে তা পরীক্ষা করুন:

# 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 SNI (server name indication) পাঠায়। এর মাধ্যমে web server সঠিক virtual host নির্বাচন করে। এটি বাদ দিলে ওই IP-এর default certificate পাওয়া যায় এবং একটি mismatch দেখা যায়। এটি বাস্তব সমস্যা মনে হলেও আসলে তা নয়।

কাটওভারের কয়েক দিন আগে DNS TTL কমান

সতর্কভাবে করা migration-ও DNS-এর কারণে ব্যর্থ হতে পারে, কারণ এতে বিল্ট-ইন বিলম্ব থাকে এবং কাটওভারের দিন সেটি কমানো যায় না। কোনো resolver আপনার A record cache করে রাখলে, তাকে দেওয়া TTL (time to live) শেষ না হওয়া পর্যন্ত সে পুরোনো record-ই সরবরাহ করতে থাকে। এখন TTL কমালেও যে resolver দশ মিনিট আগে পুরোনো মানে record cache করেছে, তার ক্ষেত্রে কোনো পরিবর্তন হবে না: পুরোনো TTL-এর অবশিষ্ট সময় পর্যন্ত সে পুরোনো মান ধরে রাখবে, তারপর নতুন এবং কম TTL শিখবে। তাই কাটওভারের অন্তত একটি পূর্ণ পুরোনো-TTL সময় আগে TTL কমান। এক দিন আগে কমানো সবচেয়ে নিরাপদ পদ্ধতি। এই বিষয়গুলোর কোনোটি নতুন হলে, records, resolvers এবং caching-এর walkthrough-এ পটভূমির ব্যাখ্যা আছে।

নিচের সংখ্যাগুলো TTL থেকেই হিসাব করা হয়েছে; এগুলো কোনো পরিমাপের ফল নয়।

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

3600 সেকেন্ড TTL-সহ প্রকাশিত একটি record পরিবর্তনের পরও 60 মিনিট পর্যন্ত ব্যবহারকারীদের পুরোনো IP-তে পাঠাতে পারে। TTL কমিয়ে 300 সেকেন্ড করলে worst case কমে 5 মিনিট হবে। এই সংখ্যাগুলোকে ন্যূনতম সময় হিসেবে ধরুন, নিশ্চয়তা হিসেবে নয়। কিছু resolver নিজেদের নির্ধারিত minimum TTL প্রয়োগ করে এবং তার চেয়ে কম মান উপেক্ষা করে। কিছু application runtime process চলার পুরো সময় resolved address cache করে রাখে। তাই পরিবর্তনের আগে শুরু হওয়া কোনো client restart না হওয়া পর্যন্ত আবার DNS lookup নাও করতে পারে।

কম TTL কার্যকর হয়েছে কি না যাচাই করার সময় নিজের cache নয়, authoritative answer পড়ুন:

# 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

ওই answer line-এর দ্বিতীয় field-এ TTL সেকেন্ডে দেওয়া থাকে। এরপর যেসব record মানুষ প্রায়ই ভুলে যায়, সেগুলো যাচাই করুন: পুরোনো server-এ IPv6 থাকলে AAAA record, www name-টি আলাদা A record হলে সেটি, CNAME না হলে সংশ্লিষ্ট record, server নিজেকেই নির্দেশ করা কোনো MX record, পুরোনো IP তালিকাভুক্ত SPF record এবং নতুন address-এর reverse DNS (PTR) record। server mail পাঠালে কাটওভারের আগে provider-এর control panel থেকে PTR সেট করুন। Receiving mail server-গুলো এটি পরীক্ষা করে, এবং PTR না থাকলে অন্য সবকিছু ঠিক দেখানোর কয়েক ঘণ্টা পরেও mail প্রত্যাখ্যাত হতে পারে।

DNS পরিবর্তন করার আগে IP ঠিকানায় নতুন সার্ভার যাচাই করুন

DNS এখনও পুরোনো সার্ভারের দিকে নির্দেশ করলেও আপনি নতুন সার্ভারে পুরো অ্যাপ্লিকেশন পরীক্ষা করতে পারেন। একটি অনুরোধের জন্য name lookup override করুন:

# 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 শুধু connection কোথায় যাবে তা পরিবর্তন করে। TLS certificate এখনও প্রকৃত name-এর বিপরীতে যাচাই করা হয়। তাই এতে certificate এবং service—দুটিই যাচাই হয়। chain যাচাই সফল হলে %{ssl_verify_result}, 0 প্রিন্ট করে।

ব্রাউজারে site-এর বিভিন্ন অংশ পরীক্ষা করতে পুরো machine-এর জন্য name override করুন। আপনার laptop-এ /etc/hosts ফাইলে, অথবা Windows-এ C:\Windows\System32\drivers\etc\hosts ফাইলে একটি line যোগ করুন:

203.0.113.20 example.com www.example.com

এরপর একজন user যেভাবে ব্যবহার করবে, সেভাবে application পরীক্ষা করুন। Log in করুন। Database থেকে data পড়ে এমন একটি page load করুন। Database-এ data লেখে এমন একটি form submit করুন। একটি file upload করে নিশ্চিত করুন যে সেটি disk-এ সঠিকভাবে সংরক্ষিত হয়েছে। Email পাঠায় এমন প্রতিটি workflow চালান এবং email পৌঁছেছে কি না পরীক্ষা করুন। নতুন IP থেকে outbound SMTP অনেক সময় অপ্রত্যাশিত সমস্যা তৈরি করে। পরীক্ষা শেষ হওয়ার সঙ্গে সঙ্গে hosts line-টি সরিয়ে ফেলুন। এটি রেখে দিলে এমন একটি site debug করতে আপনার এক ঘণ্টা চলে যেতে পারে, যা অন্য সবাই ঠিকভাবেই দেখতে পাচ্ছে।

ধাপে ধাপে cutover

  1. কয়েক দিন আগে: TTL কমিয়ে দিন, bulk rsync চালান, নতুন সার্ভার প্রস্তুত করুন এবং hosts override ব্যবহার করে সেটি পরীক্ষা করুন।
  2. নির্ধারিত দিনের window শুরুর আগে: প্রতিটি third-party allowlist-এ নতুন IP যোগ করুন এবং নিশ্চিত করুন যে নতুন সার্ভারের backup job কনফিগার করা আছে ও আপনার repository-তে নির্দেশ করছে।
  3. window শুরু করুন: পুরোনো সার্ভারে application-কে maintenance mode-এ রাখুন, যাতে সেটি আর write গ্রহণ না করে।
  4. চূড়ান্ত database dump নিন, তারপর --delete ব্যবহার করে চূড়ান্ত rsync pass চালান।
  5. নতুন সার্ভারে dump restore করুন এবং service-গুলো চালু করুন।
  6. --resolve ও hosts override ব্যবহার করে আবার পরীক্ষা করুন। এর মধ্যে একটি প্রকৃত write-ও অন্তর্ভুক্ত করুন।
  7. A এবং AAAA record নতুন IP-তে পরিবর্তন করুন।
  8. উভয় সার্ভার monitor করুন। পুরোনো সার্ভারের access log-এ এখনও কারা সেখানে আসছে তা দেখা যাবে, এবং TTL শেষ হওয়ার দিকে সংখ্যাটি শূন্যের কাছাকাছি নামা উচিত।
  9. maintenance page সরিয়ে দিন।
  10. পুরোনো সার্ভারটি অন্তত এক সপ্তাহ চালু ও অপরিবর্তিত রাখুন।

Maintenance mode-এর ধাপটি মানুষ প্রায়ই বাদ দেয়। অথচ এটিই আপনাকে সুরক্ষিত রাখে। নতুন database একটি write গ্রহণ করার পর rollback করতে গেলে হয় সেই write হারাতে হবে, নয়তো নতুন database dump করে সেটি পুরোনোটিতে আবার load করতে হবে। কয়েক মিনিটের read-only window-এর খরচ কম। কিন্তু দুটি database-ই write গ্রহণ করলে সেগুলোর তথ্য manual reconciliation করতে কয়েক দিন লাগতে পারে।

রোলব্যাক পরিকল্পনা

রোলব্যাক একটি কাজেই সম্পন্ন হয়: DNS record আবার 198.51.100.10-এ পরিবর্তন করুন। এটি কাজ করে, কারণ আগে আপনি চারটি বিষয় নিশ্চিত করেছিলেন।

  • পুরোনো সার্ভারটি এখনও চালু আছে, তার service-গুলো সক্রিয় এবং data অক্ষত। সেখানে write বন্ধ করেছেন, কিন্তু সার্ভারটি decommission করেননি।
  • TTL এখনও কম, তাই ফিরে যাওয়ার গতি forward পরিবর্তনের সময়ের মতোই দ্রুত।
  • পুরোনো IP প্রতিস্থাপন না করে third-party allowlist-এ নতুন IP যোগ করেছেন। পুরোনো address সরিয়ে দিলে payment gateway-এ rollback path ব্যর্থ হবে।
  • নতুন সার্ভারে এমন কোনো write হয়নি যা আপনি শনাক্ত করতে পারবেন না, কারণ এখন পর্যন্ত একমাত্র write ছিল আপনার নিজের test transaction।

window শুরু হওয়ার আগেই নির্ধারণ করুন, কোন পরিস্থিতিতে rollback করবেন। দুটি trigger যথেষ্ট: নির্ধারিত কয়েক মিনিটের মধ্যে diagnose করতে না-পারা যেকোনো error, এবং যেকোনো data loss। এগুলো আগে লিখে রাখলেই অনুমান করে সময় নষ্ট করা ঠেকানো যায়; না হলে দশ মিনিটের outage দীর্ঘস্থায়ী হতে পারে।

মাইগ্রেশন সফল হয়েছে কি না যাচাই করুন

সাইট লোড হলেই মাইগ্রেশন শেষ হয় না। পরে ব্যর্থ হতে পারে এমন বিষয়গুলোও পরীক্ষা করুন।

# 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 হলো আপনার কাঙ্ক্ষিত ফলাফল। certbot certificates-এ প্রত্যাশিত expiry date দেখা উচিত, এবং list-timers-এ আপনার inventory-র প্রতিটি scheduled job-এর প্রকৃত next-run time দেখা উচিত; কোনোটি ফাঁকা থাকা উচিত নয়।

এরপর নতুন সার্ভারটি ইচ্ছাকৃতভাবে একবার reboot করুন এবং সেই সময় পর্যবেক্ষণ করুন। কেউ হাতে শুরু করে enable না করা কোনো service প্রথম অনিয়ন্ত্রিত reboot পর্যন্ত, এমনকি ভোর তিনটাতেও, ঠিকঠাক চলতে পারে।

# new server
sudo reboot

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

অ্যাপ্লিকেশনটি container-এ চললে একই সমস্যা ভিন্নভাবে দেখা দেয়, কারণ reboot-এর পরে ফিরে আসার জন্য একটি compose stack-এ স্পষ্ট restart policy প্রয়োজন

শেষ পরীক্ষাটি স্থগিত করা সবচেয়ে সহজ, কিন্তু এটি সবচেয়ে গুরুত্বপূর্ণ: backup job। backup ছাড়া সার্ভারে মাইগ্রেশন শেষ করলে একটি ঝুঁকির বদলে আরেকটি ঝুঁকি তৈরি হয়। নতুন মেশিনে হাতে backup চালান, তারপর সেখান থেকে একটি ফাইল temporary directory-তে restore করুন। বাস্তবে পরীক্ষা করা restore-সহ একটি restic repository প্রয়োজনের সময় কার্যকর সমাধান দেয়। আপনি যদি এক সপ্তাহ পুরোনো ও নতুন সার্ভার পাশাপাশি চালান, প্রতিটি host-এ পৌঁছানো ও configuration করার একটি সঙ্গত পদ্ধতি উভয়ই চালু থাকা অবস্থায় তাদের configuration আলাদা হয়ে যাওয়া ঠেকায়।

কাটওভারের পরে: পুরোনো সার্ভার এবং শেষ কাজগুলো

পুরোনো সার্ভারটি এক থেকে দুই সপ্তাহ রেখে দিন। আপনি যে plan বাতিল করতে যাচ্ছিলেন, তার আরও এক মাসের খরচ হবে; তবে এটিই আপনার একমাত্র rollback ব্যবস্থা। এরপর বাকি কাজগুলো শেষ করুন।

  • নতুন box-এর জন্য আপনার ~/.ssh/config-এ একই hostname পুনরায় ব্যবহার করলে প্রথম connection-এ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! দেখা যাবে, কারণ ওই নামটি এখন ভিন্ন host key ফেরত দিচ্ছে। পরিবর্তনের কারণ নিশ্চিত হওয়ার পরে ssh-keygen -R example.com দিয়ে পুরোনো entry মুছে দিন। অভ্যাসবশত এটি করবেন না, কারণ একই warning interception attack-এর লক্ষণও হতে পারে। কোন key কোন resource-এ access করতে পারে, তা পর্যালোচনা করার জন্য migration একটি উপযুক্ত সময়। এই কাজের জন্য দেখুন ছোট fleet-এ SSH key management
  • পুরোনো সার্ভারের একটি final snapshot বা backup নিন এবং সেটি পুরোনো provider-এর বাইরে অন্য কোথাও সংরক্ষণ করুন।
  • monitoring check, SPF record এবং third-party allowlist থেকে পুরোনো IP সরান। এই ক্রম বজায় রাখুন এবং সবশেষে এটি করুন।
  • final copy অন্য কোথাও পড়া যাচ্ছে বলে নিশ্চিত হওয়ার পরেই পুরোনো plan বাতিল করুন।

FAQ

নতুন VPS-এ একটি server migrate করতে কত সময় লাগে?

ব্যবহারকারীর চোখে outage সাধারণত final database dump, final rsync pass এবং service start-এর সময়টুকুই হয়। তাই একটি ছোট application-এর জন্য সাধারণত দশ থেকে ত্রিশ মিনিট লাগে। তবে calendar time বেশি লাগে, কারণ switch করার অন্তত একটি পুরোনো-TTL period আগে DNS TTL কমাতে হয়। এক দিন আগে কমিয়ে রাখা আরও নিরাপদ। Bulk data copy-ও কয়েক দিন আগে পরিকল্পনা করুন। এটি live server-এর ওপর চালানো যায়। পরে আবার চালালে শুধু শেষ pass-এর পর পরিবর্তিত data-ই transfer হয়।

Dump না করে চলমান MySQL বা PostgreSQL database কি rsync করা যায়?

না। Database একসঙ্গে একাধিক file-এ write করার সময় rsync file ধরে ধরে copy করে। ফলে copy-তে ভিন্ন সময়ের page থাকে এবং এমন একটি state তৈরি হয়, যা database-এর কখনও ছিল না। Database start হতে অস্বীকার করতে পারে। আবার start হলেও কোনো query damaged page-এ পৌঁছালে পরে ব্যর্থ হতে পারে। pg_dump-এর সঙ্গে pg_dumpall --globals-only ব্যবহার করুন, অথবা mysqldump --single-transaction ব্যবহার করুন। আরেকটি পদ্ধতি হলো আগে database বন্ধ করে তারপর file copy করা। বড় PostgreSQL cluster-এর জন্য pg_basebackup চলমান server-এর একটি consistent physical copy তৈরি করে।

DNS পরিবর্তনের আগে নতুন VPS কীভাবে পরীক্ষা করব?

নিজের machine-এ name lookup override করুন। একটি request-এর জন্য curl --resolve example.com:443:203.0.113.20 https://example.com/ connection-টি নতুন IP-তে পাঠায়, তবে certificate যাচাইয়ের সময় প্রকৃত name-ই ব্যবহার করে। Browser দিয়ে পরীক্ষা করতে laptop-এর /etc/hosts-এ 203.0.113.20 example.com যোগ করুন। এরপর login, database read, form write এবং file upload করে দেখুন। শেষে line-টি সরিয়ে দিন। শুধু certificate পরীক্ষা করতে openssl s_client -connect 203.0.113.20:443 -servername example.com চালান।

কোন TTL সেট করা উচিত এবং কখন এটি কমানো উচিত?

A এবং AAAA record-এর TTL 300 seconds করুন। Cutover-এর অন্তত একটি পূর্ণ পুরোনো-TTL period আগে এটি করুন। আপনার পরিবর্তনের আগে কোনো resolver record cache করে রাখলে পুরোনো TTL শেষ না হওয়া পর্যন্ত সেটি পুরোনো value ব্যবহার করবে। তাই পুরোনো TTL 86400 হলে এক ঘণ্টা আগে TTL কমিয়ে কোনো লাভ নেই। Migration-এর কয়েক দিন পরে, পুরোনো server-এর access log শান্ত হয়ে গেলে, TTL আবার স্বাভাবিক value-তে ফিরিয়ে দিন।

TLS certificate কি copy করব, নাকি নতুন server-এ নতুন certificate issue করব?

দুই পদ্ধতিই কাজ করে। /etc/letsencrypt/ copy করলে certificate-এর বর্তমান expiry পর্যন্ত validity বজায় থাকে। তবে নতুন server-এ একই certbot authenticator plugin install করতে হবে। তা না হলে প্রথম renewal ব্যর্থ হবে। তাই DNS switch-এর পরে নিশ্চিত হতে certbot renew --dry-run চালান। DNS-01 challenge ব্যবহার করা সম্ভব হলে নতুন certificate issue করাই পরিষ্কার পদ্ধতি। এটি একটি TXT record-এর মাধ্যমে control প্রমাণ করে এবং DNS নতুন server-এ point করার আগেও কাজ করে। DNS পরিবর্তন না হওয়া পর্যন্ত নতুন server-এ HTTP-01 challenge ব্যবহার করা যায় না, কারণ validation request পুরোনো server-এ পৌঁছাবে।