Tự động đồng bộ thư mục giữa hai server Linux bằng rsync và SSH

Khi vận hành nhiều server, đôi lúc bạn cần tự động chuyển những file mới hoặc vừa cập nhật từ server này sang server khác. Ví dụ, ảnh được tải lên tại server chạy website cần được sao chép sang một server lưu trữ riêng.

Tự động đồng bộ thư mục giữa hai server Linux bằng rsync và SSH

Một cách triển khai đơn giản là dùng rsync để đồng bộ dữ liệu, SSH để bảo vệ kết nối và cron để chạy định kỳ.

Bài viết này hướng dẫn trên Ubuntu/Debian, với mô hình đồng bộ một chiều từ server A sang server B mỗi phút. Server A là nguồn dữ liệu chính; những thay đổi trên server B không được chuyển ngược về server A.

1. Chuẩn bị mô hình đồng bộ

Giả sử bạn sử dụng cấu hình sau:

Thành phần Giá trị minh họa
Thư mục nguồn trên server A /srv/data/uploads/
IP server B 192.0.2.20
Tài khoản nhận dữ liệu trên server B syncuser
Thư mục đích trên server B /srv/replica/uploads/
Cổng SSH server B 22
Lịch đồng bộ Mỗi phút

Thay địa chỉ IP minh họa bằng IP thật hoặc IP trong mạng riêng của bạn. Server A phải kết nối được tới cổng SSH của server B.

Trên server A, các bước tạo SSH key, script và cron cần được thực hiện bằng cùng một tài khoản Linux. Tài khoản này phải có quyền đọc thư mục nguồn và đi qua các thư mục cha.

2. Cài đặt công cụ

Trên cả hai server, chạy:

sudo apt update
sudo apt install -y rsync openssh-client

Trên server B, cài thêm SSH server nếu chưa có:

sudo apt install -y openssh-server
sudo systemctl enable --now ssh

Rsync cần được cài trên cả hai máy khi đồng bộ qua SSH. Dữ liệu truyền qua SSH được mã hóa trong quá trình truyền.

3. Chuẩn bị tài khoản và thư mục đích

Trên server B, tạo tài khoản riêng để nhận dữ liệu:

sudo adduser --disabled-password --gecos "" syncuser

Tạo thư mục đích và cấp quyền:

sudo mkdir -p /srv/replica/uploads
sudo chown syncuser:syncuser /srv/replica/uploads
sudo chmod 750 /srv/replica/uploads

Nếu tài khoản hoặc thư mục đã tồn tại, hãy kiểm tra quyền hiện tại trước khi thay đổi. Với thư mục đang được ứng dụng sử dụng, cần bố trí thêm quyền đọc cho tài khoản chạy ứng dụng.

4. Thiết lập SSH key cho tác vụ tự động

Trên server A, tạo một SSH key riêng:

mkdir -p "$HOME/.ssh"
chmod 700 "$HOME/.ssh"

ssh-keygen -t ed25519 \
  -f "$HOME/.ssh/phult_folder_sync" \
  -C "folder-sync-server-a"

Để cron chạy mà không cần nhập mật khẩu, ví dụ này sử dụng key không có passphrase: nhấn Enter khi được hỏi passphrase. Vì vậy, cần bảo vệ tài khoản và private key trên server A.

Xem public key:

cat "$HOME/.ssh/phult_folder_sync.pub"

Trên server B, chuẩn bị nơi lưu public key:

sudo install -d \
  -m 700 \
  -o syncuser \
  -g syncuser \
  /home/syncuser/.ssh

sudo touch /home/syncuser/.ssh/authorized_keys
sudo chown syncuser:syncuser \
  /home/syncuser/.ssh/authorized_keys
sudo chmod 600 \
  /home/syncuser/.ssh/authorized_keys

sudo nano /home/syncuser/.ssh/authorized_keys

Dán toàn bộ dòng public key vào file, mỗi key một dòng. Không sao chép private key sang server B.

Trở lại server A, mở cấu hình SSH:

nano "$HOME/.ssh/config"

Thêm:

Host folder-sync-target
    HostName 192.0.2.20
    User syncuser
    Port 22
    IdentityFile ~/.ssh/phult_folder_sync
    IdentitiesOnly yes
    BatchMode yes
    StrictHostKeyChecking yes
    ConnectTimeout 10
    ServerAliveInterval 15
    ServerAliveCountMax 3

Nếu SSH sử dụng cổng khác, sửa giá trị Port.

Kết nối lần đầu bằng:

ssh -o StrictHostKeyChecking=ask folder-sync-target

Đối chiếu fingerprint hiển thị với fingerprint của server B qua kênh tin cậy trước khi chấp nhận. Có thể xem fingerprint trên server B bằng:

sudo ssh-keygen -lf \
  /etc/ssh/ssh_host_ed25519_key.pub

Sau khi đăng nhập thành công, chạy exit. Kiểm tra khả năng kết nối không tương tác:

ssh folder-sync-target \
  'test -w /srv/replica/uploads && echo READY'

Nếu xuất hiện READY và không yêu cầu mật khẩu, kết nối đã sẵn sàng.

5. Chạy thử đồng bộ

Trước tiên, chạy chế độ xem trước trên server A:

rsync -rtni \
  -e ssh \
  /srv/data/uploads/ \
  folder-sync-target:/srv/replica/uploads/

Các tùy chọn chính:

Tùy chọn Ý nghĩa
-r Đồng bộ các thư mục con
-t Giữ thời gian chỉnh sửa
-n Xem trước, không thay đổi dữ liệu
-i Liệt kê những thay đổi dự kiến

Sau khi kiểm tra đúng đường dẫn, chạy thực tế:

