備份是不是真的,只有還原那一刻才知道。

Docker 服務打不開、資料夾誤刪怎麼辦?用 Uptime Kuma 實際演練:保留現場、從 Hyper Backup 還原到測試位置、驗證資料再切回正式,含反向代理與網域檢查。

Synology Docker 服務壞掉怎麼救?從備份到還原的實戰演練

上一篇 Synology NAS Docker 維運 SOP 講完了「先備份、再更新、後驗證」的原則,也提到每季要演練一次還原。但原則歸原則,多數人真正的疑問是:還原到底長什麼樣子?點哪裡?檔案放回哪?怎麼確定資料真的回來了?

這篇就把那一次演練完整走一遍。情境是最常見的一種:某個 Docker 服務在更新或誤操作後起不來,資料夾疑似損毀。我們用 Uptime Kuma 當演練對象——它的資料是單一 data/ 資料夾(SQLite),結構簡單、壞了影響有限,非常適合當你人生第一次還原演練的主角。流程走熟之後,同一套步驟可以套用到 Vaultwarden、Gitea 這些真正不能出事的服務。

先說結論:整個流程的核心只有一句話——永遠先還原到新位置測試,確認沒問題才動正式環境。

Docker 服務還原演練流程


🎯 這篇適合誰

你的情況 建議先看哪段
服務剛壞,正在找急救步驟 第一步:先停止,不要刪
想知道 Hyper Backup 怎麼還原單一資料夾 第二步:還原到新位置
不確定還原回來的資料是不是完整 第四步:驗證資料完整
服務好了但網址打不開 第六步:反向代理與網域檢查
沒壞,只是想照著演練一次 把演練變成每季習慣

🧨 情境:星期六早上,監控全滅

假設的故障場景是這樣的:

星期五晚上你更新了幾個容器,其中包括 Uptime Kuma。星期六早上發現通知全部靜悄悄——不是服務都很健康,而是 Uptime Kuma 自己掛了。打開內網網址 http://NAS-IP:3001,瀏覽器轉圈圈;Container Manager 裡容器反覆重啟;日誌顯示資料庫檔案錯誤。

這時候多數人的直覺是:把容器刪掉重裝。請忍住。重裝只能給你一個空白的 Uptime Kuma,你累積的幾十個監控項目、通知設定、幾個月的可用率歷史會全部歸零。這些東西都在 data/ 資料夾裡,而它現在可能只是「部分損毀」——你手上的每一個動作,都決定它是能救回來,還是被你自己覆蓋掉。

依照維運 SOP 的分層判斷表,「內網網址也打不開+容器持續重啟+日誌指向資料庫」,問題已經確定在應用程式資料層,不是網路、不是反向代理。可以進入還原流程。


🛑 第一步:先停止,不要刪

進入還原流程的第一件事,是把現場凍結下來。

cd /volume1/docker/uptime-kuma
docker compose stop
docker compose logs --tail=200 > ~/uptime-kuma-incident.log

三個動作,三個目的:

  1. stop 而不是 downstop 只是停止容器,容器和網路定義都還在;這個階段不需要移除任何東西。
  2. 把日誌存下來:容器一旦重建,舊日誌就沒了。這份日誌是事後判斷「當初為什麼壞」的唯一證據。
  3. 複製一份現場資料
cp -r /volume1/docker/uptime-kuma /volume1/docker/uptime-kuma-broken-20260703

第三步很多人會省略——「都壞掉了還留著幹嘛?」但「壞掉的資料」和「沒有資料」是兩回事。SQLite 資料庫損毀常常只是部分頁面出錯,萬一備份比想像中舊,這份損毀副本可能還救得出東西。維運最怕的不是第一個錯誤,而是為了救它又覆蓋掉最後一份可用資料——這句話在 SOP 那篇說過,這裡就是它實際的樣子。

⚠️ 整個流程中唯一絕對不要做的事:在確認備份可用之前,刪除任何原始資料夾。磁碟空間不夠再想辦法,順序不能反過來。


🗃️ 第二步:從備份還原到「新位置」

假設你照 Hyper Backup 完整教學 建立過備份任務,範圍涵蓋 /volume1/docker/。現在是它上場的時刻——但注意,我們不用「還原」按鈕,用「複製」

