SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor · 已更新 2026-08-01

Restic VPS 備份到另一台伺服器

使用 Restic 將 VPS 資料加密、去重並備份到另一台伺服器或物件儲存,透過 systemd 每晚執行,並以還原演練確認備份確實可用。

為什麼同一部伺服器上的備份不算備份

Restic 是免費的開放原始碼備份工具,可將檔案的加密、去重快照傳送至其他位置的儲存庫:第二部 VPS、家中的電腦,或與 S3 相容的物件儲存。本指南說明如何在 Ubuntu 24.04 上完成設定,包括安裝、透過 SFTP 建立儲存庫、執行第一次備份、設定每晚執行的 systemd 計時器、設定保留原則,以及進行可驗證整體運作正常的還原演練。目的地必須是另一部機器,因為與伺服器位於同一部機器上的複本會隨伺服器一同損毀。

伺服器上的 backup/ 目錄只能防止一種情況:意外刪除檔案。若磁碟故障,它無法保留,因為該目錄位於同一部磁碟上。若攻擊者取得 root 權限,它也無法保留,因為攻擊者會先刪除複本。若帳戶操作錯誤導致 VPS 本身遭到刪除,它同樣無法保留。全球效率最低的資料中心嘲諷名為 backup_final_v2_REAL 的 tarball 與資料位於同一個陣列上;這個笑話之所以成立,是因為許多人確實做過完全相同的事。備份必須位於伺服器之外,而 restic 是遵循這項原則時最不麻煩的方式。

Restic 的 4 個概念

Repository。 Restic 寫入資料的位置。它是採用 restic 自有格式的目錄,內含大量加密 blob,只有 restic 能讀取。請勿手動編輯;應透過 restic 指令和 -r 位址存取。

Snapshot。 備份檔案在某個時間點的狀態。每次執行備份都會建立一個 snapshot,每個 snapshot 都能獨立還原,而且各自都像是該時間點資料的完整副本。

Deduplication。 Restic 會將檔案切分成由內容定義的區塊,只上傳 Repository 尚未儲存的區塊。第一次備份會上傳所有資料;之後每次執行大致只會上傳變更的內容。若每日 snapshot 的資料量為 20 GB,而變更量為 50 MB,成本約為 50 MB,因此保留數十個 snapshot 的成本很低。

預設加密。 Restic Repository 一律會使用 AES-256 加密,而且每個指令都需要 Repository 密碼。備份主機或儲存服務提供者只會看到加密的 blob。其嚴重後果是:若遺失密碼,資料將永久遺失,這是設計上的結果。請在此伺服器以外的位置保留一份密碼副本。這項注意事項非常重要,以下還會再提到 2 次。

在 Ubuntu 24.04 上安裝 restic

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

在 Ubuntu 24.04 上,這會安裝 restic 0.16.4;目前上游版本為 0.19.1。版本差距是因為 LTS(長期支援)版本會固定套件版本。不過這裡不受影響:0.16.4 已能完成本指南中的所有操作。如果您需要最新版以取得速度改進,請從 restic 專案的 GitHub releases 頁面下載官方單一二進位檔,使用 bunzip2 解壓縮,並將其安裝至 /usr/local/bin/restic;安裝 restic 不需要其他步驟。

透過 SFTP 在另一部伺服器上建立儲存庫

您需要一部目的地機器。通常會使用第二部小型 VPS,任何具備 SSH 伺服器和可用磁碟空間的機器也都可以。Restic 支援 SFTP(透過 SSH 傳輸檔案),因此備份主機完全不需要安裝任何軟體。本指南使用 10.0.0.12 作為備份主機,並使用名為 restic 的使用者。請勿將該使用者命名為 backup:Ubuntu 和 Debian 在每次安裝時都會提供名為 backup 的保留系統帳戶(uid 34,沒有登入 shell),因此 adduser backup 會失敗,而 ssh backup@... 會建立在 nologin

