การย้ายข้อมูลระหว่าง VPS (Server Migration) เป็นงานที่หลายคนกังวลเพราะกลัว Downtime นาน หรือข้อมูลสูญหายระหว่างทาง แต่ด้วยเครื่องมือ rsync บน Linux การย้ายข้อมูลขนาดหลาย GB สามารถทำได้อย่างมีประสิทธิภาพและปลอดภัย เพราะ rsync ส่งเฉพาะส่วนที่เปลี่ยนแปลง (delta sync) ทำให้สามารถรัน sync ซ้ำหลายรอบได้ เพื่อลด Downtime ให้เหลือเพียงไม่กี่นาทีในช่วง final cutover

บทความนี้จะพาทำทีละขั้นตอน ตั้งแต่เตรียม SSH key, รัน rsync ย้ายไฟล์, ย้าย MySQL database, ตั้งค่า Nginx หรือ Apache บน VPS ใหม่ ไปจนถึงการตรวจสอบและเปลี่ยน DNS อย่างถูกวิธี เหมาะสำหรับ Ubuntu, Debian และ CentOS/Rocky Linux เท่ากัน

ทำความเข้าใจ rsync ก่อนเริ่ม

rsync (Remote Sync) เป็น command-line tool มาตรฐานบน Linux ที่ใช้ซิงค์ไฟล์และไดเรกทอรีระหว่างเครื่องสองเครื่องผ่าน SSH หัวใจสำคัญของ rsync คือ "delta transfer algorithm" ซึ่งวิเคราะห์ความแตกต่างระหว่าง source และ destination แล้วส่งเฉพาะส่วนที่ต่างกัน ไม่ใช่ส่งทั้งไฟล์ใหม่ทุกครั้ง ทำให้เหมาะมากสำหรับการ sync ซ้ำหลายรอบ

ความสามารถสำคัญที่ทำให้ rsync เหนือกว่า scp ในงาน migration:

เตรียม VPS ปลายทางและ SSH Key Authentication

ก่อนรัน rsync ควรตั้งค่า SSH Key ระหว่าง VPS เก่า (source) กับ VPS ใหม่ (destination) เพื่อให้ rsync login ได้โดยไม่ต้องพิมพ์รหัสผ่านทุกรอบ ซึ่งจำเป็นอย่างยิ่งถ้าจะตั้ง cron sync อัตโนมัติ

ขั้นตอนตั้งค่า SSH Key จาก VPS เก่าไปยัง VPS ใหม่

# บน VPS เก่า (source) — สร้าง key pair ถ้ายังไม่มี
ssh-keygen -t ed25519 -C "migration-key" -f ~/.ssh/migration_key -N ""

# คัดลอก public key ไปยัง VPS ใหม่
ssh-copy-id -i ~/.ssh/migration_key.pub root@NEW_VPS_IP

# ทดสอบ login ว่าไม่ถามรหัสผ่าน
ssh -i ~/.ssh/migration_key root@NEW_VPS_IP "echo OK"

หลังจากนี้การรัน rsync จะใช้ -e "ssh -i ~/.ssh/migration_key" เพื่อระบุ key ที่จะใช้ บน VPS ใหม่ให้อัพเดต package และติดตั้ง rsync ให้พร้อมก่อน:

# บน VPS ใหม่ (Ubuntu/Debian)
apt update && apt install -y rsync

# CentOS/Rocky Linux
yum install -y rsync

Flag ที่ใช้บ่อยและความหมาย

การใช้ rsync ให้มีประสิทธิภาพในงาน migration ต้องเลือก flag ให้เหมาะกับสถานการณ์ ตารางด้านล่างสรุป flag ที่ใช้บ่อยที่สุด:

Flag ความหมาย ใช้เมื่อ
-a Archive mode รวม -rlptgoD ทุกกรณี migration — รักษา meta ครบ
-v Verbose แสดงชื่อไฟล์ที่กำลัง sync ตอนตรวจสอบว่า sync อะไรบ้าง
--progress แสดง transfer rate และ % ของแต่ละไฟล์ ตอนโอนไฟล์ขนาดใหญ่
--delete ลบไฟล์ที่ destination ที่ไม่มีใน source Final sync เท่านั้น — อันตรายถ้าใช้ผิด
--exclude ข้ามไฟล์/folder ที่ระบุ กรอง log, cache, tmp, .git
-z Compress ข้อมูลระหว่างส่ง Network ช้า หรือไฟล์ข้อความจำนวนมาก
-n Dry-run ไม่โอนจริง แค่แสดงผล ทดสอบก่อนรันจริงทุกครั้ง
--partial เก็บไฟล์ที่โอนค้างไว้ เพื่อ resume ไฟล์ใหญ่มาก / network ไม่เสถียร