Hyper Backup 的完整還原預設會把資料放回原路徑、覆蓋現有內容。這正是我們要避免的:原資料夾要保留當現場。正確做法是用瀏覽方式把檔案取出來:

  1. 打開 Hyper Backup → 選擇備份任務 → 版本瀏覽(放大鏡圖示)。
  2. 選一個故障發生前的版本。看時間戳:故障是星期五晚上更新造成的,就選星期五白天或更早的版本。
  3. 瀏覽到 docker/uptime-kuma/data,右鍵 → 複製到
  4. 目的地選一個全新的資料夾,例如 /volume1/docker/restore-test/uptime-kuma/

幾個實務細節:

  • 版本不是越新越好。如果損毀發生在星期五 22:00,而備份任務星期五 23:00 跑過一次,那個 23:00 的版本備到的就是損毀後的資料。選版本前先想清楚故障時間點。
  • 順便把 docker-compose.yml.env 也復原出來。就算你覺得現有的沒壞,多拿一份出來對照,可以排除「其實是誰改過 Compose 檔」這種可能。
  • 如果你的備份在異地(例如 Hyper Backup 備份到 Cloudflare R2),流程相同,只是下載時間比較久——這也是演練的價值之一:你會親身知道異地還原一個服務要等多久。

🧪 第三步:用測試 Compose、不同 port 啟動

還原出來的資料,先不要接回正式服務。在測試資料夾建一份專用的 Compose 檔:

services:
  uptime-kuma-test:
    image: louislam/uptime-kuma:1
    container_name: uptime-kuma-test
    ports:
      - "3002:3001"
    volumes:
      - /volume1/docker/restore-test/uptime-kuma/data:/app/data
    restart: "no"

和正式檔相比有四個刻意的差異:

項目 正式 測試 為什麼
服務名稱 uptime-kuma uptime-kuma-test 避免撞名,兩者可以並存
對外 port 3001 3002 正式 port 保留,之後切換才乾淨
volume 路徑 原資料夾 restore-test/ 下的還原資料 這是整個演練的核心
restart unless-stopped "no" 測試容器不需要開機自動啟動

啟動並觀察:

cd /volume1/docker/restore-test/uptime-kuma
docker compose up -d
docker compose logs -f

如果日誌乾淨、沒有資料庫錯誤,開 http://NAS-IP:3002——看到登入頁,代表還原的資料至少讓服務跑得起來了。

💡 如果測試容器起不來、錯誤跟正式的一樣,這是重要線索:問題可能不在資料,而在 image 版本。試著在測試 Compose 裡指定更新前的版本 tag 再啟動一次。這就是 SOP 說「記錄目前運作中的版本」的原因——此刻你會很需要知道原本跑的是哪一版。


✅ 第四步:驗證資料完整

服務起得來不等於資料是完整的。登入測試環境(3002),逐項核對:

  • 登入帳密是原本的——能用舊密碼登入,代表使用者資料庫回來了。
  • 監控項目數量對不對——你的服務清單上有幾個監控就該有幾個。
  • 通知設定還在——打開任一個通知管道,設定值沒有變空白。
  • 歷史資料看得到——隨便點一個監控項目,可用率圖表有故障前的歷史。

換成別的服務,驗證的重點不同,但原則一樣——用「只有真實資料才答得出來」的問題來驗證:Vaultwarden 就登入後抽查幾筆密碼;Gitea 就 clone 一個 repository;Jellyfin 就確認觀看紀錄和媒體庫設定。不要只看首頁有沒有出現。

這一步同時回答了那個最根本的問題:你的備份是真的。很多人備份跑了一年,第一次驗證是在災難當下——那時候才發現範圍漏了、版本全是損毀後的,就真的太遲了。


🔁 第五步:切換正式

測試通過後,把服務接回正式環境。兩種做法:

做法 A:把還原資料搬回原路徑(推薦)

# 停掉測試容器
cd /volume1/docker/restore-test/uptime-kuma
docker compose down

# 原資料夾已有 broken 副本,清空後放入還原資料
rm -rf /volume1/docker/uptime-kuma/data
cp -r /volume1/docker/restore-test/uptime-kuma/data /volume1/docker/uptime-kuma/data

# 用原本的 Compose 啟動正式服務
cd /volume1/docker/uptime-kuma
docker compose up -d

Compose 檔、路徑、port 全部不變,反向代理和監控設定都不用動。注意 rm -rf 這行是本流程第一個不可逆動作——執行前確認 uptime-kuma-broken-* 副本存在、測試環境驗證通過。

做法 B:讓正式 Compose 指向新資料夾

改正式 Compose 檔的 volume 路徑,指向還原出來的資料夾。少一次複製,但路徑從此和服務清單、備份任務範圍不一致,三個月後的你大概率會忘記。除非資料量大到複製要跑很久,否則建議 A。

