# 本地数据备份与迁移到云服务器

本文说明如何把 **本机** 上运行的 `crypto_monitor`（四实例 + 中控）的**业务数据**迁到 **云 VPS**，并正确改配置。  
**不迁移** 本机 Python 虚拟环境（`.venv`），云上重新 `pip install` 即可。

相关：[云服务器部署说明.md](./云服务器部署说明.md) · [部署文档.md](./部署文档.md)

---

## 一、要迁什么、不迁什么

### 必须迁移（业务数据）

| 路径（每个实例目录下） | 内容 |
|------------------------|------|
| `crypto.db`（或 `.env` 里 `DB_PATH` 指向的文件） | 监控单、关键位、交易记录、复盘、运行时开关等 **SQLite 全库** |
| `static/images/`（或 `UPLOAD_DIR`） | 上传图、复盘截图等 |
| `static/images/order_charts/`（或 `ORDER_CHART_DIR`） | 订单 K 线图（若开启） |

四个实例 **各有一份独立库**：

- `crypto_monitor_binance/crypto.db`
- `crypto_monitor_okx/crypto.db`
- `crypto_monitor_gate/crypto.db`
- `crypto_monitor_gate_bot/crypto.db`

### 中控额外迁移

| 路径 | 内容 |
|------|------|
| `manual_trading_hub/hub_settings.json` | 账户 URL、启用状态、能力勾选（网页「系统设置」保存的文件） |
| `manual_trading_hub/hub_ai_summaries.json` | 中控 AI 今日总结（`/ai`） |
| `manual_trading_hub/hub_ai_chat.json` | 中控 AI 聊天会话 |

### 不要直接覆盖拷贝（需在云上重写）

| 文件 | 说明 |
|------|------|
| 各目录 `.env` | 含 API 密钥：可在云上**手工新建**，从本机抄密钥，但须改 **`flask_url`、代理、公网相关项**（见下文） |
| `.venv/`、`__pycache__/` | 云上重建 |
| PM2 日志 | 无需迁 |

### 可选

- 本机 `manual_trading_hub/.env` 里的 `HUB_BRIDGE_TOKEN`、`HUB_PASSWORD` 等：记下后在云上填入，**不要**把含密钥的 `.env` 发到公开网盘。

---

## 二、迁移前准备（本地）

### 1. 停服务（避免数据库半写入）

```bash
# 本机：停中控与子代理
cd manual_trading_hub
pm2 stop manual-trading-hub manual-agent-binance manual-agent-okx manual-agent-gate manual-agent-gate-bot

# 本机：停四个 Flask（进程名以你 pm2 list 为准）
pm2 stop crypto_okx crypto_binance crypto_gate crypto_gate_bot
# 或各目录 ecosystem 里的名字
```

未用 PM2 时，结束对应 Python/Flask 进程后再备份。

### 2. 确认数据库文件位置

各实例目录下查看 `.env` 中 `DB_PATH`（默认 `crypto.db`）。若存在 `crypto.db-wal`、`crypto.db-shm`，**必须先停服务** 再备份。

---

## 三、本地备份（推荐用自带脚本）

每个实例目录执行（会备份 **库 + static/images**）：

```bash
cd crypto_monitor_okx
bash scripts/backup_data.sh
# 默认输出到 /root/backups/crypto_monitor_okx/YYYY-MM-DD/
# 本机可改环境变量：BACKUP_ROOT=~/crypto_backups bash scripts/backup_data.sh
```

对 `crypto_monitor_binance`、`crypto_monitor_gate`、`crypto_monitor_gate_bot` **各执行一次**。

脚本产物示例：

```text
~/crypto_backups/crypto_monitor_okx/2026-05-21/
  crypto.db
  static_images.tar.gz
  manifest.txt
```

### 手工打包（不用脚本时）

在仓库根目录示例：

```bash
BACKUP=~/crypto_migrate_$(date +%Y%m%d)
mkdir -p "$BACKUP"

for dir in crypto_monitor_okx crypto_monitor_binance crypto_monitor_gate crypto_monitor_gate_bot; do
  tar -czf "$BACKUP/${dir}.tar.gz" \
    -C "$dir" crypto.db static/images 2>/dev/null || \
  tar -czf "$BACKUP/${dir}.tar.gz" -C "$dir" crypto.db
done

cp manual_trading_hub/hub_settings.json "$BACKUP/" 2>/dev/null || true
cp manual_trading_hub/hub_ai_summaries.json "$BACKUP/" 2>/dev/null || true
cp manual_trading_hub/hub_ai_chat.json "$BACKUP/" 2>/dev/null || true
```

---

## 四、上传到云服务器

在**你电脑**上（把 `USER`、`云IP` 换成实际值）：

```bash
# 打包整个备份目录
tar -czf crypto_migrate.tar.gz -C ~ crypto_backups   # 或你的 BACKUP 路径

scp crypto_migrate.tar.gz USER@云IP:/tmp/
scp manual_trading_hub/hub_settings.json USER@云IP:/tmp/   # 若单独备份
```

大文件可用 **rsync**（支持断点续传）：

```bash
rsync -avz --progress ~/crypto_backups/ USER@云IP:/tmp/crypto_backups/
```

---

## 五、云上恢复数据

