# 宝塔面板部署与反向代理

> 适用场景：知命阁已通过 **Docker** 跑在 `127.0.0.1:3130`，再用 **宝塔（BT Panel）** 绑定域名（如 `gate.hyf2.cc`）对外提供 HTTPS 访问。

---

## 一、架构说明

```
浏览器  →  HTTPS (443)  →  宝塔 Nginx  →  http://127.0.0.1:3130  →  Docker 容器 zhimingge
```

- 应用本身监听 **3130**，不直接暴露公网也可（仅 Nginx 反代）。
- AI 解读走 **`POST /api/ai`** 流式接口，Nginx **必须关闭缓冲**，否则页面上会一直空白。
- 浏览器请求的是 **域名**，`curl 127.0.0.1:3130` 能通不代表域名一定通，两处都要测。

---

## 二、Docker 部署（首次 / 更新）

### 2.1 首次部署

```bash
cd /opt
git clone https://git.bz121.com/dekun/zhimingge.git zhimingge
cd /opt/zhimingge

cp .env.example .env.local
nano .env.local          # 填写 OPENAI_API_KEY 等
chmod 600 .env.local

docker compose build --no-cache
docker compose up -d
```

### 2.2 环境变量（`.env.local`）

```env
OPENAI_API_KEY=sk-你的密钥
OPENAI_BASE_URL=https://op.bz121.com/v1
OPENAI_MODEL=huihui_ai/gemma-4-abliterated:e4b
```

| 变量 | 必填 | 说明 |
|------|------|------|
| `OPENAI_API_KEY` | 是 | AI 接口密钥 |
| `OPENAI_BASE_URL` | 否 | 与 `OPENAI_API_BASE` 二选一，默认 `https://op.bz121.com/v1` |
| `OPENAI_MODEL` | 否 | 默认 `huihui_ai/gemma-4-abliterated:e4b` |

### 2.3 日常更新

```bash
cd /opt/zhimingge
bash scripts/docker-deploy.sh
```

或手动：

```bash
git pull origin main
docker compose build --no-cache
docker compose up -d --force-recreate
```

### 2.4 确认容器正常

```bash
docker compose ps
docker exec zhimingge printenv OPENAI_API_KEY | head -c 8   # 应看到 sk- 开头
curl -s http://127.0.0.1:3130/api/health
# {"ok":true,"service":"zhimingge","apiAi":true,...}
```

更多 Docker 说明见 [DOCKER.md](./DOCKER.md)（含**镜像清理**）。

### 2.5 清理无用 Docker 镜像

多次 `build --no-cache` 后磁盘会堆积旧层，建议定期执行：

```bash
cd /opt/zhimingge
bash scripts/docker-prune.sh
```

深度清理（删除所有未被容器使用的镜像）：

```bash
bash scripts/docker-prune.sh --all
```

