Cách dùng Restic backup dữ liệu VPS an toàn
Hướng dẫn dùng Restic để backup dữ liệu từ VPS sang server khác hoặc S3. Cách thiết lập deduplication, mã hóa và dùng systemd timer để tự động hóa.
Tại sao backup trên cùng một server không phải là backup
Restic là một công cụ backup mã nguồn mở, miễn phí, giúp gửi các snapshot đã được mã hóa và deduplication của các file của bạn đến một repository ở nơi khác: một VPS thứ hai, một máy tính tại nhà, hoặc object storage tương thích với S3. Hướng dẫn này sẽ thiết lập nó trên Ubuntu 24.04, từ bước cài đặt đến việc tạo repository qua SFTP, thực hiện backup đầu tiên, thiết lập nightly systemd timer, chính sách retention, và bài kiểm tra restore để chứng minh mọi thứ hoạt động tốt. Đích đến phải là một máy khác, vì một bản copy nằm trên cùng một server sẽ "chết" cùng với 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 thứ duy nhất: vô tình xóa nhầm file. Nó không thể sống sót nếu disk bị lỗi, vì nó nằm trên chính disk đó. Nó không thể sống sót trước một attacker có quyền root, vì họ sẽ xóa các bản copy trước tiên. Nó không thể sống sót trước lỗi tài khoản khiến VPS bị xóa mất. The world's least efficient datacenter đùa về một file tarball tên là backup_final_v2_REAL nằm trên cùng một mảng đĩa với dữ liệu, và trò đùa này rất thực tế vì nhiều người trong chúng ta đã từng gặp tình huống y hệt. Quy tắc là phải để dữ liệu ở ngoài máy (off the box), và restic là cách ít đau đớn nhất để tuân thủ quy tắc đó.
Bốn khái niệm về Restic
Repository. Nơi restic ghi dữ liệu vào. Nó là một thư mục theo định dạng riêng của restic, chứa đầy các encrypted blobs, và chỉ restic mới có thể đọc được. Bạn không bao giờ được chỉnh sửa nó bằng tay; bạn tương tác với nó thông qua các lệnh restic và địa chỉ -r.
Snapshot. Một bức ảnh tại một thời điểm nhất định của các file bạn đã backup. Mỗi lần chạy backup sẽ tạo ra một snapshot, mỗi snapshot có thể được restore độc lập, và mỗi snapshot hoạt động như một bản copy hoàn chỉnh của dữ liệu tại thời điểm đó.
Deduplication. Restic chia nhỏ các file thành các chunks dựa trên nội dung và chỉ upload những chunks mà repository chưa từng thấy. Lần backup đầu tiên sẽ upload mọi thứ; các lần chạy sau đó chỉ upload những gì thay đổi. Một snapshot hàng đêm dung lượng 20 GB với 50 MB thay đổi sẽ chỉ tốn khoảng 50 MB, đó là lý do tại sao việc giữ hàng chục snapshots rất rẻ.
Encryption mặc định. Một restic repository luôn được mã hóa (AES-256), và mọi lệnh đều yêu cầu password của repository. Host backup hoặc nhà cung cấp lưu trữ chỉ thấy các encrypted blobs. Hệ quả tất yếu: nếu mất password, dữ liệu sẽ mất vĩnh viễn do thiết kế của hệ thống. Hãy giữ một bản copy password ở một nơi không phải là server này. Điều này quan trọng đến mức nó sẽ được nhắc lại hai lần nữa ở phần dưới.
Cài đặt restic trên Ubuntu 24.04
sudo apt update && sudo apt install -y restic
restic versionTrên Ubuntu 24.04, lệnh này sẽ cài đặt restic 0.16.4, trong khi bản release upstream hiện tại là 0.19.1. Sự chênh lệch này là do các bản LTS (long term support) đóng băng các phiên bản package, nhưng điều này không quan trọng: 0.16.4 có đầy đủ tính năng cho hướng dẫn này. Nếu bạn muốn bản release mới nhất để có hiệu năng tốt hơn, 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, và cài đặt vào /usr/local/bin/restic; cài đặt restic không có gì phức tạp hơn thế.
Tạo repository trên server khác qua SFTP
Bạn cần một máy đích: một VPS nhỏ thứ hai là lựa chọn phổ biến, hoặc bất kỳ máy nào có SSH server và disk trống. Restic sử dụng giao thức SFTP (file transfer over SSH), nên host backup không cần cài đặt thêm gì cả. Trong hướng dẫn này, host backup là 10.0.0.12 với user tên là restic. Đừng đặt tên user đó là backup: Ubuntu và Debian luôn có sẵn một system account được đặt tên là backup (uid 34, không có login shell) trên mọi bản cài đặt, vì vậy adduser backup sẽ lỗi và ssh backup@... sẽ rơi vào nologin.
Job chạy hàng đêm sẽ chạy với quyền root trên server được backup, vì vậy root cần có key login vào host backup. Hãy tạo một key riêng không có passphrase, vì không có con người nào thức lúc 3 giờ sáng để gõ passphrase cả, và copy nó 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 worksNếu bạn chưa quen với key, SSH key management basics sẽ giải thích về mô hình, quyền hạn và cách thu hồi một key sau này.
Tiếp theo là password của repository. Hãy tạo một password mạnh và lưu vào một file chỉ root mới đọc được:
openssl rand -base64 32 | sudo tee /root/.restic-password
sudo chmod 600 /root/.restic-passwordBây giờ hãy copy password đó vào password manager của bạn trước khi tiếp tục. Nếu VPS này chết, repository cùng với password này sẽ khôi phục lại mọi thứ; nếu không có password, repository sẽ không mang lại được gì.
Khởi tạo repository:
sudo restic -r sftp:restic@10.0.0.12:/srv/restic/web1 --password-file /root/.restic-password initcreated restic repository 9f3c2a1b0d at sftp:restic@10.0.0.12:/srv/restic/web1Một đích đến thay thế là object storage tương thích với S3, đây là lựa chọn đúng đắn nếu bạn không muốn chạy một máy thứ hai. Mọi S3-compatible bucket đều hoạt động tương tự; chỉ có địa chỉ và hai biến credential là 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 initMọi thứ sau init là giống nhau cho cả hai đích đến. Phần còn lại của hướng dẫn này sẽ dùng địa chỉ SFTP; hãy thay thế bằng địa chỉ của bạn.
Backup đầu tiên, có sử dụng excludes
Chỉ backup những dữ liệu mà bạn không thể cài đặt lại được, đừng backup toàn bộ filesystem. Hệ điều hành có thể được khôi phục bằng cách cài lại; nhưng cấu hình và dữ liệu của bạn thì không. Đối với một VPS thông thường, điều này có nghĩa là /etc, /home, và bất cứ nơi nào ứng dụng lưu trữ state, chẳng hạn như /srv hoặc /var/www. Hãy exclude các cache, vì chúng lớn, thay đổi hàng ngày và sẽ tự rebuild:
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 savedLần chạy đầu tiên sẽ upload mọi thứ nên sẽ mất thời gian. Chạy lại lệnh đó một lần nữa, nó sẽ hoàn thành trong vài giây, báo cáo một vài file thay đổi và một vài MiB được thêm vào, vì deduplication chỉ upload các chunk mới. Liệt kê những gì bạn có:
sudo restic -r sftp:restic@10.0.0.12:/srv/restic/web1 --password-file /root/.restic-password snapshotsMỗi snapshot hiển thị một ID, thời gian và các đường dẫn chứa bên trong. Những ID đó chính là thứ bạn dùng để restore.
Chạy hàng đêm với systemd timer
Việc phải gõ địa chỉ repository trong mọi câu lệnh rất phiền phức, và một bản backup chạy bằng tay sẽ không còn được thực hiện sau một tháng. Cả hai vấn đề này sẽ được giải quyết bằng một script và một timer. Script sẽ thiết lập hai biến môi trường mà restic đọc là RESTIC_REPOSITORY và RESTIC_PASSWORD_FILE, giúp mọi lệnh 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 checksudo chmod 700 /usr/local/bin/restic-backup.shCác dòng forget và check được giải thích ở hai phần tiếp theo. Bây giờ là lịch trình: một service oneshot để chạy script, và một timer để kích hoạt nó vào lúc 03:00 mỗi đêm. Timer tốt hơn cron ở đây vì log chạy được ghi vào journal, và Persistent=true sẽ chạy bù bản backup bị lỡ ngay khi server hoạt động trở lại sau 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.targetEnable timer, sau đó chạy thử service một lần bằng tay để kiểm tra:
sudo systemctl daemon-reload
sudo systemctl enable --now restic-backup.timer
sudo systemctl start restic-backup.service
sudo journalctl -u restic-backup.service -fsystemctl list-timers cho biết khi nào lần chạy tiếp theo sẽ diễn ra. Bạn cũng có thể tạo cặp file unit thay vì gõ tay:
Toàn bộ cơ chế đằng sau hai file này, bao gồm cú pháp lịch và các chỉ thị hardening mà một service có thể có, nằm trong running a program as a systemd service on a VPS.
Backup chỉ là lời đồn cho đến khi bạn restore nó
Hãy coi câu nói này là một mệnh lệnh. Một job backup chạy thành công (màu xanh) mỗi đêm chỉ chứng minh rằng job đó đã chạy; nó không chứng minh dữ liệu của bạn có thể khôi phục được hay không. Có hai cách để kiểm chứng.
Thứ nhất là restic check, thứ mà script đã chạy hàng đêm. Nó kiểm tra cấu trúc repository và index, giúp phát hiện lỗi corruption âm thầm trên host backup ngay trong đêm tiếp theo thay vì đợi đến ngày cần restore. Mỗi tháng một lần, hãy chạy phiên bản sâu hơn, nó sẽ download và xác thực mã hóa một phần mười dữ liệu thực tế 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 hợp dữ liệu là ngẫu nhiên mỗi lần, các lần chạy hàng tháng sẽ quét qua toàn bộ repository mà không tốn chi phí download toàn bộ.
Thứ hai là bài kiểm tra restore. Vẫn ở shell quyền root từ bước trên, hãy restore một thư mục thật từ snapshot mới nhất vào một vị trí tạm thời và so sánh nó với các file đang chạy:
restic restore latest --target /srv/restore-drill --include /etc/ssh
diff -r /etc/ssh /srv/restore-drill/etc/sshdiff không in ra gì nghĩa là mọi byte đều khớp hoàn toàn, đó là bằng chứng duy nhất có giá trị. Xóa /srv/restore-drill sau khi xong. Hãy thực hiện bài kiểm tra này hàng tháng, và một hoặc hai lần một năm hãy làm bản đầy đủ: restore toàn bộ snapshot mới nhất lên một VPS tạm thời và kiểm tra xem ứng dụng của bạn có thực sự khởi động được từ đó không. Ngày bạn cần nó hoạt động dưới áp lực cao, bạn sẽ muốn nó là một quy trình mà bạn đã thực hiện thành thạo.
Retention: forget và prune
Nếu không có chính sách, các snapshot sẽ tích tụ mãi mãi và repository sẽ ngày càng lớn. Dòng forget trong script áp dụng chính sách mỗi đêm: --keep-daily 7 giữ một snapshot mỗi ngày trong bảy ngày qua, --keep-weekly 4 giữ một snapshot mỗi tuần trong bốn tuần, và --keep-monthly 6 giữ một snapshot mỗi tháng trong sáu tháng. Mọi thứ không được bảo vệ bởi một rule sẽ bị quên đi.
Lệnh forget tự thân nó chỉ xóa các bản ghi snapshot; các data chunks vẫn nằm trong repository cho đến khi có thứ gì đó xóa chúng. Đó là việc của --prune: nó tìm các chunk không còn snapshot nào tham chiếu đến và xóa chúng, đó là lúc dung lượng disk thực sự được giải phóng. Prune thực hiện công việc thực sự của repository, nên với các repository lớn, một số người chạy forget hàng đêm và --prune hàng tuần; với kích thước VPS thông thường, chạy hàng đêm là đủ.
Databases: dump trước, sau đó mới backup dump
Restic copy các file khi nó đang đọc chúng, trong khi database ghi vào file liên tục. Một file database đang chạy bị capture giữa chừng sẽ restore ra một database bị lỗi, vì bản copy trộn lẫn các trang dữ liệu từ trước và sau một lần ghi. Cách khắc phục rất tiêu chuẩn: yêu cầu database engine xuất ra một file export nhất quán, sau đó để restic backup file đó.
Với PostgreSQL, hãy thêm một dòng dump vào đầu file restic-backup.sh, trước lệnh restic backup, và bao gồ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.gzmysqldump đóng vai trò tương tự cho MariaDB và MySQL. Để xem ví dụ thực tế cho toàn bộ quy trình, phần backup Nextcloud sẽ bật chế độ bảo trì, dump Postgres, và copy các file như một tập hợp nhất quán, chính xác là tập hợp mà restic nên mang ra khỏi máy mỗi đêm. SQLite cũng có ý tưởng tương tự nhưng dùng công cụ nhẹ hơn: hướng dẫn Vaultwarden dừng container trong vài giây để lấy một bản copy "cold copy" của db.sqlite3, và archive đó chính là thứ restic sẽ gửi đi khỏi server.
FAQ
Các bản backup của restic có được mã hóa không?
Có, luôn luôn. Mọi restic repository đề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 tính hoặc nhà cung cấp lưu trữ repository chỉ nắm giữ các encrypted blobs, nên nếu host backup bị xâm nhập, các file của bạn vẫn an toàn. Sự đánh đổi là tuyệt đối: nếu không có password, không ai có thể khôi phục dữ liệu, vì vậy hãy lưu một bản copy ở nơi khác ngoài server được backup.
Restic có thực hiện incremental backup không?
Mỗi restic snapshot hoạt động như một bản full backup, nhưng chỉ tốn dung lượng lưu trữ theo kiểu incremental. Restic chia nhỏ file thành các chunks và chỉ upload những chunk mà repository chưa lưu, nên một lần chạy hàng đêm chỉ chuyển tải những gì thay đổi trong ngày đó. Không giống như các cơ chế incremental truyền thống, không có chuỗi (chain) để replay: bất kỳ snapshot nào cũng có thể restore trực tiếp và việc xóa một snapshot cũ không bao giờ làm hỏng các snapshot mới hơn.
Làm thế nào để restore file từ một bản backup restic?
Chạy restic snapshots để tìm snapshot ID, sau đó dùng restic restore <id> --target /some/empty/dir để restore nó, thêm --include /path để chỉ restore một phần. latest có thể dùng thay cho ID. Restic tái tạo cấu trúc thư mục gốc bên dưới đích đến, nên việc restore /etc/ssh sẽ nằm trong /some/empty/dir/etc/ssh. Hãy thực hành việc này trước khi bạn thực sự cần, vì một bản backup chưa được test chỉ là lời đồn.
Tôi nên chạy restic backup bao lâu một lần?
Chạy hàng đêm là mức tối thiểu hợp lý cho một server, và deduplication giúp việc này rất rẻ: mỗi lần chạy chỉ upload những chunk đã thay đổi kể từ lần trước. Dữ liệu thay đổi nhanh, hoặc dữ liệu mà nếu mất dù chỉ một ngày cũng gây hậu quả lớn, có thể chạy mỗi vài giờ với cùng một pattern timer. Tần suất là phần dễ; hãy chạy restic check thường xuyên và thực hiện bài kiểm tra restore hàng tháng, vì một lịch trình mà không có sự xác thực chỉ là sự an tâm giả tạo.
Chuyện gì xảy ra nếu tôi mất password repository restic?
Các bản backup không thể khôi phục được. Mã hóa của restic không có cửa sau (back door) và không có tính năng reset, vì vậy password quan trọng như chính các bản backup vậy. Hãy giữ một bản copy trong password manager và bất kỳ nơi lưu trữ bền vững nào khác không phải là server được backup. Khi bạn vẫn còn quyền truy cập, restic key add có thể đăng ký một password thứ hai cho cùng một repository, giúp bạn có một bản dự phòng.