備份與還原
版本:v1.2 | 更新日期:2026-06-16
本指南說明如何備份、還原和遷移 Config Server 的設備資料,適用於本地端(SERVER_ROLE=local)和雲端(SERVER_ROLE=cloud)兩種角色。
#1. 資料結構總覽
Config Server 的資料儲存在 config-server/data/ 目錄下,採用檔案系統作為持久層(無外部資料庫)。
config-server/data/
├── licenses.json ← 授權記錄(Cloud-only)
├── <device-id>/ ← 每台裝置一個子目錄
│ ├── config.json ← 設備配置快照(心跳上傳)
│ ├── web/ ← Web UI 檔案(index.html.gz)
│ └── firmware/ ← OTA 韌體暫存#關鍵檔案說明
| 檔案 | 用途 | 來源 |
|---|---|---|
config.json |
設備的完整配置(網路、IO、MQTT、規則等) | 裝置心跳自動上傳 |
licenses.json |
所有裝置的授權啟用記錄 | Cloud 授權 API |
web/ |
(舊)設備 Web UI 上傳快取 | 已停用 —— upload_web.py 已廢除,Web 資產改隨 .mesb 一檔投遞(見 guide-ota-embedded-web.md) |
firmware/ |
設備 OTA 韌體暫存 | Dashboard 上傳 |
#2. 備份
#2.1 完整備份(推薦)
備份整個 data/ 目錄即可涵蓋所有設備資料:
# 建立帶時間戳的備份
cd config-server
tar -czf backup-$(date +%Y%m%d-%H%M%S).tar.gz data/#2.2 單一設備備份
若只需備份特定設備:
# 替換 <DEVICE_ID> 為實際設備 ID
tar -czf backup-<DEVICE_ID>.tar.gz data/<DEVICE_ID>/#2.3 透過 API 匯出設備配置
# 從 Config Server 匯出設備當前配置
curl -s http://localhost:8888/api/devices/<DEVICE_ID>/config | jq . > device_backup.json#2.4 建議的備份頻率
| 環境 | 頻率 | 方式 |
|---|---|---|
| 開發/測試 | 手動 | 功能開發前後各一次 |
| 生產(本地) | 每日 | cron + tar |
| 生產(雲端) | 每小時 | cron + rsync 或雲端快照 |
#3. 還原
#3.1 完整還原
cd config-server
# 停止伺服器
# pm2 stop config-server 或 Ctrl+C
# 還原
tar -xzf backup-20260324-120000.tar.gz
# 重新啟動
node server.js
# 或 pm2 restart config-server#3.2 單一設備還原
tar -xzf backup-<DEVICE_ID>.tar.gz -C config-server/#3.3 透過 API 匯入設備配置
curl -s -X POST http://localhost:8888/api/devices/<DEVICE_ID>/config \
-H "Content-Type: application/json" \
-d @device_backup.json#4. 遷移
#4.1 本地端 → 本地端(換機器)
- 停止舊機器上的 Config Server。
- 複製整個
config-server/目錄到新機器:bash rsync -avz config-server/ new-host:/path/to/config-server/ - 在新機器上安裝依賴並啟動:
bash cd config-server npm install SERVER_ROLE=local PORT=8888 node server.js - 更新裝置的 Config Server URL(透過 Web UI「設定 → 伺服器」卡片)。
#4.2 本地端 → 雲端
- 備份
data/目錄。 - 將
data/複製到雲端伺服器。 - 設定環境變數:
bash export SERVER_ROLE=cloud export PORT=3001 export FIREBASE_SERVICE_ACCOUNT=/path/to/firebase-key.json - 啟動伺服器。雲端角色會額外載入
license模組。 - 裝置端需更新 Config Server URL 為雲端地址。
#4.3 雲端 → 本地端
- 匯出
data/和licenses.json。 - 複製到本地機器。
- 使用
SERVER_ROLE=local啟動。- 注意:
licenses.json在本地模式下不會被使用,但保留以備未來遷回雲端。
- 注意:
#5. 注意事項
#5.1 裝置端配置同步
[!IMPORTANT] Config Server 儲存的是裝置上傳的快照,而非「唯一真實來源」。裝置的 QSPI Flash(
/fs/config.json)才是運行中的主配置。若兩者不一致,以裝置端為準。
#5.2 授權資料(Cloud-only)
licenses.json 包含所有裝置的授權狀態記錄。遷移時必須一併複製此檔案,否則已啟用的裝置會在雲端顯示為未授權。
#5.3 韌體檔案
config-server/firmware/ 目錄儲存透過 Dashboard 上傳的韌體版本。這些檔案較大(約 500KB-1MB),備份時請確認磁碟空間充足。
#5.4 敏感資訊
.env 檔案包含 Firebase 金鑰等敏感資訊,不應納入備份壓縮檔中。建議單獨管理:
# 備份時排除 .env
tar -czf backup.tar.gz --exclude='.env' data/#6. 自動備份腳本範例
#!/bin/bash
# config-server-backup.sh
# 每日執行:crontab -e → 0 2 * * * /path/to/config-server-backup.sh
BACKUP_DIR="/backups/config-server"
DATA_DIR="/path/to/config-server/data"
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
mkdir -p "$BACKUP_DIR"
tar -czf "$BACKUP_DIR/backup-$TIMESTAMP.tar.gz" -C "$(dirname $DATA_DIR)" data/
# 保留最近 30 天的備份
find "$BACKUP_DIR" -name "backup-*.tar.gz" -mtime +30 -delete
echo "[$(date)] 備份完成: backup-$TIMESTAMP.tar.gz"#7. 雙路徑備援:device push 到雲端+地端兩個 cs(v5.9.114+)
每台 device 同時支援 push config 到:
- Cloud cs(內建
https://opta.smms.com.tw,總是 active,無法關閉) - Local cs(
config.configServer.url有設才 active)
兩條路徑彼此獨立,任何一條成功都會更新 lastPushAt。Cloud 斷線時 local 仍累積 snapshot 歷史,反之亦然。
#設定 device 指向 local cs
device 端 admin token 起 curl:
DEV=192.168.0.31; AUTH="Authorization: Bearer <device-admin-token>"
curl -X POST -H "$AUTH" -H "Content-Type: application/json" \
-d '{"url":"http://192.168.0.120:8888","token":"admin-token","enabled":true,"autoPush":true}' \
http://$DEV/api/configserver之後 device 改 config / 手動 POST /api/configserver/push / 心跳 autoPush 都會同時打兩邊。
#觀察 push 結果(fw v5.9.119+)
curl http://$DEV/api/configserver | jq .push回傳 push.cloud 跟 push.local 各自的 {result, httpCode, ageS, failCount, cooldownMsLeft}。連續失敗 N 次(PUSH_FAIL_THRESHOLD)會進 5 min cooldown,cooldown 期間 skip 該路徑,另一條仍正常推。
#注意
- Local cs 不在線時 device 仍會嘗試 push、進 cooldown — 這是「fail-fast」設計,不會 hang 主迴圈。
- Local cs 啟動後不會自動被 device 發現,必須由人工
POST /api/configserver設 URL。 - 把
enabled=false或url=""即可關閉 local push,cloud push 不受影響。
#8. PG 備份監控(v2.2.6 cs+)
opta-backup 容器每日 pg_dump,預設 BACKUP_INTERVAL_SEC=86400 (24h)、BACKUP_KEEP_DAYS=14。
不必 SSH 就能查健康狀態:
curl -H "Authorization: Bearer <admin-jwt>" \
https://opta.smms.com.tw/api/admin/backup-status回傳:
{
"mounted": true,
"dumpDir": "/var/backups/pg",
"dumpCount": 11,
"lastDumpFile": "optacs-20260519T065122Z.dump",
"lastDumpAt": "2026-05-19T06:51:23.139Z",
"hoursSinceLastDump": 22.7,
"oldestDumpAt": "2026-05-09T06:51:20.218Z",
"totalSize": 228239,
"healthy": true
}healthy: false 表示最後一次 dump 超過 30 小時 — 該檢查 backup container 是否還活著(docker ps opta-backup)。