夜間工作會以 root 身分在要備份的伺服器上執行,因此 root 需要透過金鑰登入備份主機。請建立沒有密碼片語的專用金鑰,因為凌晨 3am 沒有人員可以輸入密碼片語,然後將金鑰複製過去:

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

如果您不熟悉金鑰,SSH 金鑰管理基礎說明了其運作方式、權限,以及日後如何撤銷金鑰。

接著處理儲存庫密碼。請將強式密碼產生至僅限 root 存取的檔案:

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

現在先將該密碼複製到密碼管理器,再繼續操作。如果此 VPS 故障,儲存庫和該密碼可以還原所有內容;沒有密碼的儲存庫則無法還原任何內容。

初始化儲存庫:

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

另一個目的地是相容於 S3 的物件儲存。如果您不想執行第二部機器,這是適合的選擇。任何相容於 S3 的儲存貯體都以相同方式運作;只有位址和 2 個認證變數需要變更:

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

init 之後的所有內容對兩種目的地都相同。本指南其餘部分會顯示 SFTP 位址;請替換為您的位址。

第一次備份並排除項目

備份無法重新安裝取得的資料,不要備份整個檔案系統。重新安裝後,作業系統可以恢復;但您的組態和資料無法恢復。對一般 VPS 而言,這通常包括 /etc/home,以及應用程式儲存狀態的位置,例如 /srv/var/www。請排除快取,因為快取容量大、每天都會變動,而且可以自行重建:

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

第一次執行會上傳所有內容,因此需要一些時間。再次執行相同的命令後,幾秒內即可完成,只會顯示少數檔案變更及新增幾 MiB,因為重複資料刪除只會上傳新的區塊。列出現有內容:

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

每個快照都會顯示 ID、時間及其中包含的路徑。還原時會使用這些 ID。

使用 systemd 計時器執行每晚工作

每次執行命令都輸入儲存庫位址很快就會變得麻煩,而手動執行的備份通常不到一個月就會停止。這兩個問題都能透過一個指令碼和一個計時器解決。指令碼會設定 restic 讀取的兩個環境變數 RESTIC_REPOSITORYRESTIC_PASSWORD_FILE,因此其中的每個命令都能保持簡短:

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

forgetcheck 行會在接下來兩節說明。接著設定排程:建立一個執行該指令碼的 oneshot 服務,再建立一個每天 03:00 觸發該服務的計時器。這裡使用計時器優於 cron 行,因為執行記錄會寫入 journal,而且 Persistent=true 會在伺服器停機後恢復運作時,立即執行錯過的備份。

# /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

啟用計時器,然後手動執行一次服務並監看其運作情形:

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 會顯示下一次執行的時間。您也可以產生這兩個 unit 檔案,而不必手動輸入:

ToolGenerate the backup service and timer

這兩個檔案背後的完整模式,包括行事曆語法,以及服務可使用的強化安全性指令,請參閱在 VPS 上將程式作為 systemd 服務執行

備份在還原前都只是傳聞

將這句話視為準則。備份工作每天晚上都顯示成功,只能證明工作已執行;不能證明資料可以還原。兩項檢查可以補足這個缺口。

首先是 restic check,指令碼已經每天晚上執行這項檢查。它會驗證儲存庫結構和索引,因此備份主機上的靜默損毀會在隔天晚上被發現,而不是等到還原日才發現。每月執行一次更深入的版本,下載實際資料的隨機十分之一並進行密碼編譯驗證:

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%

由於每次選取的子集都是隨機的,每月執行會逐步涵蓋整個儲存庫,不必支付完整下載的成本。

其次是還原演練。仍在上述的 root shell 中,將最新快照中的一個實際目錄還原至暫存位置,並與線上檔案比較:

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

diff 沒有輸出表示每個位元組都已完全一致地還原,這是唯一有意義的證據。之後刪除 /srv/restore-drill。每月執行這項演練;每年再執行一到兩次完整版本:將最新的完整快照還原至暫存 VPS,並確認應用程式確實能從該快照啟動。當你需要在壓力下完成這項工作時,應該已經把它做成熟悉的例行程序。

保留:forget 加上 prune