详细说明见 [DOCKER.md — 镜像清理](./DOCKER.md#镜像清理)。


### 3.1 添加网站

1. 宝塔 → **网站** → **添加站点**
2. 域名填：`gate.hyf2.cc`（换成你的域名）
3. PHP 选 **纯静态** 或随意（实际由反代到 3130）
4. 按需申请 **SSL**（Let's Encrypt）

### 3.2 配置反向代理

**方式 A（推荐）**：网站 → 选中站点 → **反向代理** → **添加反向代理**

- 代理名称：`zhimingge`
- 目标 URL：`http://127.0.0.1:3130`
- 发送域名：`$host`（不要填 `127.0.0.1`）

添加后点击 **配置文件**，找到 `#PROXY-START/` … `#PROXY-END/` 整段，**替换为下方完整配置**。

**方式 B**：网站 → **设置** → **配置文件**，在 `server { ... }` 内手动加入 `location`。

---

## 四、宝塔反代配置（完整可复制）

将站点配置中 `#PROXY-START/` 到 `#PROXY-END/` **整段替换**为：

```nginx
#PROXY-START/

location ^~ /
{
    proxy_pass http://127.0.0.1:3130;
    proxy_http_version 1.1;

    # 必须用真实域名，不要用 127.0.0.1
    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;
    proxy_set_header REMOTE-HOST $remote_addr;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;

    # AI 流式输出：必须关闭缓冲
    proxy_buffering off;
    proxy_cache off;
    proxy_read_timeout 300s;
    proxy_send_timeout 300s;
    chunked_transfer_encoding on;

    add_header X-Cache $upstream_cache_status;

    # 静态资源短缓存
    set $static_filelkzjrLn7 0;
    if ( $uri ~* "\.(gif|png|jpg|css|js|woff|woff2)$" )
    {
        set $static_filelkzjrLn7 1;
        expires 1m;
    }
    if ( $static_filelkzjrLn7 = 0 )
    {
        add_header Cache-Control no-cache;
    }
}

#PROXY-END/
```

### 4.1 与默认宝塔配置的差异（必改项）

| 原配置（错误） | 应改为 | 原因 |
|----------------|--------|------|
| `proxy_set_header Host 127.0.0.1;` | `proxy_set_header Host $host;` | Next.js 需要正确 Host，否则路由 / API 异常 |
| （无） | `proxy_set_header X-Forwarded-Proto $scheme;` | HTTPS 站点识别协议 |
| （无） | `proxy_buffering off;` | **AI 流式必须**，否则浏览器收不到逐字输出 |
| （无） | `proxy_read_timeout 300s;` | 模型生成较慢时不超时 |

保存后在宝塔点击 **重载配置**，或 SSH 执行：

```bash
nginx -t && systemctl reload nginx
```

### 4.2 注意

- 只保留 **一层** 到 3130 的反代，避免同一站点重复添加多个冲突的 `location /`。
- 若曾用 **PM2** 占 3130，需先停掉：`pm2 stop zhimingge; pm2 delete zhimingge`
- 防火墙可只开放 80/443，**不必**对公网开放 3130。

---

## 五、验证（本地 + 域名都要测）

### 5.1 健康检查

```bash
# 直连容器（应返回 JSON）
curl -s http://127.0.0.1:3130/api/health

# 经域名（应同样返回 JSON；若 HTML/404 则是 Nginx 问题）
curl -s https://gate.hyf2.cc/api/health
```

期望输出示例：

```json
{"ok":true,"service":"zhimingge","apiAi":true,"build":"dba0245+"}
```

### 5.2 AI 流式接口

```bash
curl -N -X POST https://gate.hyf2.cc/api/ai \
  -H "Content-Type: application/json" \
  -d '{"mode":"bazi","payload":{"input":{"date":"1990-01-01","time":"12:00","gender":"male","longitude":120},"question":"测试","birthPlaceName":"上海市"}}'
```

应看到 **中文内容逐字输出**，而不是 HTML 404 页面。

### 5.3 六爻 AI 解读（页面）

1. 打开 `https://gate.hyf2.cc/liuyao`
2. 填写问事、地域、完成起卦
3. 点击 **AI 解读**
4. 结果区应出现流式文字；加载中会显示「AI 分析中...」

---

## 六、常见问题

| 现象 | 可能原因 | 处理 |
|------|----------|------|
| `curl 127.0.0.1:3130/api/health` 正常，域名 404 | Nginx 未反代或未重载 | 检查宝塔反代配置，`nginx -t && systemctl reload nginx` |
| 域名返回 HTML 404 | 反代目标错误或旧容器 | 确认 `proxy_pass http://127.0.0.1:3130`，`docker compose ps` |
| 页面 AI 一直空白 | `proxy_buffering` 未关 | 按第四节加上 `proxy_buffering off` |
| 页面 AI 报错「接口未到达后端」 | `Host` 设为 127.0.0.1 | 改为 `Host $host` |
| AI 很快超时 | 读超时太短 | 设置 `proxy_read_timeout 300s` |
| 构建后仍无 `/api/ai` | 镜像未更新 | `git pull` + `docker compose build --no-cache` + `up -d --force-recreate` |
| 容器内无密钥 | `.env.local` 未挂载 | 检查 `docker-compose.yml` 的 `env_file`，`docker exec zhimingge printenv OPENAI_API_KEY` |

---

## 七、相关文档

- [DOCKER.md](./DOCKER.md) — Docker 构建、环境变量、排错
- [NGINX.md](./NGINX.md) — 非宝塔、手写 Nginx 配置参考
- [DEPLOY.md](./DEPLOY.md) — PM2 备选部署
