rsync: ตัวอย่างการซิงก์ไฟล์และสำรองข้อมูลใน Linux
rsync คัดลอกและซิงก์ไฟล์ทั้งในเครื่องและผ่าน SSH โดยส่งเฉพาะส่วนที่เปลี่ยนแปลง คำสั่งพื้นฐานคือ rsync -avz ต้นทาง/ user@host:/ปลายทาง/ โดย -a เก็บสิทธิ์และเวลา, -v แสดงรายการไฟล์, -z บีบอัดข้อมูลระหว่างส่ง ส่วน --delete ทำให้ปลายทางเหมือนต้นทางทุกประการ และ -n ใช้ตรวจผลลัพธ์ก่อนโดยไม่เปลี่ยนแปลงอะไร
rsync เป็นเครื่องมือมาตรฐานของ Linux สำหรับคัดลอกและซิงก์ไฟล์ ทั้งภายในเครื่อง ระหว่างดิสก์ และระหว่างเซิร์ฟเวอร์ผ่าน SSH จุดที่ต่างจาก cp และ scp คือ rsync ส่งเฉพาะสิ่งที่เปลี่ยนแปลง ดังนั้นการซิงก์ไดเรกทอรีขนาดใหญ่ซ้ำอีกครั้งใช้เวลาเพียงไม่กี่วินาที ด้านล่างเป็นตัวอย่าง rsync สำหรับงานทั่วไป: อัปโหลดโปรเจกต์ขึ้นเซิร์ฟเวอร์, ทำสำเนาไดเรกทอรี, การยกเว้นไฟล์, การสำรองข้อมูลพร้อมสแนปช็อต และการรันตามกำหนดเวลา
ไวยากรณ์และแฟลกที่จำเป็น
รูปแบบคำสั่งทั่วไป:
rsync [ตัวเลือก] ต้นทาง... ปลายทาง
ต้นทางและปลายทางอาจเป็นพาธในเครื่องหรือพาธระยะไกลในรูปแบบ user@host:/path ต้องมีฝั่งใดฝั่งหนึ่งเป็นเครื่องในเสมอ เพราะ rsync ไม่คัดลอกโดยตรงระหว่างเครื่องระยะไกลสองเครื่อง
| แฟลก | ทำอะไร |
|---|---|
-a | โหมดอาร์ไคฟ์: ทำซ้ำแบบเรียกซ้ำ เก็บสิทธิ์ เจ้าของ กลุ่ม เวลาแก้ไข และลิงก์สัญลักษณ์ (เทียบเท่า -rlptgoD) |
-v | แสดงรายการไฟล์ที่ถูกส่ง |
-z | บีบอัดข้อมูลขณะส่งผ่านเครือข่าย |
-h | แสดงขนาดในรูปแบบอ่านง่าย (K, M, G) |
-P | เทียบเท่า --partial --progress: แสดงความคืบหน้าและดาวน์โหลดไฟล์ที่ค้างต่อได้ |
-n, --dry-run | ทดลองรัน: แสดงสิ่งที่จะทำ โดยไม่เปลี่ยนแปลงอะไร |
--delete | ลบไฟล์ในปลายทางที่ไม่มีในต้นทาง |
--exclude | ไม่คัดลอกไฟล์ที่ตรงกับรูปแบบที่กำหนด |
-e | กำหนดเชลล์ระยะไกล เช่น -e "ssh -p 2222" |
-H, -A, -X | เก็บลิงก์แบบฮาร์ด ACL และ extended attributes (ไม่รวมอยู่ใน -a) |
ในเก้าใน สิบกรณีการใช้ rsync -avh ในเครื่องและ rsync -avzh ผ่านเครือข่ายก็เพียงพอแล้ว
เครื่องหมายสแลชท้ายพาธ: กับดักหลัก
ข้อผิดพลาดที่นักเริ่มต้นพบบ่อยที่สุดเกี่ยวข้องกับสแลชท้ายของต้นทาง ซึ่งเป็นตัวกำหนดว่าจะคัดลอกตัวไดเรกทอรีเอง หรือเฉพาะเนื้อหาข้างใน
# คัดลอกไดเรกทอรี project เข้าไปใน /backup → ได้ /backup/project/...
rsync -av project /backup/
# คัดลอกเนื้อหาของ project ไปยัง /backup → ไฟล์จะอยู่ใน /backup/ โดยตรง
rsync -av project/ /backup/
จำง่ายๆ ว่า สแลชท้ายของต้นทางหมายถึง «เนื้อหาของไดเรกทอรีนี้» ส่วนปลายทางไม่มีผลกับสแลช หากไม่แน่ใจ ให้เพิ่ม -n แล้วดูว่า rsync จะสร้างพาธอะไรบ้าง
การคัดลอกในเครื่อง
คัดลอกไดเรกทอรีไปยังดิสก์ภายนอกพร้อมแสดงความคืบหน้า:
rsync -avhP ~/photos/ /mnt/usb/photos/
การรันคำสั่งเดิมซ้ำจะไม่คัดลอกทุกอย่างใหม่ rsync เปรียบเทียบขนาดและเวลาแก้ไขของไฟล์ และส่งเฉพาะไฟล์ที่ใหม่หรือเปลี่ยนแปลง ผลลัพธ์ท้ายคำสั่งแสดงว่าส่งข้อมูลจริงไปเท่าไร:
sending incremental file list
2026/10/IMG_2041.jpg
4.12M 100% 38.40MB/s 0:00:00 (xfr#1, to-chk=0/1534)
sent 4.13M bytes received 9.25K bytes 2.76M bytes/sec
total size is 6.82G speedup is 1,648.21
ค่า speedup บอกว่าข้อมูลที่ส่งน้อยกว่าการคัดลอกทั้งหมดกี่เท่า
rsync ผ่าน SSH: คัดลอกขึ้นเซิร์ฟเวอร์และดาวน์โหลดกลับ
สำหรับพาธระยะไกล rsync ใช้ SSH เป็นค่าเริ่มต้น จึงไม่ต้องตั้งค่าเพิ่ม ขอเพียงการล็อกอินด้วย ssh ใช้งานได้ การใช้คีย์สะดวกที่สุด เพราะไม่ต้องใส่รหัสผ่าน และนำคำสั่งไปใส่ใน cron ได้
# อัปโหลดเว็บไซต์ขึ้นเซิร์ฟเวอร์
rsync -avz ./site/ deploy@203.0.113.10:/var/www/site/
# ดาวน์โหลดล็อกจากเซิร์ฟเวอร์มาไว้ที่เครื่องของคุณ
rsync -avz deploy@203.0.113.10:/var/log/nginx/ ./nginx-logs/
# SSH บนพอร์ตที่ไม่ใช่ค่าเริ่มต้นและใช้คีย์เฉพาะ
rsync -avz -e "ssh -p 2222 -i ~/.ssh/deploy_key" ./site/ deploy@203.0.113.10:/var/www/site/
rsync ต้องติดตั้งทั้งสองเครื่อง เพราะฝั่งระยะไกลจะถูกเรียกผ่าน SSH หากไม่มี จะเห็นข้อความ rsync: command not found ให้ติดตั้งแพ็กเกจด้วย sudo apt install rsync หรือ sudo dnf install rsync
หากกำหนดโฮสต์ไว้ใน ~/.ssh/config ภายใต้ชื่อเล่น rsync จะเข้าใจชื่อนั้น: rsync -avz ./site/ prod:/var/www/site/
ต้องใช้สิทธิ์ root บนเซิร์ฟเวอร์
เมื่อไฟล์ในปลายทางเป็นของ root แต่คุณล็อกอินด้วยผู้ใช้ปกติ สามารถรัน rsync ฝั่งระยะไกลผ่าน sudo ได้:
rsync -avz --rsync-path="sudo rsync" ./conf/ admin@server:/etc/myapp/
วิธีนี้ต้องตั้ง sudo ให้รัน rsync ได้โดยไม่ถามรหัสผ่านบนเซิร์ฟเวอร์ (กฎใน sudoers) มิฉะนั้นคำสั่งจะค้างรอการป้อนข้อมูล
ทำสำเนาไดเรกทอรีให้เหมือนกันทุกประการ: --delete
โดยค่าเริ่มต้น rsync จะเพิ่มและอัปเดตไฟล์เท่านั้น แต่ไม่ลบอะไรเลย หากต้องการให้ปลายทางเป็นสำเนาที่ตรงกับต้นทางทุกประการ ต้องใช้ --delete:
rsync -avh --delete ~/projects/ /mnt/backup/projects/
แฟลกนี้ทรงพลังและอันตราย พาธที่ผิด (เช่น ต้นทางว่างเปล่า หรือลืมสแลช) จะลบข้อมูลในปลายทาง กฎจึงมีข้อเดียว: คำสั่งที่มี --delete ให้รันด้วย -n ก่อนเสมอ
$ rsync -avhn --delete ~/projects/ /mnt/backup/projects/
sending incremental file list
deleting old-app/README.md
deleting old-app/
app/main.py
sent 1.20K bytes received 64 bytes 2.53K bytes/sec
total size is 18.4M speedup is 14,554.39 (DRY RUN)
บรรทัด deleting แสดงสิ่งที่จะถูกลบ เมื่อแน่ใจว่าถูกต้องแล้วจึงรันโดยไม่มี -n
ตัวเลือกที่เกี่ยวข้อง: --delete-after ลบไฟล์หลังการส่งเสร็จ (ทำให้ปลายทางครบถ้วนนานกว่า) ส่วน --backup --backup-dir=/mnt/backup/deleted-$(date +%F) จะไม่ลบ แต่ย้ายไฟล์ที่ถูกลบหรือถูกแทนที่ไปไว้ในไดเรกทอรีแยก
การยกเว้นไฟล์: --exclude และ --include
การยกเว้นไฟล์ชั่วคราว dependencies และความลับเป็นแนวปฏิบัติปกติเมื่อดีพลอยหรือสำรองข้อมูล
# หลายรูปแบบ
rsync -avz --exclude='.git/' --exclude='node_modules/' --exclude='*.log' ./app/ server:/srv/app/
# รูปแบบจากไฟล์
rsync -avz --exclude-from='.rsyncignore' ./app/ server:/srv/app/
ไฟล์ .rsyncignore คือรายการรูปแบบอย่างง่าย หนึ่งรูปแบบต่อหนึ่งบรรทัด:
.git/
node_modules/
*.log
.env
tmp/
วิธีที่รูปแบบทำงาน:
- รูปแบบที่ไม่มีสแลชนำหน้า (
*.log) ตรงกับไฟล์ในทุกระดับความลึก - รูปแบบที่มีสแลชนำหน้า (
/tmp/) ผูกกับรากของการส่ง จะยกเว้นเฉพาะtmpระดับบนสุด - สแลชท้าย (
cache/) หมายถึง «เฉพาะไดเรกทอรี» - กฎถูกตรวจตามลำดับ และรายการแรกที่ตรงจะถูกใช้
จากข้อสุดท้ายนำไปสู่เทคนิค «คัดลอกเฉพาะที่ต้องการ»: อนุญาตก่อน แล้วปฏิเสธทุกอย่างที่เหลือ
# คัดลอกเฉพาะไฟล์ .conf และคงโครงสร้างไดเรกทอรีไว้
rsync -av --include='*/' --include='*.conf' --exclude='*' /etc/ ./etc-confs/
ที่นี่ --include='*/' จำเป็นเพื่อให้ rsync เข้าไปในทุกไดเรกทอรีย่อย เพิ่ม --prune-empty-dirs (-m) หากไม่ต้องการสร้างโฟลเดอร์ว่าง
สำรองข้อมูลด้วย rsync
สำเนาประจำวันแบบง่าย
การสำรองโฮมไดเรกทอรีขั้นต่ำไปยังดิสก์ตัวที่สอง:
rsync -aH --delete --exclude='.cache/' /home/alice/ /mnt/backup/alice/
ข้อจำกัดของวิธีนี้คือเก็บเพียงเวอร์ชันเดียว หากไฟล์ถูกทำให้เสียหายและการสำรองซิงก์ไปแล้ว เวอร์ชันเก่าก็หายไป
สแนปช็อตแบบเพิ่มทีละส่วนด้วย --link-dest
แฟลก --link-dest แก้ปัญหานี้ได้เกือบโดยไม่เสียพื้นที่เพิ่ม ไฟล์ที่ไม่เปลี่ยนแปลงจะไม่ถูกคัดลอก แต่สร้างเป็นลิงก์แบบฮาร์ดไปยังไฟล์ของสแนปช็อตก่อนหน้า สแนปช็อตแต่ละชุดดูเหมือนสำเนาเต็ม แต่กินพื้นที่เฉพาะส่วนที่เปลี่ยน
#!/bin/bash
set -euo pipefail
SRC="/home/alice/"
DEST="/mnt/backup/snapshots"
TODAY="$(date +%F)"
mkdir -p "$DEST"
rsync -aH --delete \
--exclude='.cache/' \
--link-dest="$DEST/latest" \
"$SRC" "$DEST/$TODAY"
ln -sfn "$DEST/$TODAY" "$DEST/latest"
การรันครั้งแรกยังไม่มีไดเรกทอรี latest rsync จะแสดงคำเตือนและทำสำเนาเต็ม ซึ่งเป็นเรื่องปกติ สแนปช็อตเก่าลบได้ด้วย rm -rf ธรรมดา ไฟล์ที่สแนปช็อตอื่นอ้างถึงจะไม่หายไป
ลบสแนปช็อตที่เก่ากว่า 30 วันได้ด้วยคำสั่งนี้:
find /mnt/backup/snapshots -maxdepth 1 -type d -name '20*' -mtime +30 -exec rm -rf {} +
สำรองเซิร์ฟเวอร์ไปยังเครื่องอื่น
ควรเลือกทิศทาง «จากเซิร์ฟเวอร์สำรองไปยังเครื่องงาน» เพื่อให้เครื่องสำรองดึงข้อมูลเอง และเซิร์ฟเวอร์งานไม่มีสิทธิ์เข้าถึงสำเนา หากเซิร์ฟเวอร์งานถูกเจาะ สำเนาสำรองยังปลอดภัย
rsync -azH --delete -e "ssh -i /root/.ssh/backup_key" \
backup@web01:/var/www/ /srv/backups/web01/www/
ฐานข้อมูลไม่ควรคัดลอกด้วยวิธีนี้ เพราะไฟล์ของ DBMS ที่กำลังทำงานจะไม่สอดคล้องกันขณะคัดลอก ให้ทำ dump ก่อน (mysqldump, pg_dump) แล้วให้ rsync ย้ายไฟล์ dump ที่เสร็จแล้ว
รันตามกำหนดเวลาด้วย cron
เพิ่มสคริปต์สำรองลงใน cron ด้วยคำสั่ง crontab -e:
# ทุกวันเวลา 03:15 ผลลัพธ์เก็บไว้ในล็อก
15 3 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
สิ่งที่ควรตรวจเพื่อให้การสำรองจาก cron ทำงานจริง:
- ใช้พาธแบบเต็มในสคริปต์ เพราะ cron มี
PATHน้อยมากและไดเรกทอรีปัจจุบันต่างออกไป - ใช้คีย์ SSH ที่ไม่มีรหัสผ่าน และโฮสต์อยู่ใน
known_hostsแล้ว มิฉะนั้น rsync จะค้างรอคำถามเรื่องการยืนยันคีย์โฮสต์ - สคริปต์ตรวจรหัสส่งกลับ: rsync คืนค่า 0 เมื่อสำเร็จ, 23 เมื่อส่งไฟล์บางส่วนไม่สำเร็จ และ 24 เมื่อไฟล์หายไประหว่างการคัดลอก
- ป้องกันการรันซ้อนกันด้วย
flock:flock -n /tmp/backup.lock /usr/local/bin/backup.sh
แทน cron ก็ใช้ตัวจับเวลาของ systemd ได้ โดยผลลัพธ์จะเก็บในจอร์นัล และดูได้สะดวกด้วย journalctl
ตัวเลือกที่เป็นประโยชน์สำหรับการส่งข้อมูลขนาดใหญ่
| งาน | ตัวเลือก |
|---|---|
| จำกัดความเร็วเพื่อไม่ให้ใช้ช่องสัญญาณเต็ม | --bwlimit=5M |
| ดาวน์โหลดไฟล์ใหญ่ต่อหลังการขาดหาย | -P (หรือ --partial) |
| แสดงความคืบหน้ารวมแทนรายการไฟล์ | --info=progress2 |
| เปรียบเทียบด้วยเนื้อหาแทนเวลา | -c (--checksum) ช้ากว่า |
| ไม่แตะไฟล์ที่ปลายทางใหม่กว่า | -u (--update) |
| ไม่เขียนทับไฟล์ที่มีอยู่แล้ว | --ignore-existing |
| ลบไฟล์ต้นทางหลังส่งเสร็จ (ย้าย) | --remove-source-files |
| สถิติโดยละเอียดท้ายคำสั่ง | --stats |
ข้อผิดพลาดที่พบบ่อยและวิธีแก้
Permission deniedตอนเขียน — ผู้ใช้ไม่มีสิทธิ์ในไดเรกทอรีปลายทาง ตรวจเจ้าของไดเรกทอรีหรือใช้--rsync-path="sudo rsync"- ไฟล์ถูกคัดลอกใหม่ทุกครั้ง — เวลาแก้ไขไม่ถูกเก็บไว้ ตรวจว่ามี
-aหรือ-t; บน FAT/exFAT ให้เพิ่ม--modify-window=2เพราะระบบเหล่านี้เก็บเวลาที่ความละเอียดสองวินาที - ข้อผิดพลาด
chownหรือchgrpเมื่อคัดลอกไปยังแฟลชไดรฟ์หรือโฟลเดอร์เครือข่าย — ระบบไฟล์ไม่รองรับเจ้าของ ให้เปลี่ยน-aเป็น-rlt - เกิดโฟลเดอร์ซ้อน
/backup/project/project— สแลชท้ายของต้นทางผิด connection unexpectedly closed— ปัญหาที่ SSH หรือไม่มี rsync บนฝั่งระยะไกล ทดสอบการล็อกอินด้วยsshปกติและตรวจว่ามีrsyncบนเซิร์ฟเวอร์
สรุป
สำหรับงานประจำวันควรจำคำสั่งไม่กี่คำสั่ง: rsync -avz src/ host:/dst/ สำหรับคัดลอกผ่าน SSH, --delete ร่วมกับ -n ก่อนเสมอสำหรับการทำสำเนาให้ตรง, --exclude สำหรับไฟล์ที่ไม่ต้องการ และ --link-dest สำหรับการสำรองแบบสแนปช็อต ระวังสแลชท้ายของต้นทาง แล้ว rsync จะเป็นวิธีที่เชื่อถือได้ที่สุดในการย้ายไฟล์ระหว่างเครื่อง การซิงก์และการสำรองข้อมูลถูกอธิบายพร้อมตัวอย่างจริงในคอร์ส Linux
คำถามที่พบบ่อย
rsync ดีกว่า scp อย่างไร?
scp คัดลอกไฟล์ทั้งหมดทุกครั้ง ส่วน rsync ส่งเฉพาะส่วนที่เปลี่ยน รองรับการดาวน์โหลดต่อ ลบไฟล์ที่เกินในปลายทาง และยกเว้นไฟล์ตามรูปแบบได้ สำหรับการคัดลอกไฟล์เดียวครั้งเดียวแทบไม่ต่างกัน แต่สำหรับการซิงก์เป็นประจำ rsync เร็วกว่ามาก
ใช้ rsync บน Windows ได้หรือไม่?
ได้ ผ่าน WSL ซึ่งติดตั้ง rsync เหมือนบน Linux ทั่วไป หรือผ่าน Cygwin การซิงก์ไฟล์จากเครื่อง Windows ไปยังเซิร์ฟเวอร์ Linux สะดวกที่สุดจาก WSL
rsync เข้ารหัสข้อมูลที่ส่งหรือไม่?
ตัว rsync เองไม่เข้ารหัส แต่เมื่อคัดลอกผ่าน SSH ข้อมูลทั้งหมดจะวิ่งผ่านการเชื่อมต่อ SSH ที่เข้ารหัส การส่งที่ไม่เข้ารหัสเกิดขึ้นเฉพาะเมื่อใช้ดีมอน rsync ผ่านที่อยู่รูปแบบ rsync://
จะตรวจสอบได้อย่างไรว่าสำเนาตรงกับต้นฉบับ?
รัน rsync -avnc ต้นทาง/ ปลายทาง/ แฟลก -c เปรียบเทียบด้วย checksum และ -n ไม่เปลี่ยนแปลงอะไร ถ้ารายการไฟล์ว่างเปล่า แสดงว่าสำเนาเหมือนกัน
จะเกิดอะไรขึ้นหาก rsync ถูกขัดจังหวะกลางคัน?
ไฟล์ที่ส่งเสร็จแล้วจะคงอยู่ ส่วนไฟล์ที่ยังไม่สมบูรณ์จะถูกลบตามค่าเริ่มต้น การรันคำสั่งเดิมซ้ำจะทำต่อจากจุดที่หยุด และหากใช้แฟลก -P ส่วนของไฟล์ที่ค้างอยู่จะถูกเก็บไว้ด้วย
หัวข้อนี้สอนอย่างละเอียดพร้อมฝึกปฏิบัติในคอร์ส “Linux: с нуля до уверенного администрирования”
ไปที่คอร์ส