切換完成後,照 SOP 的更新後驗證流程再走一次:內網網址、核心功能、外部網址、日誌。都正常之後,broken 副本和 restore-test/ 保留一兩週再刪,不用急。


🌐 第六步:反向代理與網域檢查

如果你的服務有透過 Nginx Proxy Manager 對外,切回正式後多測一層:用外部網址https://服務.你的網域)完整走一次登入。

這次演練 port 沒變,反向代理理論上不受影響。但實務上「服務修好了、網址還是打不開」很常見,原因通常在:

  • 還原過程中容器重建,Docker 內部 IP 變了——如果 NPM 的 proxy host 是填容器 IP 而不是 NAS IP 或容器名稱,就會斷。
  • 切換時改了 port(做法 B 又順手改 port 的人),NPM 還指向舊 port。
  • 服務停機期間憑證剛好到期,NPM 續期失敗。

另外提醒一件演練時才會想到的事:NPM 自己也是一個 Docker 服務。它的 proxy host 設定、憑證都存在自己的 data/ 資料夾——它也在你的備份範圍嗎?如果哪天壞的不是 Uptime Kuma 而是 NPM 本身,所有服務的外部入口會一起消失。把它加進服務清單,備份等級標「高」。


🗓️ 把演練變成每季習慣

上面六步是「真的壞掉」的版本。而演練的精髓在於:不用等它壞

每季挑一個低風險服務,直接從第二步開始走:從備份取出資料 → 還原到測試資料夾 → 不同 port 啟動 → 驗證 → 刪掉測試環境。正式服務全程不動,風險是零,耗時大約 30 分鐘。

每季演練你會實際確認四件事:

  1. 備份範圍沒有漏——服務清單上的資料夾,備份裡真的找得到。
  2. 備份版本是好的——還原出來起得動、資料是完整的。
  3. Compose 和 .env 拿得回來——不是只有資料,連「怎麼跑起來」都救得回來。
  4. 你自己還記得流程——真正的災難現場沒有心情查文件,肌肉記憶才可靠。

第一次演練幾乎都會發現至少一個問題:某個 volume 不在備份範圍、.env 忘了備、版本保留數太少。在演練中發現,是收穫;在災難中發現,是損失。這 30 分鐘就是整個 3-2-1 備份策略裡投資報酬率最高的一段。


❓ 常見問題

Q:我用 Container Manager 圖形介面,沒用 SSH,也能照做嗎?

可以。停止容器、重建容器都能在 Container Manager 的「容器」頁完成;測試環境則用「專案」功能貼上測試 Compose 建立。只有複製資料夾的部分改用 File Station 操作。不熟 Compose 的話,先讀 Synology Docker Compose 完整教學,維運的每一步都會輕鬆很多。

Q:資料庫型服務(Immich、Nextcloud)也能這樣用檔案層級還原嗎?

要小心。SQLite 型服務(Uptime Kuma、Vaultwarden 預設、Gitea 預設)在容器停止後做檔案備份與還原,一般沒問題。但 PostgreSQL、MySQL 這類資料庫,在運行中做的檔案層級備份可能不一致,官方多半建議搭配資料庫匯出(dump)。演練時照服務官方的備份文件走,不要假設所有服務都跟 Uptime Kuma 一樣簡單。

Q:沒有故障前的備份版本怎麼辦?

先確認 broken 副本還在,然後看服務本身有沒有內建修復手段(例如 SQLite 的完整性檢查與匯出)。救不回來就只能重建服務、重新設定——然後把這次教訓變成備份任務:調高版本保留數、確認排程頻率跟得上你的資料變動速度。

Q:演練用的測試容器,會不會跟正式服務搶資料或互相干擾?

只要 volume 指向不同資料夾、port 不同、容器名稱不同,兩者完全獨立。唯一要注意的是有些服務會主動對外連線(例如發通知)——演練 Uptime Kuma 時測試環境的通知設定是真的,起來之後可能會發出誤報,可以先把測試容器的通知靜音或斷網。


還原演練跟消防演習是同一件事:沒有人希望用上,但每個人都該走過一次。

你不需要記住這篇的每一個指令,只需要記住那個順序——凍結現場、還原到新位置、測試、驗證、才切正式。走過一次之後,「服務壞了」就會從讓你心跳加速的意外,變成一個你知道從哪裡開始、也知道會在哪裡結束的流程。


🔗 延伸閱讀

這篇有幫助嗎? 備份是不是真的,只有還原那一刻才知道。