假设代码已在 `/opt/crypto_monitor`（`git clone` 或 `rsync` 代码均可，**代码与数据分开**）。

```bash
ssh USER@云IP
cd /opt/crypto_monitor

# 解压（若用 scp 单包）
tar -xzf /tmp/crypto_migrate.tar.gz -C /tmp

# 按实例恢复（示例：OKX）
pm2 stop crypto_okx 2>/dev/null || true
cp /tmp/crypto_backups/crypto_monitor_okx/2026-05-21/crypto.db crypto_monitor_okx/crypto.db
tar -xzf /tmp/crypto_backups/crypto_monitor_okx/2026-05-21/static_images.tar.gz -C crypto_monitor_okx/
# 若 tar 里是 static/images 目录结构，确认解压后路径为 crypto_monitor_okx/static/images

# 对其余三所重复同样步骤
```

恢复中控设置：

```bash
cp /tmp/hub_settings.json manual_trading_hub/hub_settings.json
# 或解压备份里带的 hub_settings.json
```

**权限**（避免 Flask 写库失败）：

```bash
sudo chown -R 运行用户:运行用户 /opt/crypto_monitor/crypto_monitor_*/crypto.db
sudo chown -R 运行用户:运行用户 /opt/crypto_monitor/crypto_monitor_*/static/images
```

---

## 六、云上必须改的配置（比迁移本身更重要）

数据文件原样拷过去不够，**.env 与 hub_settings 要按云环境改**。

### 1. 各实例 `crypto_monitor_*/.env`

从本机**抄写** API 密钥等，并调整：

| 项 | 本地常见 | 云上建议 |
|----|----------|----------|
| `OKX_SOCKS_PROXY` 等 | `socks5h://127.0.0.1:1080` | **留空**（直连），除非云上仍访问不了交易所 |
| `APP_AUTH_DISABLED` | 可能为 true（本机） | **false** 或未设置 |
| `APP_USERNAME` / `APP_PASSWORD` | 可有 | 设统一强密码（直链登录） |
| `HUB_BRIDGE_TOKEN` | 有 | 与中控 **完全一致** |

### 2. `manual_trading_hub/.env`

见 [云服务器部署说明.md](./云服务器部署说明.md)：`HUB_PASSWORD`、`HUB_BRIDGE_TOKEN`、`HUB_COOKIE_SECURE=true` 等。

### 3. `hub_settings.json` 里的 URL

**必须**改成浏览器能打开的地址：

| 字段 | 云上 |
|------|------|
| `flask_url` | `https://okx.你的域名.com`（每实例不同子域） |
| `agent_url` | `http://127.0.0.1:15201`（保持本机，勿写公网 IP） |

本机若是 `http://192.168.x.x:5004` 或 `http://127.0.0.1:5004`，上云后**一定要改**，否则「打开实例」会指错地址。

---

## 七、云上启动与验收

```bash
# 依赖（各目录 venv + manual_trading_hub）
# 见 云服务器部署说明.md、部署文档.md

cd /opt/crypto_monitor
# 先四实例 Flask，再 manual_trading_hub ecosystem
pm2 start ...
pm2 save
```

验收：

- [ ] 各实例网页能登录，**交易记录 / 关键位 / 监控单** 与本地一致  
- [ ] 复盘图片能显示（`static/images` 路径正确）  
- [ ] 中控监控卡片能读到持仓；`hub_settings` 账户 URL 正确  
- [ ] 本机已 **停止** 或不再用同一 API Key 同时跑两套（避免重复下单）

---

## 八、迁移策略建议

### 方案 A：一次性切换（简单）

1. 本地停 PM2 → 备份 → 上传 → 云上恢复 → 改配置 → 只跑云端。  
2. 适合能接受 **短暂停机**（几十分钟）。

### 方案 B：先云后停本地（稳一点）

1. 云上先部署代码、空库跑通；  
2. 临近切换时再备份本地**最新**库覆盖云上；  
3. 切换时刻停本地、启云上。  
4. 减少「备份到上线」之间的数据空窗。

### 注意

- **同一交易所 API Key 不要本地和云上同时自动交易**，以免重复挂单。  
- 迁移后第一次在云上打开，建议先看监控单、持仓是否与预期一致，再放开自动逻辑。

---

## 九、常见问题

**Q：只拷 `crypto.db` 不够吗？**  
- 复盘、上传相关功能还依赖 `static/images`；建议库 + 图片一起迁。

**Q：迁移后 OKX 监控单没了？**  
- 查是否拷错目录（四所各一个库）、或恢复后用了空库路径（`DB_PATH` 不一致）。

**Q：图片 404？**  
- 检查 `static/images` 是否解压到实例目录下；数据库里路径若为相对路径，一般与目录结构一致即可。

**Q：本地还用 SOCKS，云上要不要？**  
- 云上通常 **不需要** SSH 隧道；见 [云服务器部署说明.md](./云服务器部署说明.md) 与此前说明：直连稳定后去掉 `*_SOCKS_PROXY`。

---

## 十、相关脚本

各实例目录：

```bash
bash scripts/backup_data.sh
```

环境变量：`BACKUP_ROOT`、`BACKUP_RETENTION_DAYS`、`BACKUP_INSTANCE`（见脚本内注释）。