如果沒有保留政策,快照會永久累積,儲存庫只會持續增長。指令碼中的 forget 行會在每晚套用政策:--keep-daily 7 會保留過去 7 天每天 1 個快照,--keep-weekly 4 會保留 4 週每週 1 個快照,--keep-monthly 6 會保留 6 個月每月 1 個快照。未受任何規則保護的快照都會被忘記。

單獨執行 forget 只會移除快照記錄;資料區塊仍會留在儲存庫中,直到其他程序將其刪除。--prune 就是用來執行這項工作:它會找出沒有任何現存快照參照的區塊並刪除,磁碟空間也會在此時實際釋出。Prune 會執行實際的儲存庫作業,因此對大型儲存庫而言,有些人會每晚執行 forget,每週執行 --prune;以一般 VPS 的大小而言,每晚執行即可。

資料庫:先傾印,再備份傾印檔

Restic 會在讀取檔案時複製檔案,而資料庫會持續寫入檔案。擷取正在寫入中的資料庫檔案,還原後會變成損毀的資料庫,因為複本混合了寫入前後的頁面。標準作法是:讓資料庫引擎將一致的匯出內容產生至檔案,再讓 restic 備份該檔案。

對 PostgreSQL 而言,請在 restic-backup.sh 的頂端、restic backup 指令之前加入傾印指令,並將傾印目錄加入備份路徑:

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

mysqldump 在 MariaDB 和 MySQL 中扮演相同角色。如需完整模式的實作範例,Nextcloud 備份區段會啟用維護模式、傾印 Postgres,並將檔案作為一致的集合複製;這正是 restic 每晚應從伺服器備份出去的內容。SQLite 的概念相同,但作法更簡單:Vaultwarden 指南會停止容器幾秒,以建立 db.sqlite3 的冷複本;restic 會將該封存檔備份至伺服器外部。

FAQ

restic 備份是否已加密?

是,備份一律會加密。每個 restic 儲存庫都使用 AES-256 加密,沒有未加密模式,而且每個命令都需要儲存庫密碼。存放儲存庫的機器或服務提供者只會持有已加密的 blob,因此備份主機遭入侵也不會暴露您的檔案。代價是絕對的:沒有密碼,任何人都無法復原資料,因此請將密碼副本存放在遠離伺服器的位置。

restic 是否執行增量備份?

每個 restic snapshot 的行為都像完整備份,但所需儲存空間採增量方式增加。Restic 會將檔案分割成區塊,只上傳儲存庫尚未儲存的區塊,因此夜間執行時,傳輸量大致等於當天的變更量。與傳統增量備份不同,這裡沒有需要重播的鏈結:任何 snapshot 都能直接還原,而刪除舊 snapshot 絕不會破壞較新的 snapshot。

如何從 restic 備份還原檔案?

執行 restic snapshots 找出 snapshot ID,接著執行 restic restore <id> --target /some/empty/dir 進行還原;加入 --include /path 可只還原其中一部分。latest 可取代 ID。Restic 會在目標位置下重建原始目錄結構,因此還原 /etc/ssh 會將內容放入 /some/empty/dir/etc/ssh。請在真正需要之前先演練,因為未經測試的備份只是假設。

應多久執行一次 restic backup?

對伺服器而言,每晚執行是合理的最低頻率,而重複資料刪除功能也能降低成本:每次執行只會上傳自上次執行後變更的區塊。變更快速,或遺失一天資料便會造成重大影響的資料,可以使用相同的 timer 模式每幾小時執行一次。頻率只是其中一半;也請定期執行 restic check,並每月進行一次還原演練,因為沒有驗證的排程只能帶來虛假的安心感。

如果遺失 restic 儲存庫密碼,會發生什麼事?

備份將無法復原。Restic 的加密沒有後門,也沒有重設機制,因此密碼與備份本身同等重要。請將副本保存在密碼管理器中,以及其他不在備份伺服器上的耐久儲存位置。仍可存取儲存庫時,restic key add 可以為同一個儲存庫註冊第二組密碼,作為備用密碼。