SSD Nodes Learn Hosting plans →
Hướng dẫn Matt ConnorBởi Matt Connor · Cập nhật ngày 2026-08-07

Restic backup VPS sang server khác, có restore kiểm thử

Hướng dẫn Restic trên Ubuntu 24.04: backup mã hóa, dedup sang VPS hoặc S3, chạy hằng đêm bằng systemd timer và kiểm thử restore để xác nhận dữ liệu.

Vì sao bản backup trên cùng server không phải là backup

Restic là công cụ backup miễn phí, mã nguồn mở. Công cụ này gửi các snapshot đã mã hóa và loại bỏ dữ liệu trùng lặp của các file đến một repository ở nơi khác: một VPS thứ hai, một máy tại nhà hoặc object storage tương thích với S3. Hướng dẫn này thiết lập Restic trên Ubuntu 24.04, từ cài đặt đến tạo repository qua SFTP, thực hiện backup đầu tiên, tạo systemd timer chạy hằng đêm, đặt chính sách lưu giữ và thực hiện quy trình restore để chứng minh toàn bộ hệ thống hoạt động. Đích backup phải là một máy khác, vì bản sao nằm trên cùng server sẽ mất theo server.

Một thư mục backup/ trên chính máy được backup chỉ bảo vệ bạn khỏi một việc: xóa nhầm file. Nó không tồn tại sau khi disk hỏng, vì thư mục đó nằm trên chính disk ấy. Nó cũng không tồn tại sau khi attacker có quyền root, vì attacker sẽ xóa các bản sao trước. Nó không tồn tại sau một thao tác nhầm làm xóa chính VPS. Trung tâm dữ liệu kém hiệu quả nhất thế giới nói đùa về một tarball tên backup_final_v2_REAL nằm trên cùng array với dữ liệu. Câu đùa đúng vì rất nhiều người trong chúng ta từng làm chính xác như vậy. Quy tắc là phải lưu bản sao ngoài máy, và restic là cách ít phiền phức nhất để thực hiện quy tắc đó.

Restic qua 4 ý

Repository. Nơi restic ghi dữ liệu vào. Đây là một thư mục theo định dạng riêng của restic, chứa đầy các blob đã mã hóa và chỉ restic mới đọc được. Bạn không bao giờ chỉnh sửa trực tiếp thư mục này; hãy thao tác với nó bằng các lệnh restic và địa chỉ -r.

Snapshot. Ảnh chụp trạng thái của các file tại một thời điểm khi bạn backup. Mỗi lần chạy backup tạo một snapshot. Mỗi snapshot có thể được restore độc lập và hoạt động như một bản sao đầy đủ của dữ liệu tại thời điểm đó.

Deduplication. Restic chia file thành các chunk được xác định theo nội dung và chỉ upload những chunk mà repository chưa có. Lần backup đầu tiên upload toàn bộ dữ liệu. Các lần sau chỉ upload phần dữ liệu đã thay đổi. Một snapshot chạy hằng đêm với 20 GB dữ liệu, trong đó 50 MB thay đổi, chỉ tốn khoảng 50 MB. Vì vậy, việc giữ hàng chục snapshot không tốn nhiều dung lượng.

Mã hóa mặc định. Repository của restic luôn được mã hóa bằng AES-256 và mọi lệnh đều cần password của repository. Backup host hoặc nhà cung cấp storage chỉ nhìn thấy các blob đã mã hóa. Hệ quả nghiêm trọng là nếu mất password, dữ liệu sẽ mất vĩnh viễn theo đúng thiết kế. Hãy giữ một bản sao password ở nơi không phải server này. Điều này đủ quan trọng để được nhắc lại thêm 2 lần ở phần dưới.

Cài đặt restic trên Ubuntu 24.04

sudo apt update && sudo apt install -y restic
restic version

Trên Ubuntu 24.04, lệnh này cài restic 0.16.4, trong khi bản phát hành hiện tại từ upstream là 0.19.1. Khoảng chênh lệch này tồn tại vì bản phát hành LTS (long term support) đóng băng phiên bản package. Điều đó không ảnh hưởng trong trường hợp này: 0.16.4 có đầy đủ chức năng cần thiết cho toàn bộ hướng dẫn. Nếu muốn dùng bản phát hành mới nhất để có các cải tiến về tốc độ, hãy tải bản build single-binary chính thức từ trang GitHub releases của dự án restic, giải nén bằng bunzip2 rồi cài vào /usr/local/bin/restic. Cài restic không cần làm thêm bước nào khác.

Tạo repository trên một server khác qua SFTP

