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

本文说明在 **局域网(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`～`15202`.

---

## 三,局域网部署(IP + 端口)

适用:家里/办公室内网,例如服务器 `192.168.8.6`.

### 3.1 端口约定(示例,以你实际为准)

| 服务 | 端口 |
|------|------|
| 中控 hub | 5100 |
| OKX Flask | 5004 |
| 币安 Flask | 5001 |
| Gate | 5000 |
| agent | 15200～15202(仅本机) |

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

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 # 名称以你为准

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

改 `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`).

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

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

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