rsync -rti \
  -e ssh \
  /srv/data/uploads/ \
  folder-sync-target:/srv/replica/uploads/

Dấu / cuối đường dẫn nguồn có ý nghĩa quan trọng: nó yêu cầu sao chép nội dung bên trong thư mục, tránh tạo thêm một cấp uploads tại đích.

Cấu hình này dành cho các file thông thường, chẳng hạn ảnh và tài liệu. Nó không sao chép symlink và không cố giữ nguyên owner, group, ACL hay extended attributes.

6. Tạo script tự động có khóa chống chạy chồng

Trên server A, tạo các thư mục cần thiết:

mkdir -p "$HOME/bin" "$HOME/.local/state/folder-sync"
nano "$HOME/bin/sync-uploads.sh"

Dán nội dung:

#!/bin/bash
set -euo pipefail

export PATH=/usr/local/bin:/usr/bin:/bin

SOURCE_DIR="/srv/data/uploads/"
DESTINATION="folder-sync-target:/srv/replica/uploads/"
STATE_DIR="$HOME/.local/state/folder-sync"

mkdir -p "$STATE_DIR"

exec 9>"$STATE_DIR/sync.lock"

if ! flock -n 9; then
    exit 0
fi

if [[ ! -d "$SOURCE_DIR" ]]; then
    echo "ERROR: Source directory does not exist: $SOURCE_DIR" >&2
    exit 1
fi

echo "[$(date -Is)] Sync started"

if rsync -rti \
    --timeout=120 \
    -e ssh \
    "$SOURCE_DIR" \
    "$DESTINATION"; then
    echo "[$(date -Is)] Sync completed"
else
    status=$?
    echo "[$(date -Is)] Sync failed: exit code $status" >&2
    exit "$status"
fi

Cấp quyền và chạy thử:

chmod 700 "$HOME/bin/sync-uploads.sh"
"$HOME/bin/sync-uploads.sh"

flock -n giúp bỏ qua lượt chạy mới nếu lượt trước vẫn đang giữ khóa, tránh nhiều tiến trình đồng bộ chạy cùng lúc.

7. Đặt lịch chạy mỗi phút

Trên server A, kiểm tra cron:

sudo apt install -y cron
sudo systemctl enable --now cron

Mở crontab bằng chính tài khoản đã tạo SSH key:

crontab -e

Thêm:

* * * * * "$HOME/bin/sync-uploads.sh" >> "$HOME/.local/state/folder-sync/sync.log" 2>&1

Xem log:

tail -n 50 "$HOME/.local/state/folder-sync/sync.log"

Với server vận hành lâu dài, nên cấu hình xoay vòng log để file này không tăng mãi.

Nếu muốn chạy mỗi 5 phút, thay phần lịch bằng:

*/5 * * * *

Đồng bộ mỗi phút không có nghĩa file chắc chắn xuất hiện tại đích trong 60 giây. Thời gian thực tế còn phụ thuộc dung lượng, kết nối và việc lượt chạy trước đã hoàn tất hay chưa.

8. Kiểm tra kết quả

Tạo một file thử trên server A bằng tài khoản có quyền ghi vào thư mục nguồn:

printf 'Folder sync test\n' \
  > /srv/data/uploads/sync-test.txt

Sau lượt chạy tiếp theo, kiểm tra trên server B:

cat /srv/replica/uploads/sync-test.txt

Tiếp tục sửa file tại nguồn và kiểm tra lại để xác nhận việc cập nhật.

Nếu file không xuất hiện, kiểm tra lần lượt:

  • SSH có kết nối được mà không hỏi mật khẩu không?

  • Tài khoản chạy cron có quyền đọc nguồn không?

  • syncuser có quyền ghi tại đích không?

  • Log có báo lỗi đường dẫn, mạng hoặc hết dung lượng không?

9. Có nên đồng bộ cả thao tác xóa?

Cấu hình trong bài giữ lại file tại đích khi file nguồn bị xóa. Tuy nhiên, file cùng đường dẫn tại đích vẫn có thể bị ghi đè khi nguồn thay đổi.

Nếu muốn thư mục đích phản ánh cả việc xóa ở nguồn, rsync có tùy chọn --delete. Trước khi bật, kiểm tra bằng:

rsync -rtni \
  --delete \
  -e ssh \
  /srv/data/uploads/ \
  folder-sync-target:/srv/replica/uploads/

Chỉ thêm --delete vào script sau khi đã xác nhận danh sách xóa và có phương án khôi phục. Tùy chọn này có thể xóa những file chỉ tồn tại ở thư mục đích.

Không chỉnh sửa độc lập cùng một file trên cả hai server với mô hình này: lần đồng bộ tiếp theo có thể ghi đè thay đổi ở server B.

10. Khi nào cần giải pháp khác?

Nếu cần phản ứng gần thời gian thực, có thể xem xét Lsyncd. Công cụ này theo dõi sự kiện thay đổi của filesystem và kích hoạt đồng bộ, thường dùng rsync để truyền dữ liệu.

Với dữ liệu đang được ghi, cần có quy trình bảo đảm file hoàn tất trước khi đồng bộ, chẳng hạn ghi vào thư mục tạm rồi chuyển sang thư mục nguồn. Không dùng cách sao chép thư mục này để đồng bộ trực tiếp dữ liệu đang hoạt động của MySQL hoặc PostgreSQL; hãy sử dụng replication hoặc cơ chế backup phù hợp.

Rsync kết hợp cron phù hợp cho việc sao chép ảnh, tài liệu và file tĩnh giữa hai server. Nếu cần phục hồi phiên bản cũ, cần bổ sung backup có lịch sử hoặc snapshot: một thư mục được đồng bộ vẫn có thể nhận cả những thay đổi sai từ nguồn.

Chia sẻ