Bạn cần một máy đích: một VPS nhỏ thứ hai thường là lựa chọn phù hợp, và bất kỳ máy nào có SSH server cùng dung lượng đĩa còn trống đều dùng được. Restic hỗ trợ SFTP (truyền file qua SSH), nên backup host không cần cài thêm gì. Trong hướng dẫn này, backup host là 10.0.0.12 với user tên restic. Không đặt tên user đó là backup: Ubuntu và Debian đều tạo sẵn system account dành riêng tên backup (uid 34, không có login shell) trong mọi bản cài đặt, nên adduser backup sẽ fail và ssh backup@... sẽ trỏ vào nologin.

Job chạy hằng đêm sẽ chạy dưới quyền root trên server được backup, nên root cần đăng nhập bằng key vào backup host. Tạo một key riêng không có passphrase, vì lúc 3am không có người nhập passphrase, rồi copy key sang đó:

sudo ssh-keygen -t ed25519 -f /root/.ssh/id_ed25519 -N "" -C "web1-restic"
sudo ssh-copy-id -i /root/.ssh/id_ed25519.pub restic@10.0.0.12
sudo ssh restic@10.0.0.12 true && echo key login works

Nếu bạn chưa quen với key, Kiến thức cơ bản về quản lý SSH key giải thích mô hình này, các quyền cần thiết và cách revoke key sau này.

Tiếp theo là password của repository. Tạo một password mạnh và ghi vào file chỉ root có thể đọc:

openssl rand -base64 32 | sudo tee /root/.restic-password
sudo chmod 600 /root/.restic-password

Bây giờ copy password đó vào password manager trước khi tiếp tục. Nếu VPS này bị hỏng, repository cùng password này sẽ khôi phục được toàn bộ dữ liệu; chỉ có repository mà không có password thì không khôi phục được gì.

Khởi tạo repository:

sudo restic -r sftp:restic@10.0.0.12:/srv/restic/web1 --password-file /root/.restic-password init
created restic repository 9f3c2a1b0d at sftp:restic@10.0.0.12:/srv/restic/web1

Lựa chọn đích khác là object storage tương thích S3. Đây là lựa chọn phù hợp khi bạn không muốn vận hành máy thứ hai. Mọi bucket tương thích S3 đều hoạt động giống nhau; chỉ địa chỉ và 2 biến credential thay đổi:

export AWS_ACCESS_KEY_ID=your-key-id
export AWS_SECRET_ACCESS_KEY=your-secret-key
sudo -E restic -r s3:https://s3.example.com/web1-backups --password-file /root/.restic-password init

Mọi thứ sau init đều giống nhau với cả 2 đích lưu trữ. Phần còn lại của hướng dẫn này dùng địa chỉ SFTP; hãy thay bằng địa chỉ của bạn.

Bản backup đầu tiên, kèm exclude

Hãy backup dữ liệu không thể cài lại, không phải toàn bộ filesystem. Hệ điều hành có thể khôi phục bằng cách cài lại; configuration và dữ liệu của bạn thì không. Với một VPS điển hình, đó là /etc, /home và nơi các ứng dụng lưu state, chẳng hạn như /srv hoặc /var/www. Hãy exclude cache vì chúng chiếm nhiều dung lượng, thay đổi mỗi ngày và có thể tự tạo lại:

sudo restic -r sftp:restic@10.0.0.12:/srv/restic/web1 --password-file /root/.restic-password backup /etc /home /srv --exclude '/home/*/.cache'
Files:        4181 new,     0 changed,     0 unmodified
Added to the repository: 731.204 MiB (312.418 MiB stored)
snapshot 5b8a3f2c saved

Lần chạy đầu tiên upload toàn bộ dữ liệu nên sẽ mất một lúc. Chạy lại cùng command sẽ hoàn tất trong vài giây. Kết quả cho biết có một vài file thay đổi và thêm một vài MiB, vì deduplication chỉ upload các chunk mới. Liệt kê những gì bạn đang có:

sudo restic -r sftp:restic@10.0.0.12:/srv/restic/web1 --password-file /root/.restic-password snapshots

Mỗi snapshot hiển thị một ID, thời gian và các path mà snapshot chứa. Bạn dùng những ID đó để restore.

Chạy hằng đêm bằng systemd timer

Việc nhập địa chỉ repository trong mọi command sẽ nhanh chóng trở nên phiền phức, còn backup chạy thủ công thường sẽ bị bỏ quên trong vòng một tháng. Cả hai vấn đề đều được giải quyết bằng một script và một timer. Script đặt 2 biến môi trường mà restic đọc là RESTIC_REPOSITORYRESTIC_PASSWORD_FILE, nên mọi command bên trong script đều ngắn gọn:

sudo nano /usr/local/bin/restic-backup.sh
#!/usr/bin/env bash
set -euo pipefail
export RESTIC_REPOSITORY='sftp:restic@10.0.0.12:/srv/restic/web1'
export RESTIC_PASSWORD_FILE=/root/.restic-password

