# 中控 · 局域网与反代部署说明

本文说明在 **局域网（IP + 端口）** 与 **宝塔/Nginx 反代（域名）** 两种场景下，如何配置中控与各实例，并实现：

- **从中控** 点「实例 / 策略交易 / 复盘」→ **免输入** 实例网页密码（SSO 临时链接，默认 **2 小时** 内有效、**单次使用**）
- **浏览器直链** 实例地址（反代域名或 `http://IP:端口`）→ 进入 **`/login`**，输入统一 **`APP_USERNAME` / `APP_PASSWORD`**

SSO 签名复用 **`HUB_BRIDGE_TOKEN`**（与中控调实例 API 相同，四所 `.env` 与 `manual_trading_hub/.env` 保持一致）。

**云服务器（VPS）** 的硬件、安全组、宝塔、环境变量与验收清单见 **[云服务器部署说明.md](./云服务器部署说明.md)**。

---

## 一、两种访问方式对照

| 项目 | 局域网 | 反代（域名） |
|------|--------|----------------|
| 中控地址 | `http://内网IP:5100` | `https://hub.你的域名.com` |
| 实例地址（浏览器） | `http://内网IP:5004` 等 | `https://okx.你的域名.com` 等 |
| `hub_settings` 里 `flask_url` | 建议写 **`http://内网IP:端口`** | 建议写 **`https://该实例域名`**（与浏览器一致） |
| 中控本机调实例 API | 可与浏览器相同；同机也可用 `http://127.0.0.1:端口` + `HUB_PUBLIC_ORIGIN` | 同机可用 `127.0.0.1:端口` 或域名（需 Nginx 转发 `X-Hub-Token`） |
| `HUB_PUBLIC_ORIGIN` | 若 `flask_url` 填 `127.0.0.1`，**必填** `http://内网IP` | 若 `flask_url` 已是完整域名，**可不设** |
| 宝塔 | 可不装反代，直连端口 | 每实例一个站点 + SSL；中控单独站点 |
| 直链登录 | 实例 `/login` | 实例 `/login` |
| 从中控打开 | `/hub-sso?token=...` 自动登录 | 同上 |

---

## 二、共用环境变量（必配）

### 2.1 中控 `manual_trading_hub/.env`

```bash
HUB_BRIDGE_TOKEN=请填一长串随机字符
HUB_USERNAME=admin          # 中控登录（建议设置）
HUB_PASSWORD=你的中控密码
HUB_SSO_TTL_SEC=7200        # 可选，默认 7200 = 2 小时
```

### 2.2 四个实例 `crypto_monitor_*/.env`

每个目录相同（**直链**时用这套登录实例网页）：

```bash
HUB_BRIDGE_TOKEN=与中控完全相同
APP_USERNAME=统一用户名
APP_PASSWORD=统一密码
# 云上切勿 APP_AUTH_DISABLED=true
```

### 2.3 子代理

`CONTROL_TOKEN` 可与 `HUB_BRIDGE_TOKEN` 相同；子代理只监听 `127.0.0.1`，**不要**对公网暴露 `15200`～`15203`。

---

## 三、局域网部署（IP + 端口）

适用：家里/办公室内网，例如服务器 `192.168.8.6`。

### 3.1 端口约定（示例，以你实际为准）

| 服务 | 端口 |
|------|------|
| 中控 hub | 5100 |
| OKX Flask | 5004 |
| 币安 Flask | 5001 |
| Gate 训练 | 5000 |
| Gate 趋势 | 5002 |
| agent | 15200～15203（仅本机） |

### 3.2 系统设置 `hub_settings.json`（网页「系统设置」保存）

浏览器里你会打开的地址，应使用 **内网 IP**，不要用 `127.0.0.1`（否则别的电脑上的浏览器会连到你本机）：

```json
{
  "flask_url": "http://192.168.8.6:5004",
  "agent_url": "http://127.0.0.1:15201"
}
```

说明：

- **`flask_url`**：给浏览器用的实例页地址 → 写 **`http://192.168.8.6:端口`**
- **`agent_url`**：仅中控服务器访问 → 写 **`http://127.0.0.1:1520x`**

各账户按上表改端口即可。

### 3.3 可选：`flask_url` 仍写 127.0.0.1 时

若坚持 `flask_url` 为 `http://127.0.0.1:5004`（仅 hub 与本机 Flask 同机），在中控 `.env` 增加：

```bash
HUB_PUBLIC_ORIGIN=http://192.168.8.6
```

中控会把返回给前端的链接从 `127.0.0.1` 替换为 `192.168.8.6`（端口保留）。

### 3.4 访问方式

1. 中控：`http://192.168.8.6:5100` → 登录中控 → 点「实例」→ 新标签进入 OKX，**无需**再输实例密码。  
2. 直链：`http://192.168.8.6:5004` → 出现登录页 → 输入 `APP_USERNAME` / `APP_PASSWORD`。

### 3.5 防火墙

内网自用：放行 `5100`、各 `APP_PORT`；**不要**对公网开放 agent 端口。