ขั้นตอนที่ 1 — Sync ไฟล์เว็บไซต์ (Initial Sync)

เริ่มต้นด้วยการ sync ไฟล์เว็บไซต์ทั้งหมดจาก VPS เก่าไปยัง VPS ใหม่ รัน initial sync ขณะ service ยังทำงานปกติ เพื่อโอนข้อมูลส่วนใหญ่ก่อนโดยไม่มี downtime ตอนนี้ยังไม่ต้องใช้ --delete

# Initial sync ไฟล์เว็บ (รันบน VPS เก่า)
rsync -avz --progress \
  --exclude='*.log' \
  --exclude='*.tmp' \
  --exclude='cache/' \
  --exclude='.git/' \
  -e "ssh -i ~/.ssh/migration_key" \
  /var/www/html/ \
  root@NEW_VPS_IP:/var/www/html/

หลังรัน initial sync เสร็จ ให้ตรวจดู output ว่ามีไฟล์ error หรือไม่ และจดจำขนาดข้อมูลทั้งหมดไว้เพื่อเปรียบเทียบกับ final sync:

# ตรวจขนาดข้อมูล source
du -sh /var/www/html/

# ตรวจขนาดข้อมูล destination (ssh เข้าไปตรวจ)
ssh -i ~/.ssh/migration_key root@NEW_VPS_IP "du -sh /var/www/html/"

ขั้นตอนที่ 2 — ย้าย MySQL Database

การย้าย MySQL ต้องทำแยกจาก rsync เพราะไฟล์ .ibd และ .frm ของ MySQL ที่ service กำลังทำงานอยู่ไม่ควร copy ตรงๆ (อาจ corrupt ได้) วิธีที่ถูกต้องคือ dump ด้วย mysqldump แล้ว import บน server ใหม่

Dump ทุก Database จาก VPS เก่า

# Dump ทุก database ไปเป็นไฟล์เดียว
mysqldump --all-databases --single-transaction \
  --routines --events --triggers \
  -u root -p > /root/all_databases_backup.sql

# หรือ dump ทีละ database (แนะนำสำหรับ database หลายอัน)
mysqldump --single-transaction --routines \
  -u root -p mywebsite_db > /root/mywebsite_db.sql

โอนไฟล์ Dump ไปยัง VPS ใหม่

# ใช้ rsync โอนไฟล์ sql ที่ dump ไว้
rsync -avz --progress \
  -e "ssh -i ~/.ssh/migration_key" \
  /root/all_databases_backup.sql \
  root@NEW_VPS_IP:/root/

# หรือ pipe ตรงผ่าน ssh เลย (ประหยัดพื้นที่ disk)
mysqldump --all-databases --single-transaction \
  --routines --events --triggers \
  -u root -p | \
  ssh -i ~/.ssh/migration_key root@NEW_VPS_IP \
  "mysql -u root -p"

Import บน VPS ใหม่

# บน VPS ใหม่ — import ไฟล์ dump
mysql -u root -p < /root/all_databases_backup.sql

# ตรวจว่า database ครบ
mysql -u root -p -e "SHOW DATABASES;"

เคล็ดลับสำคัญ: ก่อน import บน VPS ใหม่ ให้ตรวจว่า MySQL version บน VPS ใหม่เท่ากับหรือใหม่กว่า VPS เก่า การ downgrade MySQL version อาจทำให้ไฟล์ dump ที่ export มาจาก version ใหม่กว่า import ไม่ได้ รัน mysql --version บนทั้งสองเครื่องเพื่อเปรียบเทียบก่อนเสมอ

ขั้นตอนที่ 3 — ย้าย Web Server Config (Nginx / Apache)

ไฟล์ config ของ Nginx หรือ Apache ต้องโอนด้วยความระมัดระวัง เพราะ path บางอย่างอาจต่างกัน และต้องตรวจสอบ SSL certificate path ด้วย

ย้าย Nginx Config