restic backup /etc /home /srv --exclude '/home/*/.cache'
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
restic check
sudo chmod 700 /usr/local/bin/restic-backup.sh

Các dòng forgetcheck được giải thích trong 2 phần tiếp theo. Bây giờ là lịch chạy: một service oneshot để chạy script và một timer kích hoạt service vào 03:00 mỗi đêm. Trong trường hợp này, timer tốt hơn một dòng cron vì lần chạy được ghi vào journal, còn Persistent=true sẽ chạy backup bị bỏ lỡ ngay khi server hoạt động trở lại sau thời gian downtime.

# /etc/systemd/system/restic-backup.service
[Unit]
Description=Nightly restic backup
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/restic-backup.sh
# /etc/systemd/system/restic-backup.timer
[Unit]
Description=Run the nightly restic backup

[Timer]
OnCalendar=*-*-* 03:00:00
RandomizedDelaySec=15m
Persistent=true

[Install]
WantedBy=timers.target

Enable timer, sau đó chạy service một lần thủ công và theo dõi quá trình thực thi:

sudo systemctl daemon-reload
sudo systemctl enable --now restic-backup.timer
sudo systemctl start restic-backup.service
sudo journalctl -u restic-backup.service -f

systemctl list-timers cho biết lần chạy tiếp theo sẽ được kích hoạt khi nào. Bạn cũng có thể tạo cặp unit file thay vì tự nhập chúng:

ToolGenerate the backup service and timer

Mẫu cấu hình đầy đủ đằng sau 2 file này, bao gồm cú pháp calendar và các directive hardening mà một service có thể sử dụng, được trình bày trong chạy một chương trình dưới dạng systemd service trên VPS.

Bản backup chỉ là tin đồn cho đến khi bạn restore nó

Hãy xem câu này như một nguyên tắc bắt buộc. Một backup job chạy thành công mỗi đêm chỉ chứng minh rằng job đã chạy; nó không chứng minh dữ liệu có thể khôi phục. Hai bước kiểm tra sẽ loại bỏ khoảng trống này.

Trước hết là restic check, vốn đã được script chạy mỗi đêm. Lệnh này xác minh cấu trúc repository và index, nên lỗi hỏng dữ liệu âm thầm trên backup host sẽ được phát hiện vào đêm tiếp theo thay vì đến ngày restore. Mỗi tháng một lần, hãy chạy phiên bản kiểm tra sâu hơn. Phiên bản này sẽ download và xác minh bằng cryptographic signature một phần mười dữ liệu thực tế được chọn ngẫu nhiên:

sudo -i
export RESTIC_REPOSITORY='sftp:restic@10.0.0.12:/srv/restic/web1'
export RESTIC_PASSWORD_FILE=/root/.restic-password
restic check --read-data-subset=10%

Vì tập dữ liệu được chọn ngẫu nhiên mỗi lần, các lần chạy hằng tháng sẽ lần lượt kiểm tra toàn bộ repository mà không phải download toàn bộ dữ liệu.

Thứ hai là restore drill. Vẫn trong root shell ở trên, hãy restore một directory thực từ snapshot mới nhất vào một vị trí tạm, rồi so sánh với các file đang hoạt động:

restic restore latest --target /srv/restore-drill --include /etc/ssh
diff -r /etc/ssh /srv/restore-drill/etc/ssh

diff không in gì ra nghĩa là mọi byte đã được khôi phục giống hệt, và đây là bằng chứng duy nhất có giá trị. Xóa /srv/restore-drill sau đó. Thực hiện restore drill này hằng tháng. Một hoặc hai lần mỗi năm, hãy thực hiện phiên bản đầy đủ: restore toàn bộ snapshot mới nhất lên một VPS tạm và kiểm tra xem ứng dụng có thực sự khởi động được từ đó hay không. Khi cần quy trình này hoạt động dưới áp lực, bạn sẽ muốn đó là một quy trình quen thuộc mà mình đã thực hiện trước đó.

Retention: forget và prune

Nếu không có policy, các snapshot sẽ tích lũy mãi và repository chỉ ngày càng lớn. Dòng forget trong script áp dụng policy mỗi đêm: --keep-daily 7 giữ lại một snapshot mỗi ngày trong 7 ngày gần nhất, --keep-weekly 4 giữ lại một snapshot mỗi tuần trong 4 tuần, và --keep-monthly 6 giữ lại một snapshot mỗi tháng trong 6 tháng. Mọi snapshot không được rule nào bảo vệ sẽ bị forget.