---

## 四、反代部署（域名 + 宝塔）

适用：云服务器，对外用 HTTPS 域名。

### 4.1 域名规划（示例）

| 站点 | 反代到 |
|------|--------|
| `hub.example.com` | `127.0.0.1:5100` |
| `okx.example.com` | `127.0.0.1:5004` |
| `binance.example.com` | `127.0.0.1:5001` |
| `gate.example.com` | `127.0.0.1:5000` |
| `gate-bot.example.com` | `127.0.0.1:5002` |

Flask / hub 进程仍只监听 **127.0.0.1** 或 `0.0.0.0` 本机端口，由 Nginx 对外提供 HTTPS。

### 4.2 宝塔操作要点

1. 每个域名 → **反向代理** → 目标 `http://127.0.0.1:对应端口`。  
2. 申请 **SSL**（Let’s Encrypt）。  
3. **不要**再给实例站加一层宝塔「访问密码」（避免与 Flask `/login` 重复）；直链鉴权用 **`APP_USERNAME` / `APP_PASSWORD`** 即可。  
4. 自定义 Nginx 配置中保留 WebSocket/大 body 如需；确保代理头：

```nginx
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
```

中控请求实例 API 时会带 **`X-Hub-Token`**，Nginx 默认会转发请求头，一般无需额外配置。

### 4.3 `hub_settings` 示例（反代）

```json
{
  "flask_url": "https://okx.example.com",
  "agent_url": "http://127.0.0.1:15201"
}
```

- 浏览器与 SSO 链接使用 **`https://okx.example.com`**。  
- 中控服务器拉 `/api/hub/*` 仍走本机 `agent_url`；`flask_url` 用域名时，hub 会请求 `https://okx.example.com/api/...`（同机可通即可）。

同机部署时也可：

- `flask_url`: `http://127.0.0.1:5004`  
- `HUB_PUBLIC_ORIGIN`: `https://okx.example.com`  

仅当**所有实例共用一个对外 IP、靠端口区分**时才适合用 `HUB_PUBLIC_ORIGIN`；**每实例独立域名**时，请直接在 `flask_url` 写该实例域名。

### 4.4 中控 `.env`（反代建议）

```bash
HUB_BRIDGE_TOKEN=...
HUB_USERNAME=...
HUB_PASSWORD=...
HUB_COOKIE_SECURE=true          # 中控为 HTTPS 时建议开启
```

### 4.5 访问方式

1. `https://hub.example.com` 登录中控 → 点「打开实例」→ `https://okx.example.com/hub-sso?...` → 进入系统。  
2. 地址栏直接输入 `https://okx.example.com` → `/login` → 实例账号密码。

---

## 五、SSO 行为说明（2 小时）

| 项 | 说明 |
|----|------|
| 有效期 | 默认 **7200 秒（2 小时）**，`HUB_SSO_TTL_SEC` 可改 |
| 单次使用 | 同一链接成功登录后 **不能再用**；需在中控重新点「打开实例」 |
| 密钥 | 复用 **`HUB_BRIDGE_TOKEN`** |
| 直链 | 无 token → 正常 **`/login`** |

---

## 六、部署与重启顺序

```bash
cd /opt/crypto_monitor
# 各实例
pm2 restart crypto_okx crypto_binance crypto_gate crypto_gate_bot   # 名称以你为准

cd manual_trading_hub
pm2 restart manual-trading-hub manual-agent-binance manual-agent-okx manual-agent-gate manual-agent-gate-bot
```

改 `hub_settings` 或 `.env` 后重启 **hub + 对应实例 Flask**（`hub_bridge` 与 `/hub-sso` 在实例进程内）。

---

## 七、验收清单

- [ ] 四实例 `.env` 与中控 `HUB_BRIDGE_TOKEN` 一致  
- [ ] 四实例 `APP_USERNAME` / `APP_PASSWORD` 一致  
- [ ] 局域网：`flask_url` 为 `http://IP:端口`；反代：`flask_url` 为 `https://域名`  
- [ ] 已登录中控 → 点「实例」→ **无**实例登录页  
- [ ] 隐身窗口直链实例域名/IP → **有** `/login`  
- [ ] 复制「打开实例」完整 URL，用过一次后再开 → 失效并回到登录页  

---

## 八、常见问题

**Q：从中控打开仍要登录？**  
- 检查实例是否已 `git pull` 并重启（需有 `/hub-sso`）。  
- `HUB_BRIDGE_TOKEN` 是否四所一致。  
- `hub_settings` 里该账户 `key` 是否与 `install_on_app(exchange=...)` 一致（如 `okx`、`binance`、`gate`、`gate_bot`）。

**Q：直链也要登录中控？**  
- 不应。直链只走实例 `/login`。若跳到中控，检查是否点错链接或 Nginx 配错站点。

**Q：链接多久失效？**  
- 签发后 **2 小时**内且 **未使用过**；过期或已用需在中控重新点打开。

更多故障见 [常见问题.md](./常见问题.md)、[部署文档.md](./部署文档.md)。
