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 ý chính
Repository. Đây là nơi restic ghi dữ liệu. Đó là một directory theo format 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 repository thủ công; hãy thao tác với nó qua các lệnh restic và địa chỉ -r.
Snapshot. Đây là ảnh chụp dữ liệu tại một thời điểm, gồm các file 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 thay đổi. Một snapshot chạy hằng đêm của 20 GB dữ liệu, trong đó có 50 MB thay đổi, chỉ tốn khoảng 50 MB. Vì vậy, giữ hàng chục snapshot vẫn không tốn nhiều storage.
Mã hóa mặc định. Repository của restic luôn được mã hóa bằng AES-256. Restic từ chối tạo hoặc mở repository bằng password rỗng, trừ khi bạn truyền --insecure-no-password (restic 0.17.0 trở lên). Vì vậy, repository được thiết lập như trong hướng dẫn này cần password cho mọi lệnh. Backup host hoặc storage provider 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 đến mức sẽ được nhắc lại 2 lần nữa bê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 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 worksNế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-passwordBâ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 initcreated restic repository 9f3c2a1b0d at sftp:restic@10.0.0.12:/srv/restic/web1Lự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 initMọ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 savedLầ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 snapshotsMỗ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_REPOSITORY và RESTIC_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 checksudo chmod 700 /usr/local/bin/restic-backup.shCác dòng forget và check đượ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.targetEnable 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 -fsystemctl 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:
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.
Backup chỉ là lời đồn cho đến khi bạn restore được
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ể quay lại. Có 2 bước kiểm tra để khép lại khoảng trống này.
Đầu tiên là restic check, lệnh mà script đã chạy mỗi đêm. Lệnh này kiểm tra cấu trúc repository và index. Nhờ đó, corruption â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 download và xác minh bằng cryptographic 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ì subset được chọn ngẫu nhiên mỗi lần, tài liệu của restic nêu rõ rằng các lần chạy lặp lại không được đảm bảo sẽ bao phủ mọi pack file, dù bạn chạy bao nhiêu lần. Nếu muốn các lần chạy hằng tháng lần lượt kiểm tra toàn bộ repository mà không phải trả chi phí cho một lần download đầy đủ, hãy dùng dạng group cố định: --read-data-subset=1/10 trong một tháng, 2/10 vào tháng tiếp theo, rồi tiếp tục đến 10/10. Restic chia pack file thành 10 group có kích thước gần bằng nhau và chỉ kiểm tra group n. Sau 10 lần chạy, toàn bộ group sẽ được đọc đúng một lần.
Thứ hai là restore drill. Vẫn trong root shell ở phần trên, hãy restore một directory thực tế từ snapshot mới nhất vào một vị trí tạm thời rồi so sánh 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 gì ra nghĩa là mọi byte đã quay lại giống hệt. Đây là bằng chứng duy nhất có giá trị. Sau đó xóa /srv/restore-drill. Thực hiện restore drill này mỗi tháng. Một hoặc 2 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 thời và kiểm tra ứng dụng có thực sự khởi động từ đó hay không. Khi cần thực hiện việc này dưới áp lực, bạn sẽ muốn đó là một quy trình mình đã làm quen từ 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.gzmysqldump 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
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 và không có mode không mã hóa. Restic cũng từ chối password rỗng trừ khi bạn truyền --insecure-no-password (có từ restic 0.17.0), vì vậy repository được thiết lập như trong hướng dẫn này cần password cho mọi lệnh. Machine hoặc provider lưu repository chỉ giữ các blob đã mã hóa. Vì vậy, backup host bị breach cũng không làm lộ các file của bạn. Đổi lại, điều kiện này là tuyệt đối: không có password thì không ai có thể khôi phục dữ liệu. Hãy lưu một bản sao password bên ngoài server.
Restic có thực hiện incremental backup không?
Mỗi snapshot của restic hoạt động như một full backup nhưng chỉ tốn phần storage tăng thêm. Restic chia file thành các chunk và chỉ upload những chunk repository chưa lưu. Vì vậy, một lần chạy hằng đêm chỉ truyền khoảng phần dữ liệu đã thay đổi trong ngày. Khác với các cơ chế incremental truyền thống, không có chain cần replay. Mọi snapshot đều restore trực tiếp được và việc xóa snapshot cũ không làm snapshot mới hơn bị hỏng.
Làm thế nào để restore file từ backup của restic?
Chạy restic snapshots để tìm snapshot ID, sau đó chạy restic restore <id> --target /some/empty/dir để restore snapshot đó. Thêm --include /path nếu chỉ muốn restore một phần. latest có thể dùng thay cho ID. Restic tạo lại cấu trúc directory ban đầu bên dưới target, vì vậy restore /etc/ssh sẽ đưa dữ liệu vào /some/empty/dir/etc/ssh. Hãy luyện tập việc này trước khi cần dùng, vì một backup chưa được kiểm tra chỉ là lời đồn.
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 server. Deduplication giúp việc này ít tốn kém, vì mỗi lần chạy chỉ upload các chunk đã thay đổi từ lần trước. Dữ liệu thay đổi nhanh hoặc mất 1 ngày dữ liệu sẽ gây thiệt hại lớn có thể được backup mỗi vài giờ với cùng pattern của timer. Tần suất chỉ là một nửa vấn đề. Hãy chạy restic check thường xuyên và thực hiện restore drill mỗi tháng, vì schedule không có verification 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?
Backup sẽ không thể khôi phục. Cơ chế mã hóa của restic không có back door và cũng không có chức năng reset, vì vậy password quan trọng không kém chính các bản backup. Hãy giữ một bản sao trong password manager và 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ứ 2 cho cùng repository để tạo password dự phòng.