rsync - Khi scp không còn đủ dùng nữa
scp thì copy. rsync thì sync. Nghe tưởng giống nhau - nhưng khác nhau hoàn toàn khi mọi thứ đi sai.
Bài trước tôi viết về scp - nhanh, gọn, không cần setup gì. Nếu bạn chưa đọc, link ở đây.
Nhưng thật ra tôi dùng scp ngày càng ít hơn. Không phải vì nó tệ, mà vì rsync làm được tất cả những gì scp làm, cộng thêm một đống thứ mà scp không bao giờ làm được.
Hai cái hay nhất: chỉ transfer phần thay đổi và resume được khi đứt kết nối. Với file lớn hoặc deploy thường xuyên, hai điểm này thôi là đủ để chuyển sang rsync rồi.
Cú pháp cơ bản
rsync [options] source destinationNhìn quen không? Đúng rồi - giống hệt scp. Nếu bạn đã dùng scp thành thạo thì học rsync chỉ mất thêm 10 phút.
Trailing slash - thứ gây confuse nhiều nhất
Đây là điểm khác biệt lớn nhất so với scp, và cũng là thứ tôi thấy mọi người hay bị nhầm nhất.
# Có slash - copy NỘI DUNG bên trong folder
rsync -av ./dist/ user@server:/var/www/
# Kết quả: /var/www/index.html, /var/www/app.js ...
# Không có slash — copy CẢ folder (kèm tên)
rsync -av ./dist user@server:/var/www/
# Kết quả: /var/www/dist/index.html, /var/www/dist/app.js ...Quy tắc đơn giản để nhớ: dấu slash = mở folder ra, lấy nội dung bên trong.
Khi deploy web app, hầu hết trường hợp bạn muốn có slash - copy nội dung dist/ thẳng vào /var/www/, không phải tạo thêm folder dist lồng bên trong.
Combo mặc định nên dùng
rsync -avzPBốn flag này tôi gần như luôn dùng cùng nhau:
-a- Archive mode, gộp-rlptgoD: recursive + giữ nguyên permission, timestamps, symlinks...-v- Verbose, thấy file nào đang được transfer-z- Compress, giảm data transfer - hữu ích với file text, code-P- Hiện progress bar + resume được khi đứt giữa chừng
Các options hay dùng
-nhoặc--dry-run- Giả lập, không thực sự copy. Luôn chạy cái này trước khi thực thi lần đầu--delete- Xóa file ở đích nếu ở nguồn đã xóa. Dùng khi muốn sync thực sự--exclude- Bỏ qua file/folder chỉ định--include- Include lại sau khi exclude-e- Chỉ định SSH command (key, port)--checksum- So sánh bằng checksum thay vì size + timestamp--bwlimit=1000- Giới hạn bandwidth (KB/s)--backup- Backup file trước khi override
Upload - Local to Remote
# Upload folder build lên server
rsync -avzP ./dist/ ubuntu@server:/var/www/html/
# Với SSH key
rsync -avzP -e "ssh -i ~/.ssh/key.pem" ./dist/ ubuntu@server:/var/www/html/
# Với SSH config alias — tiện nhất
rsync -avzP ./dist/ myserver:/var/www/html/
# Dry run trước để kiểm tra
rsync -avzP --dry-run ./dist/ myserver:/var/www/html/Download - Remote to Local
# Download folder từ server về
rsync -avzP user@server:/var/www/html/ ./local-backup/
# Backup database dump
rsync -avzP user@db-server:/tmp/dumps/ ~/backups/db/
# Download log files
rsync -avzP user@server:/var/log/nginx/ ./logs/--delete - Sync thực sự
Mặc định rsync chỉ thêm và cập nhật, không xóa. Muốn đích giống hệt nguồn:
rsync -avzP --delete ./dist/ user@server:/var/www/html/⚠️ Cẩn thận với
--delete- file ở server mà không có ở local sẽ bị xóa vĩnh viễn. Luôn--dry-runtrước khi dùng lần đầu.
# Kiểm tra trước
rsync -avzP --delete --dry-run ./dist/ user@server:/var/www/html/
# Thấy ổn rồi mới chạy thật
rsync -avzP --delete ./dist/ user@server:/var/www/html/--exclude - Bỏ qua file không cần thiết
# Exclude 1 folder
rsync -avzP --exclude 'node_modules' ./ user@server:/app/
# Exclude nhiều thứ
rsync -avzP \
--exclude 'node_modules' \
--exclude '.git' \
--exclude '.env' \
--exclude '*.log' \
--exclude 'dist' \
./ user@server:/app/
# Dùng file exclude — giống .gitignore
rsync -avzP --exclude-from='.rsyncignore' ./ user@server:/app/File .rsyncignore:
node_modules/
.git/
.env
*.log
dist/
__pycache__/
*.pycUsecase thực tế
Deploy web app
npm run build
rsync -avzP --delete \
--exclude '.env' \
./dist/ ubuntu@myserver:/var/www/myapp/Backup định kỳ với timestamp
# Backup thủ công
rsync -avzP user@server:/var/data/ ~/backups/$(date +%Y-%m-%d)/
# Kết hợp cron — backup mỗi ngày lúc 2am
# crontab -e
0 2 * * * rsync -avzP user@server:/var/data/ ~/backups/$(date +\%Y-\%m-\%d)/Backup với --backup - giữ lại file cũ trước khi overwrite
rsync -avzP --backup --backup-dir=/backup/$(date +%Y%m%d) \
user@server:/important/ ./local/Sync qua port SSH khác
rsync -avzP -e "ssh -p 2222 -i ~/.ssh/key.pem" \
./dist/ user@server:/var/www/Resume file lớn bị đứt giữa chừng
-P đã bao gồm --partial nên chỉ cần chạy lại đúng lệnh cũ - rsync tự tiếp tục từ chỗ dừng.
rsync -avzP largefile.iso user@server:/tmp/
# Bị đứt → chạy lại y chang, nó tiếp tục từ chỗ dừngMột lỗi nhỏ trong bản gốc
Trong bảng options ban đầu có ghi --postgres - đây là typo, không có flag nào tên vậy. -P thực ra là viết tắt của --progress --partial. Tôi đã sửa lại trong bài này rồi.
Vậy là xong phần core của rsync. Từ giờ mỗi khi deploy hay backup, thay scp bằng rsync -avzP là an toàn hơn nhiều rồi.
Bài tiếp theo tôi sẽ viết về step-ca - tự dựng private Certificate Authority cho internal services. Nếu bạn đang chạy homelab hoặc internal tooling, bài đó sẽ hữu ích.