# โอน Nginx config ทั้งหมด
rsync -avz --progress \
  -e "ssh -i ~/.ssh/migration_key" \
  /etc/nginx/sites-available/ \
  root@NEW_VPS_IP:/etc/nginx/sites-available/

rsync -avz --progress \
  -e "ssh -i ~/.ssh/migration_key" \
  /etc/nginx/snippets/ \
  root@NEW_VPS_IP:/etc/nginx/snippets/

# บน VPS ใหม่ — enable site และตรวจ config
ssh -i ~/.ssh/migration_key root@NEW_VPS_IP \
  "ln -s /etc/nginx/sites-available/mysite.conf /etc/nginx/sites-enabled/ && nginx -t"

ย้าย Apache Config (ถ้าใช้ Apache)

# โอน VirtualHost config
rsync -avz --progress \
  -e "ssh -i ~/.ssh/migration_key" \
  /etc/apache2/sites-available/ \
  root@NEW_VPS_IP:/etc/apache2/sites-available/

# บน VPS ใหม่ — enable site และตรวจ syntax
ssh -i ~/.ssh/migration_key root@NEW_VPS_IP \
  "a2ensite mysite.conf && apache2ctl configtest"

ย้าย SSL Certificate (Let's Encrypt)

# โอน Certbot certificates ทั้งหมด
rsync -avz --progress \
  -e "ssh -i ~/.ssh/migration_key" \
  /etc/letsencrypt/ \
  root@NEW_VPS_IP:/etc/letsencrypt/

# บน VPS ใหม่ — ติดตั้ง certbot และตรวจ cert
ssh -i ~/.ssh/migration_key root@NEW_VPS_IP \
  "certbot certificates"

หมายเหตุ: หลัง cutover DNS แล้ว ควรรัน certbot renew --dry-run บน VPS ใหม่เพื่อตรวจว่า auto-renew ทำงานได้ เพราะ Let's Encrypt ตรวจผ่าน HTTP challenge ซึ่งต้องการ DNS ชี้มาที่ IP ใหม่แล้ว

ขั้นตอนที่ 4 — Final Sync และลด Downtime

ก่อน cutover จริง ต้องรัน final sync เพื่อให้ข้อมูลทั้งสองฝั่งตรงกันในช่วงสุดท้าย ขั้นตอนนี้ทำให้ total downtime เหลือน้อยที่สุด โดยใช้เวลาเท่ากับ final rsync + restart service + DNS propagation เท่านั้น

# ขั้นตอน Final Sync (รันตามลำดับ)

# 1. หยุด web server และ application บน VPS เก่า
systemctl stop nginx
# หรือ: systemctl stop apache2

# 2. Flush และ dump MySQL ล่าสุด
mysql -u root -p -e "FLUSH TABLES WITH READ LOCK;"
mysqldump --all-databases --single-transaction \
  --routines --events --triggers \
  -u root -p > /root/final_dump.sql
mysql -u root -p -e "UNLOCK TABLES;"

# 3. Final rsync ด้วย --delete เพื่อให้ตรงกันสมบูรณ์
rsync -avz --progress --delete \
  --exclude='*.log' \
  --exclude='*.tmp' \
  --exclude='cache/' \
  -e "ssh -i ~/.ssh/migration_key" \
  /var/www/html/ \
  root@NEW_VPS_IP:/var/www/html/

# 4. Import final dump บน VPS ใหม่
ssh -i ~/.ssh/migration_key root@NEW_VPS_IP \
  "mysql -u root -p < /root/final_dump.sql"

# 5. Start service บน VPS ใหม่
ssh -i ~/.ssh/migration_key root@NEW_VPS_IP \
  "systemctl start nginx && systemctl start php8.2-fpm"

ตรวจสอบก่อน DNS Cutover

ก่อนเปลี่ยน DNS ให้ทดสอบเว็บไซต์บน VPS ใหม่ก่อน โดยการแก้ไฟล์ /etc/hosts บนเครื่องที่ใช้ทดสอบให้ชี้ domain ไปยัง IP ใหม่ชั่วคราว

# เพิ่มใน /etc/hosts บนเครื่องทดสอบ (ไม่ใช่บน VPS)
# แทน NEW_VPS_IP ด้วย IP จริงของ VPS ใหม่
NEW_VPS_IP  mydomain.com  www.mydomain.com

รายการที่ต้องตรวจสอบก่อน cutover:

เปลี่ยน DNS และตรวจสอบหลัง Cutover

เมื่อทุกอย่างผ่านการทดสอบแล้ว ให้ลด TTL ของ DNS record ก่อนล่วงหน้า 24-48 ชั่วโมง (ถ้าทำได้) เพื่อให้ DNS propagate เร็วขึ้น จากนั้นเปลี่ยน A record ให้ชี้ไปยัง IP ของ VPS ใหม่

# ตรวจ DNS propagation หลังเปลี่ยน
dig +short mydomain.com A
nslookup mydomain.com 8.8.8.8

# ตรวจจากหลาย location (ใช้ online tool หรือ command)
# ตัวอย่าง: ดูว่า IP ที่แสดงเป็น IP ใหม่แล้วหรือยัง
dig mydomain.com @1.1.1.1 A +short
dig mydomain.com @8.8.8.8 A +short

หลัง DNS propagate ครบแล้ว ให้เก็บ VPS เก่าไว้อีกอย่างน้อย 7 วันก่อนยกเลิก เพื่อรองรับกรณีที่มีปัญหาและต้องการ rollback หรือดึงข้อมูลบางอย่างเพิ่มเติม

คำถามที่พบบ่อย (FAQ)

rsync ต่างจาก scp อย่างไร และควรใช้ตัวไหนในการย้าย VPS

rsync ส่งเฉพาะข้อมูลที่เปลี่ยนแปลง (delta sync) ทำให้รัน sync ซ้ำหลายรอบได้โดยใช้เวลาน้อยลงเรื่อยๆ รองรับ --exclude สำหรับกรองไฟล์ที่ไม่ต้องการ และมี flag -a เพื่อรักษา permission, owner, timestamp ครบ ส่วน scp คัดลอกทั้งไฟล์ใหม่ทุกครั้งโดยไม่ตรวจส่วนต่าง เหมาะกับไฟล์ขนาดเล็กหรือการโอนครั้งเดียว สำหรับงาน migration VPS ขนาดกลาง-ใหญ่แนะนำ rsync เพราะทำ final sync ช่วง maintenance window ได้รวดเร็ว

ต้องปิด Service บน VPS เก่าก่อน rsync ไหม

ไม่จำเป็นต้องปิดตั้งแต่ต้น แนะนำให้รัน rsync ครั้งแรกขณะ service ยังทำงานเพื่อโอนข้อมูลส่วนใหญ่ก่อน จากนั้นก่อน cutover จริงให้ปิด Nginx/Apache และ MySQL แล้วรัน rsync รอบสุดท้ายเพื่อ sync เฉพาะ file ที่เปลี่ยนแปลงหลัง sync ครั้งแรก ขั้นตอนนี้ทำให้ total downtime เหลือแค่ไม่กี่นาทีในระหว่าง final sync และ DNS propagation

rsync จะย้าย permission และ ownership ให้ด้วยไหม

ใช่ ถ้าใช้ flag -a (archive) หรือ -rlptgoD ซึ่งรวม -p (preserve permissions), -g (group), -o (owner), -t (timestamps) ไว้ครบ แต่การ preserve owner ต้องรัน rsync ในฐานะ root บน server ปลายทางด้วย มิฉะนั้น rsync จะ fallback เป็น user ของตัวเองแทน ตรวจสอบหลัง sync ด้วย ls -la เทียบกัน 2 ฝั่ง

หลังย้าย VPS ด้วย rsync เสร็จแล้วต้องทำอะไรเพิ่มก่อน DNS cutover

ต้องตรวจสอบอย่างน้อย 5 จุด ได้แก่ (1) ทดสอบเว็บไซต์โดยแก้ /etc/hosts ให้ชี้ IP ใหม่ก่อน (2) ตรวจ MySQL ว่า database และ user ครบ สามารถ connect ได้ (3) รัน service ทั้งหมดบน VPS ใหม่และ verify ด้วย systemctl status (4) ตรวจ log ของ Nginx/Apache ว่าไม่มี 500 error (5) ตรวจ SSL certificate ว่า renew script (cron) ยังทำงานบน VPS ใหม่ด้วย เมื่อทุกอย่าง OK จึงค่อย TTL ลดแล้ว update DNS

VPS KVM ประสิทธิภาพสูงของ AsiaGB

AsiaGB VPS Root Access เต็มรูปแบบ Docker MySQL Python Node.js เริ่มต้น 500 บาท/เดือน

ดูแพ็กเกจ VPS