forget tự nó chỉ xóa các bản ghi snapshot; các data chunk vẫn nằm trong repository cho đến khi có thao tác xóa chúng. --prune thực hiện việc đó: lệnh tìm các chunk không còn được snapshot nào tham chiếu và xóa chúng. Đây là lúc dung lượng đĩa thực sự được giải phóng. Prune thực hiện công việc thực trên repository, nên với repository lớn, một số người chạy forget mỗi đêm và --prune mỗi tuần. Với kích thước VPS thông thường, chạy mỗi đêm là phù hợp.

Cơ sở dữ liệu: dump trước, sau đó backup dump

Restic sao chép file trong khi đọc chúng, còn cơ sở dữ liệu liên tục ghi vào các file đó. Nếu file cơ sở dữ liệu đang được ghi dở bị chụp lại, quá trình khôi phục sẽ tạo ra cơ sở dữ liệu bị hỏng vì bản sao trộn các page trước và sau khi ghi. Cách xử lý tiêu chuẩn là yêu cầu database engine tạo một bản export nhất quán ra file, rồi để restic backup file đó.

Với PostgreSQL, thêm một dòng dump vào đầu restic-backup.sh, trước lệnh restic backup, đồng thời thêm thư mục dump vào các đường dẫn backup:

mkdir -p /var/backups/db
sudo -u postgres pg_dump myapp | gzip > /var/backups/db/myapp.sql.gz

mysqldump có cùng vai trò với MariaDB và MySQL. Để xem ví dụ đầy đủ cho toàn bộ mô hình này, phần backup Nextcloud bật maintenance mode, dump Postgres và sao chép các file thành một bộ nhất quán. Đây chính xác là bộ file mà restic cần đưa ra khỏi máy mỗi đêm. Với SQLite, ý tưởng cũng giống vậy nhưng cách thực hiện đơn giản hơn: hướng dẫn Vaultwarden dừng container trong vài giây để tạo bản sao lạnh của db.sqlite3, rồi restic đưa archive đó ra khỏi server.

FAQ

Bản backup của restic có được mã hóa không?

Có, luôn luôn. Mọi repository của restic đều được mã hóa bằng AES-256, không có chế độ không mã hóa, và mọi lệnh đều yêu cầu password của repository. Máy hoặc nhà cung cấp đang lưu repository chỉ giữ các blob đã mã hóa, nên một backup host bị breach không làm lộ các file của bạn. Đổi lại, nếu không có password thì không ai có thể khôi phục dữ liệu. Vì vậy, hãy lưu một bản sao password ở nơi khác, không đặt trên server.

restic có hỗ trợ backup incremental không?

Mỗi snapshot của restic hoạt động như một bản backup đầy đủ, nhưng chỉ tiêu tốn dung lượng incremental. Restic chia file thành các chunk và chỉ upload những chunk repository chưa lưu, nên một lần chạy ban đêm thường chỉ truyền lượng dữ liệu thay đổi trong ngày. Khác với cơ chế incremental truyền thống, restic không có chain cần replay: mọi snapshot đều được khôi phục trực tiếp, và xóa snapshot cũ không bao giờ làm hỏng snapshot mới hơn.

Làm cách nào để khôi phục file từ backup của restic?

Chạy restic snapshots để tìm snapshot ID, sau đó chạy restic restore <id> --target /some/empty/dir để khôi phục snapshot đó; thêm --include /path nếu chỉ muốn khôi phục một phần. Có thể dùng latest thay cho ID. Restic tạo lại cấu trúc thư mục ban đầu bên dưới thư mục đích, nên khôi phục /etc/ssh sẽ tạo kết quả tại /some/empty/dir/etc/ssh. Hãy thử quy trình này trước khi cần dùng, vì một bản backup chưa được kiểm thử chỉ là phỏng đoán.

Nên chạy restic backup bao lâu một lần?

Chạy mỗi đêm là mức tối thiểu hợp lý cho server, và deduplication giúp giảm chi phí: mỗi lần chạy chỉ upload các chunk đã thay đổi kể từ lần trước. Dữ liệu thay đổi nhanh, hoặc dữ liệu mất một ngày cũng gây ảnh hưởng lớn, có thể được backup vài giờ một lần bằng cùng kiểu timer. Tần suất chỉ là một nửa công việc; hãy chạy restic check thường xuyên và diễn tập restore mỗi tháng, vì lịch chạy không đi kèm xác minh chỉ tạo cảm giác an toàn giả.

Điều gì xảy ra nếu tôi mất password của repository restic?

Các bản backup không thể khôi phục. Cơ chế mã hóa của restic không có back door và không có chức năng reset, nên password quan trọng không kém chính các bản backup. Hãy lưu một bản trong password manager và tại một nơi bền vững khác không phải server được backup. Khi vẫn còn quyền truy cập, restic key add có thể đăng ký password thứ hai cho cùng repository, giúp bạn có một password dự phòng.