docs(部署方案): 同步 NAS+甲骨文反代决策 + 生成部署骨架
- SRS/SDD/README/PROGRESS 统一将部署目标由"美国服务器"更正为"NAS 本机 + 甲骨文服务器反向代理"(此前已确认但未入库) - 新增 docker-compose.yml / nginx.conf / .env.example(对应待办任务4) - 相对 SDD 草稿的安全加固:one-api 端口改绑 127.0.0.1(原为公网端口映射),lobe-chat 不再发布主机端口,仅走容器内网
This commit is contained in:
21
.env.example
Normal file
21
.env.example
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# NexusAI 部署环境变量模板
|
||||||
|
# 复制为 .env 并填入真实值;.env 已加入 .gitignore,切勿提交版本库。
|
||||||
|
|
||||||
|
# ---- MySQL ----
|
||||||
|
MYSQL_ROOT_PASSWORD=change_me_strong_password
|
||||||
|
|
||||||
|
# ---- One-API ----
|
||||||
|
# One-API 后台管理员登录后生成的对外聚合 Token(sk-xxxx),写入 LobeChat 使用
|
||||||
|
ONE_API_TOKEN=sk-change_me_after_one_api_setup
|
||||||
|
|
||||||
|
# ---- LobeChat ----
|
||||||
|
# 前端访问密码(Access Code),自定义,建议高复杂度
|
||||||
|
LOBE_ACCESS_CODE=change_me_access_code
|
||||||
|
|
||||||
|
# ---- 各 AI 渠道 API Key ----
|
||||||
|
# 在 One-API 后台添加渠道时手动填入,此处仅作为记录/备用,不由容器直接读取
|
||||||
|
GEMINI_API_KEY=
|
||||||
|
NVIDIA_API_KEY=
|
||||||
|
GROQ_API_KEY=
|
||||||
|
OPENROUTER_API_KEY=
|
||||||
|
MISTRAL_API_KEY=
|
||||||
34
PROGRESS.md
34
PROGRESS.md
@@ -6,14 +6,25 @@
|
|||||||
|
|
||||||
| 服务 | 节点 | 状态 | 说明 |
|
| 服务 | 节点 | 状态 | 说明 |
|
||||||
|------|------|------|------|
|
|------|------|------|------|
|
||||||
| Nginx | 美国服务器(待申请) | ⏳ 未部署 | HTTPS 反向代理层 |
|
| Oracle 反代层 | 甲骨文服务器 129.146.203.203 | ⏳ 未配置 | frp/nginx 反代端口 → NAS 网关入口 |
|
||||||
| LobeChat | 美国服务器(待申请) | ⏳ 未部署 | 前端对话界面 |
|
| Nginx | NAS 192.168.50.64 | ⏳ 未部署 | HTTPS 反向代理层 |
|
||||||
| One-API | 美国服务器(待申请) | ⏳ 未部署 | 网关聚合层 |
|
| LobeChat | NAS 192.168.50.64 | ⏳ 未部署 | 前端对话界面 |
|
||||||
| MySQL | 美国服务器(待申请) | ⏳ 未部署 | One-API 数据存储 |
|
| One-API | NAS 192.168.50.64 | ⏳ 未部署 | 网关聚合层 |
|
||||||
|
| MySQL | NAS 192.168.50.64 | ⏳ 未部署 | One-API 数据存储 |
|
||||||
|
|
||||||
|
## 2026-08-23 部署骨架生成:docker-compose.yml / nginx.conf / .env.example
|
||||||
|
|
||||||
|
- **产出**:仓库根目录新增 `docker-compose.yml`(mysql / one-api / lobe-chat / nginx 四服务)、`nginx.conf`(443 SSL + 80→443 跳转 + SSE 流式透传配置)、`.env.example`(含 MYSQL_ROOT_PASSWORD / ONE_API_TOKEN / LOBE_ACCESS_CODE / 各渠道 Key 占位)。
|
||||||
|
- **相对 SDD 草稿的两处安全加固**:
|
||||||
|
1. `one-api` 端口改为 `127.0.0.1:3000:3000`(原草稿是 `3000:3000` 全网卡暴露),管理需通过 SSH 隧道(`ssh -p 2222 -L 3000:127.0.0.1:3000 ericwyuan@192.168.50.64`)转发后本地访问,符合 SRS FR-5.2 / SDD 第5章"后台管理端口不映射公网"的要求。
|
||||||
|
2. `lobe-chat` 不再发布主机端口(原草稿 `3210:3210`),仅通过 `ai-network` 容器网络被 nginx 访问,进一步收敛暴露面。
|
||||||
|
- **nginx.conf 待确认项**:`server_name` 暂用 `_` 通配(域名与证书方案见 SDD 8.4 待确认事项,任务 6);`certs/fullchain.pem` / `privkey.pem` 尚未生成,需任务 6 确认证书方案后补充。
|
||||||
|
- **尚未做**:实际登录 NAS 部署(依赖新 Gemini/NVIDIA Key 与 Oracle 反代方式确认,任务 1-3, 5, 6)。
|
||||||
|
|
||||||
## 2026-08-23 项目启动:文档入库 + 仓库初始化
|
## 2026-08-23 项目启动:文档入库 + 仓库初始化
|
||||||
|
|
||||||
- **决策**:采用成熟开源组件(Nginx + LobeChat + One-API + MySQL)容器化搭建,不重复造轮子;网关对外统一暴露 `auto-vision` / `auto-text` 两个聚合模型名。
|
- **决策**:采用成熟开源组件(Nginx + LobeChat + One-API + MySQL)容器化搭建,不重复造轮子;网关对外统一暴露 `auto-vision` / `auto-text` 两个聚合模型名。
|
||||||
|
- **部署方案(用户 2026-08-23 确认)**:部署于 NAS 本机(Docker Compose),由甲骨文服务器(129.146.203.203)frp/nginx 反向代理端口对外提供访问(与 FAM 项目 frp 方案一致);NAS 出站直连各海外 API。
|
||||||
- **文档**:`docs/01-软件需求文档-SRS.md`(V1.0)+ `docs/02-软件设计文档-SDD.md`(V1.0)入库;README 汇总架构/服务器访问信息/提交规范。
|
- **文档**:`docs/01-软件需求文档-SRS.md`(V1.0)+ `docs/02-软件设计文档-SDD.md`(V1.0)入库;README 汇总架构/服务器访问信息/提交规范。
|
||||||
- **安全**:Gemini 与 NVIDIA 的旧 API Key 不写入仓库(将申请新值);所有 Key 计划通过服务器 `.env` 管理(已加入 .gitignore)。
|
- **安全**:Gemini 与 NVIDIA 的旧 API Key 不写入仓库(将申请新值);所有 Key 计划通过服务器 `.env` 管理(已加入 .gitignore)。
|
||||||
- **仓库**:本地初始化,推送 Gitea `http://192.168.50.64:3000/ericwyuan/NexusAI`。
|
- **仓库**:本地初始化,推送 Gitea `http://192.168.50.64:3000/ericwyuan/NexusAI`。
|
||||||
@@ -28,17 +39,19 @@
|
|||||||
| 2 | 软件设计文档(SDD V1.0)入库 | 2026-08-23 |
|
| 2 | 软件设计文档(SDD V1.0)入库 | 2026-08-23 |
|
||||||
| 3 | README(架构/服务器信息/提交规范) | 2026-08-23 |
|
| 3 | README(架构/服务器信息/提交规范) | 2026-08-23 |
|
||||||
| 4 | 仓库初始化 + 推送 Gitea | 2026-08-23 |
|
| 4 | 仓库初始化 + 推送 Gitea | 2026-08-23 |
|
||||||
|
| 5 | 生成部署骨架(docker-compose.yml / nginx.conf / .env.example) | 2026-08-23 |
|
||||||
|
|
||||||
### 待完成
|
### 待完成
|
||||||
|
|
||||||
| # | 任务 | 依赖 | 优先级 |
|
| # | 任务 | 依赖 | 优先级 |
|
||||||
|---|------|------|--------|
|
|---|------|------|--------|
|
||||||
| 1 | 申请美国服务器(网关部署目标) | - | 高 |
|
| 1 | 验证 NAS 到各海外 API 官方域名的直连稳定性 | - | 高 |
|
||||||
| 2 | 申请新 Gemini / NVIDIA API Key | - | 高 |
|
| 2 | 申请新 Gemini / NVIDIA API Key | - | 高 |
|
||||||
| 3 | 生成部署骨架(docker-compose.yml / nginx.conf / .env.example) | 文档 | 高 |
|
| 3 | 确认 Oracle 反代方式(frp 隧道 vs nginx 反代) | 决策 | 高 |
|
||||||
| 4 | 实际部署 + One-API 渠道配置(5 家)+ Failover 验证 | 服务器/Key | 高 |
|
| 5 | NAS 实际部署 + One-API 渠道配置(5 家)+ Failover 验证 | Key | 高 |
|
||||||
| 5 | HTTPS 域名与证书 | 服务器 | 中 |
|
| 6 | 配置 Oracle 反代端口 → NAS 网关入口 | 反代方式 | 高 |
|
||||||
| 6 | 确认 Server-Side 模式 / 管理端口访问方式 / 监控方案 | 决策 | 中 |
|
| 7 | HTTPS 域名与证书 | NAS | 中 |
|
||||||
|
| 8 | 确认 Server-Side 模式 / 管理端口访问方式 / 监控方案 | 决策 | 中 |
|
||||||
|
|
||||||
## 技术决策记录
|
## 技术决策记录
|
||||||
|
|
||||||
@@ -46,4 +59,5 @@
|
|||||||
2. **模型映射** - 前端只感知 `auto-vision`(图文)与 `auto-text`(纯文本)两个聚合模型名,多渠道不同模型映射到统一对外模型名
|
2. **模型映射** - 前端只感知 `auto-vision`(图文)与 `auto-text`(纯文本)两个聚合模型名,多渠道不同模型映射到统一对外模型名
|
||||||
3. **优先级路由** - 渠道优先级数字越小越优先,同优先级内按权重轮询分摊负载
|
3. **优先级路由** - 渠道优先级数字越小越优先,同优先级内按权重轮询分摊负载
|
||||||
4. **冷却恢复** - 渠道连续失败超阈值(5 次/5 分钟)进入冷却禁用,冷却期(10 分钟)后自动恢复参与路由
|
4. **冷却恢复** - 渠道连续失败超阈值(5 次/5 分钟)进入冷却禁用,冷却期(10 分钟)后自动恢复参与路由
|
||||||
5. **最小暴露面** - 仅 Nginx 80/443 对公网暴露,One-API 后台与 MySQL 端口仅容器内网可访问
|
5. **最小暴露面** - 对外仅暴露甲骨文服务器反代端口,NAS 本机不直接暴露公网;One-API 后台与 MySQL 端口仅容器内网可访问
|
||||||
|
6. **部署位置** - NAS 本机 Docker Compose(Synology ContainerManager),甲骨文服务器 frp/nginx 反代公网端口 → NAS 网关入口;NAS 出站直连海外 API
|
||||||
|
|||||||
47
README.md
47
README.md
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
## 1. 项目简介与设计目标
|
## 1. 项目简介与设计目标
|
||||||
|
|
||||||
公司内网直连 NVIDIA NIM、Gemini 等免费大模型 API 不稳定,本系统部署在美国服务器上,聚合 5 家免费多模态 API(Gemini、NVIDIA NIM、Groq、OpenRouter、Mistral),通过 One-API 网关统一路由,实现"一个渠道不可用自动切换下一个"的高可用能力,并提供接近 Gemini 首页体验的 Web 对话界面(LobeChat),支持图片 + 文字混合输入问答。
|
公司内网直连 NVIDIA NIM、Gemini 等免费大模型 API 不稳定,本系统**部署在 NAS 本机**(Docker Compose),聚合 5 家免费多模态 API(Gemini、NVIDIA NIM、Groq、OpenRouter、Mistral),通过 One-API 网关统一路由,实现"一个渠道不可用自动切换下一个"的高可用能力,并提供接近 Gemini 首页体验的 Web 对话界面(LobeChat),支持图片 + 文字混合输入问答;对外由**甲骨文服务器(129.146.203.203)反向代理端口**提供访问(与 FAM 项目 frp 方案一致)。
|
||||||
|
|
||||||
### 1.1 核心价值
|
### 1.1 核心价值
|
||||||
|
|
||||||
@@ -29,16 +29,20 @@
|
|||||||
浏览器 / 移动端浏览器(公司内网)
|
浏览器 / 移动端浏览器(公司内网)
|
||||||
│ HTTPS (443)
|
│ HTTPS (443)
|
||||||
▼
|
▼
|
||||||
Nginx(反向代理,HTTPS 终止,流式透传)──► LobeChat(前端,:3210)──► One-API(网关,:3000 仅内网)──► MySQL
|
甲骨文服务器(129.146.203.203)—— frp/nginx 反代端口(对外统一入口)
|
||||||
|
│ 反代 / 隧道(frp)
|
||||||
|
▼
|
||||||
|
NAS 本机(Docker 宿主机)
|
||||||
|
├─ Nginx(HTTPS 终止,流式透传)──► LobeChat(:3210)──► One-API(:3000 仅内网)──► MySQL
|
||||||
│
|
│
|
||||||
┌──────────────┬──────────────┬──────────────┐
|
▼ NAS 出站直连海外 API
|
||||||
▼ ▼ ▼ ▼
|
Gemini · NVIDIA NIM · Groq · OpenRouter · Mistral
|
||||||
Gemini NVIDIA NIM Groq OpenRouter Mistral
|
|
||||||
```
|
```
|
||||||
|
|
||||||
| 层级 | 组件 | 职责 |
|
| 层级 | 组件 | 职责 |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| 接入层 | Nginx | HTTPS 终止、反向代理、访问入口统一 |
|
| 反代层 | 甲骨文服务器 | frp/nginx 反向代理端口,对外统一访问入口 |
|
||||||
|
| 接入层 | Nginx | HTTPS 终止、反向代理(NAS 本机) |
|
||||||
| 表现层 | LobeChat | 对话界面渲染、图片上传、Access Code 鉴权、对话历史(IndexedDB) |
|
| 表现层 | LobeChat | 对话界面渲染、图片上传、Access Code 鉴权、对话历史(IndexedDB) |
|
||||||
| 网关层 | One-API | 协议转换、渠道路由、Failover、用量统计 |
|
| 网关层 | One-API | 协议转换、渠道路由、Failover、用量统计 |
|
||||||
| 数据层 | MySQL | 渠道配置 / Token / 调用日志持久化 |
|
| 数据层 | MySQL | 渠道配置 / Token / 调用日志持久化 |
|
||||||
@@ -71,7 +75,9 @@ Nginx(反向代理,HTTPS 终止,流式透传)──► LobeChat(前端
|
|||||||
|
|
||||||
## 3. 部署概览
|
## 3. 部署概览
|
||||||
|
|
||||||
- **方式**:单机 Docker Compose,所有服务在同一 `ai-network` 内,仅 Nginx 80/443 对公网暴露
|
- **部署位置**:NAS 本机(Synology DSM 7,Docker Compose / ContainerManager)
|
||||||
|
- **对外访问**:甲骨文服务器(129.146.203.203)frp/nginx 反向代理端口 → NAS 的 Nginx 443
|
||||||
|
- **方式**:所有服务在同一 `ai-network` 内,仅 Nginx 80/443 对局域网暴露
|
||||||
- **目录结构**:`docker-compose.yml` / `.env`(敏感变量,不入库)/ `nginx.conf` / `certs/` / `one-api-data/` / `mysql-data/`
|
- **目录结构**:`docker-compose.yml` / `.env`(敏感变量,不入库)/ `nginx.conf` / `certs/` / `one-api-data/` / `mysql-data/`
|
||||||
- **详细部署步骤**:见 [SDD 第 6 章](docs/02-软件设计文档-SDD.md#6-部署设计)
|
- **详细部署步骤**:见 [SDD 第 6 章](docs/02-软件设计文档-SDD.md#6-部署设计)
|
||||||
|
|
||||||
@@ -79,13 +85,14 @@ Nginx(反向代理,HTTPS 终止,流式透传)──► LobeChat(前端
|
|||||||
|
|
||||||
| 服务 | 镜像 | 端口 | 说明 |
|
| 服务 | 镜像 | 端口 | 说明 |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| nginx | nginx:alpine | 80/443(公网) | HTTPS 终止、反向代理 |
|
| nginx | nginx:alpine | 80/443(NAS 局域网) | HTTPS 终止、反向代理 |
|
||||||
| lobe-chat | lobehub/lobe-chat:latest | 3210(内网) | 前端对话界面 |
|
| lobe-chat | lobehub/lobe-chat:latest | 3210(内网) | 前端对话界面 |
|
||||||
| one-api | justsong/one-api:latest | 3000(内网) | 网关聚合层 |
|
| one-api | justsong/one-api:latest | 3000(内网) | 网关聚合层 |
|
||||||
| mysql | mysql:8.0 | 3306(内网) | One-API 数据存储 |
|
| mysql | mysql:8.0 | 3306(内网) | One-API 数据存储 |
|
||||||
|
|
||||||
### 3.2 安全要点
|
### 3.2 安全要点
|
||||||
|
|
||||||
|
- 对外仅暴露甲骨文服务器反代端口,NAS 本机不直接暴露公网
|
||||||
- One-API 后台端口(3000)不映射公网,远程管理走 SSH 隧道 / VPN
|
- One-API 后台端口(3000)不映射公网,远程管理走 SSH 隧道 / VPN
|
||||||
- 所有 API Key 通过服务器 `.env` 注入容器环境变量,`.env` 不入库(见 [SDD 第 5 章](docs/02-软件设计文档-SDD.md#5-安全设计))
|
- 所有 API Key 通过服务器 `.env` 注入容器环境变量,`.env` 不入库(见 [SDD 第 5 章](docs/02-软件设计文档-SDD.md#5-安全设计))
|
||||||
- 前端强制 `ACCESS_CODE` 校验;Nginx 全站 HTTPS
|
- 前端强制 `ACCESS_CODE` 校验;Nginx 全站 HTTPS
|
||||||
@@ -94,7 +101,7 @@ Nginx(反向代理,HTTPS 终止,流式透传)──► LobeChat(前端
|
|||||||
|
|
||||||
## 4. 服务器访问信息
|
## 4. 服务器访问信息
|
||||||
|
|
||||||
### 4.1 Synology NAS(FAM-Core + FAM-UI + MariaDB + Gitea)
|
### 4.1 Synology NAS(AI 网关部署目标 + FAM + Gitea)
|
||||||
|
|
||||||
| 项目 | 值 |
|
| 项目 | 值 |
|
||||||
|---|---|
|
|---|---|
|
||||||
@@ -114,7 +121,7 @@ Nginx(反向代理,HTTPS 终止,流式透传)──► LobeChat(前端
|
|||||||
| Root 密码 | iLoveJava5! |
|
| Root 密码 | iLoveJava5! |
|
||||||
| 连接 | `/usr/local/mariadb10/bin/mysql -S /run/mysqld/mysqld10.sock -u root -p` |
|
| 连接 | `/usr/local/mariadb10/bin/mysql -S /run/mysqld/mysqld10.sock -u root -p` |
|
||||||
|
|
||||||
### 4.3 Oracle Cloud(FAM-Edge + Ollama + FFmpeg)
|
### 4.3 Oracle Cloud(反代层,129.146.203.203)
|
||||||
|
|
||||||
| 项目 | 值 |
|
| 项目 | 值 |
|
||||||
|---|---|
|
|---|---|
|
||||||
@@ -123,6 +130,7 @@ Nginx(反向代理,HTTPS 终止,流式透传)──► LobeChat(前端
|
|||||||
| 系统 | aarch64 (Ampere A1 2C12G), Ubuntu 20.04 LTS |
|
| 系统 | aarch64 (Ampere A1 2C12G), Ubuntu 20.04 LTS |
|
||||||
| Tailscale | 100.74.137.126(已安装在线,与 NAS 端口不通) |
|
| Tailscale | 100.74.137.126(已安装在线,与 NAS 端口不通) |
|
||||||
| 登录命令 | `ssh -i ~/.ssh/oracle_sentinel ubuntu@129.146.203.203` |
|
| 登录命令 | `ssh -i ~/.ssh/oracle_sentinel ubuntu@129.146.203.203` |
|
||||||
|
| 反代职责 | frp/nginx 反代公网端口 → NAS AI 网关入口 |
|
||||||
|
|
||||||
### 4.4 Gitea 代码仓库
|
### 4.4 Gitea 代码仓库
|
||||||
|
|
||||||
@@ -131,15 +139,13 @@ Nginx(反向代理,HTTPS 终止,流式透传)──► LobeChat(前端
|
|||||||
| URL | http://192.168.50.64:3000/ericwyuan/NexusAI |
|
| URL | http://192.168.50.64:3000/ericwyuan/NexusAI |
|
||||||
| 账号 / 密码 | ericwyuan / iLoveJava5 |
|
| 账号 / 密码 | ericwyuan / iLoveJava5 |
|
||||||
|
|
||||||
> 美国服务器(AI 网关部署目标)访问信息待补充。
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 5. AI 渠道 API Key(服务器 `.env` 管理,不入库)
|
## 5. AI 渠道 API Key(服务器 `.env` 管理,不入库)
|
||||||
|
|
||||||
> ⚠️ Gemini 与 NVIDIA 的 Key 将申请新值,此处不写入旧 Key,配置于美国服务器 `.env` 的占位变量。
|
> ⚠️ Gemini 与 NVIDIA 的 Key 将申请新值,此处不写入旧 Key,配置于 NAS `.env` 的占位变量。
|
||||||
|
|
||||||
| 渠道 | 模型 / 端点 | Key 环境变量(服务器 .env) |
|
| 渠道 | 模型 / 端点 | Key 环境变量(NAS .env) |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| Gemini | `generativelanguage.googleapis.com/v1beta`,模型 `gemini-flash-latest` | `${GEMINI_API_KEY}`(新 Key 待申请) |
|
| Gemini | `generativelanguage.googleapis.com/v1beta`,模型 `gemini-flash-latest` | `${GEMINI_API_KEY}`(新 Key 待申请) |
|
||||||
| NVIDIA NIM | `integrate.api.nvidia.com/v1`,默认 `meta/llama-3.2-11b-vision-instruct` | `${NVIDIA_API_KEY}`(新 Key 待申请) |
|
| NVIDIA NIM | `integrate.api.nvidia.com/v1`,默认 `meta/llama-3.2-11b-vision-instruct` | `${NVIDIA_API_KEY}`(新 Key 待申请) |
|
||||||
@@ -147,7 +153,7 @@ Nginx(反向代理,HTTPS 终止,流式透传)──► LobeChat(前端
|
|||||||
| OpenRouter | `openrouter.ai/api/v1` | `${OPENROUTER_API_KEY}` |
|
| OpenRouter | `openrouter.ai/api/v1` | `${OPENROUTER_API_KEY}` |
|
||||||
| Mistral | `api.mistral.ai/v1` | `${MISTRAL_API_KEY}` |
|
| Mistral | `api.mistral.ai/v1` | `${MISTRAL_API_KEY}` |
|
||||||
|
|
||||||
> 各渠道 Key 申请后填入美国服务器 `.env`,One-API 后台添加渠道时引用,切勿提交版本库。
|
> 各渠道 Key 申请后填入 NAS `.env`,One-API 后台添加渠道时引用,切勿提交版本库。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -183,12 +189,13 @@ Nginx(反向代理,HTTPS 终止,流式透传)──► LobeChat(前端
|
|||||||
|
|
||||||
| # | 任务 | 优先级 |
|
| # | 任务 | 优先级 |
|
||||||
|---|------|--------|
|
|---|------|--------|
|
||||||
| 1 | 申请美国服务器,确认访问信息 | 高 |
|
| 1 | 验证 NAS 到各海外 API 官方域名的直连稳定性 | 高 |
|
||||||
| 2 | 申请新 Gemini / NVIDIA API Key | 高 |
|
| 2 | 申请新 Gemini / NVIDIA API Key | 高 |
|
||||||
| 3 | 确认 HTTPS 域名与证书方案 | 中 |
|
| 3 | 确认 Oracle 反代方式(frp 隧道 vs nginx 反代) | 高 |
|
||||||
| 4 | 生成部署骨架(docker-compose.yml / nginx.conf / .env.example) | 高 |
|
| 4 | ~~生成部署骨架(docker-compose.yml / nginx.conf / .env.example)~~ 已完成 | 高 |
|
||||||
| 5 | 实际部署 + One-API 渠道配置 + Failover 验证 | 高 |
|
| 5 | NAS 实际部署 + One-API 渠道配置 + Failover 验证 | 高 |
|
||||||
| 6 | 确认 Server-Side 模式 / 管理端口访问方式 / 监控方案 | 中 |
|
| 6 | 确认 HTTPS 域名与证书方案 | 中 |
|
||||||
|
| 7 | 确认 Server-Side 模式 / 管理端口访问方式 / 监控方案 | 中 |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
66
docker-compose.yml
Normal file
66
docker-compose.yml
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
mysql:
|
||||||
|
image: mysql:8.0
|
||||||
|
container_name: one-api-mysql
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
|
||||||
|
- MYSQL_DATABASE=oneapi
|
||||||
|
volumes:
|
||||||
|
- ./mysql-data:/var/lib/mysql
|
||||||
|
networks:
|
||||||
|
- ai-network
|
||||||
|
|
||||||
|
one-api:
|
||||||
|
image: justsong/one-api:latest
|
||||||
|
container_name: one-api
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
# 仅绑定 127.0.0.1,不对局域网/公网暴露;远程管理走 SSH 隧道:
|
||||||
|
# ssh -p 2222 -L 3000:127.0.0.1:3000 ericwyuan@192.168.50.64
|
||||||
|
- "127.0.0.1:3000:3000"
|
||||||
|
volumes:
|
||||||
|
- ./one-api-data:/data
|
||||||
|
environment:
|
||||||
|
- SQL_DSN=root:${MYSQL_ROOT_PASSWORD}@tcp(mysql:3306)/oneapi
|
||||||
|
- TZ=Asia/Shanghai
|
||||||
|
depends_on:
|
||||||
|
- mysql
|
||||||
|
networks:
|
||||||
|
- ai-network
|
||||||
|
|
||||||
|
lobe-chat:
|
||||||
|
image: lobehub/lobe-chat:latest
|
||||||
|
container_name: lobe-chat
|
||||||
|
restart: always
|
||||||
|
# 不发布主机端口:仅 Nginx 通过容器网络访问 lobe-chat:3210
|
||||||
|
environment:
|
||||||
|
- OPENAI_API_KEY=${ONE_API_TOKEN}
|
||||||
|
- OPENAI_PROXY_URL=http://one-api:3000/v1
|
||||||
|
- ACCESS_CODE=${LOBE_ACCESS_CODE}
|
||||||
|
- DEFAULT_LANG=zh-CN
|
||||||
|
depends_on:
|
||||||
|
- one-api
|
||||||
|
networks:
|
||||||
|
- ai-network
|
||||||
|
|
||||||
|
nginx:
|
||||||
|
image: nginx:alpine
|
||||||
|
container_name: nginx-proxy
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
- "443:443"
|
||||||
|
volumes:
|
||||||
|
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
||||||
|
- ./certs:/etc/nginx/certs:ro
|
||||||
|
depends_on:
|
||||||
|
- lobe-chat
|
||||||
|
networks:
|
||||||
|
- ai-network
|
||||||
|
|
||||||
|
networks:
|
||||||
|
ai-network:
|
||||||
|
driver: bridge
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
### 1.2 项目背景
|
### 1.2 项目背景
|
||||||
|
|
||||||
由于公司内网访问 NVIDIA NIM、Gemini 等免费大模型 API 不稳定,希望在自有美国服务器上搭建一套类似 Gemini 首页体验的对话系统,聚合多个免费 AI API 渠道,实现"一个渠道不可用自动切换下一个"的高可用能力,同时支持图文多模态问答。
|
由于公司内网访问 NVIDIA NIM、Gemini 等免费大模型 API 不稳定,希望在自有 NAS 上搭建一套类似 Gemini 首页体验的对话系统(由甲骨文服务器反向代理端口对外提供访问),聚合多个免费 AI API 渠道,实现"一个渠道不可用自动切换下一个"的高可用能力,同时支持图文多模态问答。
|
||||||
|
|
||||||
### 1.3 项目目标
|
### 1.3 项目目标
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
- 聚合至少 5 家免费多模态 API(Gemini、NVIDIA NIM、Groq、OpenRouter、Mistral)
|
- 聚合至少 5 家免费多模态 API(Gemini、NVIDIA NIM、Groq、OpenRouter、Mistral)
|
||||||
- 单一渠道失败时自动故障转移(Failover),用户无感知
|
- 单一渠道失败时自动故障转移(Failover),用户无感知
|
||||||
- 支持图片 + 文字混合输入的问答
|
- 支持图片 + 文字混合输入的问答
|
||||||
- 部署在美国服务器,规避公司内网对海外 API 的直连限制
|
- 部署于 NAS 本机(Docker Compose),由甲骨文服务器反向代理端口对外访问,规避公司内网对海外 API 的直连限制
|
||||||
- 全部使用免费额度,不产生 API 调用费用
|
- 全部使用免费额度,不产生 API 调用费用
|
||||||
|
|
||||||
### 1.4 术语定义
|
### 1.4 术语定义
|
||||||
@@ -56,17 +56,17 @@
|
|||||||
|
|
||||||
### 2.3 运行环境
|
### 2.3 运行环境
|
||||||
|
|
||||||
- 部署位置:美国服务器(无地区网络限制)
|
- 部署位置:NAS 本机(Docker Compose),由甲骨文服务器(129.146.203.203)反向代理端口对外提供访问
|
||||||
- 访问方来源:公司内网(网络不稳定,仅需保证到本服务器一段链路可用)
|
- 访问方来源:公司内网(网络不稳定,仅需保证到甲骨文服务器一段链路可用)
|
||||||
- 容器化部署:Docker + Docker Compose
|
- 容器化部署:Docker + Docker Compose(NAS 使用 ContainerManager)
|
||||||
- 操作系统:Linux(Ubuntu/Debian 系)
|
- 操作系统:Synology DSM 7(Linux 内核)
|
||||||
|
|
||||||
### 2.4 约束与假设
|
### 2.4 约束与假设
|
||||||
|
|
||||||
- 假设:美国服务器可稳定访问 Google、NVIDIA、Groq、OpenRouter、Mistral 官方域名
|
- 假设:NAS 本机可稳定访问 Google、NVIDIA、Groq、OpenRouter、Mistral 官方域名
|
||||||
- 约束:仅使用各平台免费额度,不产生付费调用
|
- 约束:仅使用各平台免费额度,不产生付费调用
|
||||||
- 约束:不做未成年人相关内容、不涉及企业内部代码泄露到公网模型(需用户自行注意脱敏)
|
- 约束:不做未成年人相关内容、不涉及企业内部代码泄露到公网模型(需用户自行注意脱敏)
|
||||||
- 假设:公司内网到美国服务器的连接比公司内网直连各 API 官方域名更稳定
|
- 假设:公司内网到甲骨文服务器、甲骨文到 NAS 的链路比公司内网直连各 API 官方域名更稳定
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,13 @@
|
|||||||
│ HTTPS (443)
|
│ HTTPS (443)
|
||||||
▼
|
▼
|
||||||
┌───────────────────────────────────────────────────────────────┐
|
┌───────────────────────────────────────────────────────────────┐
|
||||||
│ 美国服务器(Docker 宿主机) │
|
│ 甲骨文服务器(129.146.203.203,公网反代层) │
|
||||||
|
│ frp / nginx 反向代理端口 → NAS(对外统一入口) │
|
||||||
|
└──────────────────────────┬────────────────────────────────────┘
|
||||||
|
│ 反代 / 隧道(frp)
|
||||||
|
▼
|
||||||
|
┌───────────────────────────────────────────────────────────────┐
|
||||||
|
│ NAS 本机(Docker 宿主机) │
|
||||||
│ │
|
│ │
|
||||||
│ ┌─────────────────────────────────────────────────────────┐ │
|
│ ┌─────────────────────────────────────────────────────────┐ │
|
||||||
│ │ Nginx(反向代理层) │ │
|
│ │ Nginx(反向代理层) │ │
|
||||||
@@ -77,7 +83,8 @@
|
|||||||
|
|
||||||
| 层级 | 组件 | 职责 |
|
| 层级 | 组件 | 职责 |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| 接入层 | Nginx | HTTPS 终止、反向代理、访问入口统一 |
|
| 反代层 | 甲骨文服务器 | frp/nginx 反向代理端口,对外统一访问入口 |
|
||||||
|
| 接入层 | Nginx | HTTPS 终止、反向代理、访问入口统一(NAS 本机) |
|
||||||
| 表现层 | LobeChat | 用户交互、对话渲染、多模态输入采集 |
|
| 表现层 | LobeChat | 用户交互、对话渲染、多模态输入采集 |
|
||||||
| 网关层 | One-API | 协议转换、渠道路由、故障转移、用量统计 |
|
| 网关层 | One-API | 协议转换、渠道路由、故障转移、用量统计 |
|
||||||
| 数据层 | MySQL | 网关配置与日志持久化 |
|
| 数据层 | MySQL | 网关配置与日志持久化 |
|
||||||
@@ -85,7 +92,7 @@
|
|||||||
|
|
||||||
### 2.3 部署视图
|
### 2.3 部署视图
|
||||||
|
|
||||||
单机 Docker Compose 部署,各服务以容器形式运行在同一 Docker 网络(`ai-network`)内,服务间通过容器名互相寻址,仅 Nginx 的 80/443 端口对公网暴露。
|
单机 Docker Compose 部署于 **NAS 本机**,各服务以容器形式运行在同一 Docker 网络(`ai-network`)内,服务间通过容器名互相寻址,仅 Nginx 的 80/443 端口对局域网暴露;对外由**甲骨文服务器(129.146.203.203)**通过 frp/nginx 反向代理该端口,供公司内网公网访问。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -94,7 +101,7 @@
|
|||||||
### 3.1 Nginx 反向代理模块
|
### 3.1 Nginx 反向代理模块
|
||||||
|
|
||||||
**职责**
|
**职责**
|
||||||
- 对外仅暴露 443(HTTPS)与 80(HTTP 跳转 443)
|
- 在 NAS 本机暴露 443(HTTPS)与 80(HTTP 跳转 443);公网访问由甲骨文服务器反向代理到本机 443 端口
|
||||||
- 将请求转发至 `lobe-chat:3210`
|
- 将请求转发至 `lobe-chat:3210`
|
||||||
- 关闭代理缓冲以支持流式输出(SSE)
|
- 关闭代理缓冲以支持流式输出(SSE)
|
||||||
|
|
||||||
@@ -233,10 +240,11 @@ server {
|
|||||||
|
|
||||||
| 风险点 | 设计对策 |
|
| 风险点 | 设计对策 |
|
||||||
|---|---|
|
|---|---|
|
||||||
| 后台管理端口暴露 | One-API 的 3000 端口不映射到公网,仅容器内网可访问;如需远程管理,走 SSH 隧道或 VPN |
|
| 后台管理端口暴露 | One-API 的 3000 端口不映射到公网,仅容器内网可访问;Oracle 反代仅转发前端端口,管理端口走 SSH 隧道或 VPN |
|
||||||
| API Key 泄露 | 所有 Key 通过 `.env` 文件注入容器环境变量,`.env` 加入 `.gitignore`,不提交版本库 |
|
| API Key 泄露 | 所有 Key 通过 `.env` 文件注入容器环境变量,`.env` 加入 `.gitignore`,不提交版本库 |
|
||||||
| 未授权访问前端 | LobeChat `ACCESS_CODE` 强制校验 |
|
| 未授权访问前端 | LobeChat `ACCESS_CODE` 强制校验 |
|
||||||
| 传输层安全 | Nginx 强制 HTTPS,HTTP 请求 301 跳转 |
|
| 传输层安全 | Nginx 强制 HTTPS,HTTP 请求 301 跳转 |
|
||||||
|
| 公网入口暴露 | 对外仅暴露甲骨文服务器反代端口,NAS 本机不直接暴露公网 |
|
||||||
| 密钥被盗用后的止损 | One-API 后台可随时吊销/轮换 Token,不影响各渠道原始 Key |
|
| 密钥被盗用后的止损 | One-API 后台可随时吊销/轮换 Token,不影响各渠道原始 Key |
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -327,15 +335,16 @@ networks:
|
|||||||
|
|
||||||
### 6.3 部署步骤
|
### 6.3 部署步骤
|
||||||
|
|
||||||
1. 服务器安装 Docker + Docker Compose
|
1. NAS 安装 Docker + Docker Compose(ContainerManager)
|
||||||
2. 按 6.1 结构创建目录,放置 `docker-compose.yml`、`.env`、`nginx.conf`
|
2. 按 6.1 结构创建目录,放置 `docker-compose.yml`、`.env`、`nginx.conf`
|
||||||
3. 申请 HTTPS 证书(Let's Encrypt/certbot)放入 `certs/`
|
3. 申请 HTTPS 证书(Let's Encrypt/certbot)放入 `certs/`
|
||||||
4. 执行 `docker-compose up -d` 启动全部服务
|
4. 执行 `docker-compose up -d` 启动全部服务
|
||||||
5. 访问 `http://<服务器IP>:3000` 完成 One-API 初始化(设置管理员密码)
|
5. 访问 `http://<NAS-IP>:3000` 完成 One-API 初始化(设置管理员密码)
|
||||||
6. 后台按 3.3 节渠道设计表逐个添加渠道,设置优先级
|
6. 后台按 3.3 节渠道设计表逐个添加渠道,设置优先级
|
||||||
7. 创建对外 Token,写入 `.env` 的 `ONE_API_TOKEN`
|
7. 创建对外 Token,写入 `.env` 的 `ONE_API_TOKEN`
|
||||||
8. `docker-compose restart lobe-chat` 使配置生效
|
8. `docker-compose restart lobe-chat` 使配置生效
|
||||||
9. 访问 `https://<域名>` 验证前端可正常对话、上传图片、触发 Failover
|
9. 在甲骨文服务器配置 frp(或 nginx 反代)将公网端口转发至 NAS 的 Nginx 443 端口
|
||||||
|
10. 访问 `https://<域名>`(经甲骨文反代)验证前端可正常对话、上传图片、触发 Failover
|
||||||
|
|
||||||
### 6.4 运维监控设计
|
### 6.4 运维监控设计
|
||||||
|
|
||||||
@@ -368,3 +377,5 @@ networks:
|
|||||||
2. 后台管理端口是否需要通过 VPN/SSH 隧道访问,还是接受当前仅内网暴露的方案
|
2. 后台管理端口是否需要通过 VPN/SSH 隧道访问,还是接受当前仅内网暴露的方案
|
||||||
3. 是否需要接入 Prometheus/Grafana 做可视化监控(当前为后续扩展项,非本期必做)
|
3. 是否需要接入 Prometheus/Grafana 做可视化监控(当前为后续扩展项,非本期必做)
|
||||||
4. 域名与证书由紫川自行准备,还是需要方案建议
|
4. 域名与证书由紫川自行准备,还是需要方案建议
|
||||||
|
5. **NAS 到各海外 API 官方域名的直连稳定性验证**(部署目标已改为 NAS 本机 + 甲骨文反代,需确认 NAS 出站访问 Google/NVIDIA/Groq/OpenRouter/Mistral 的稳定性)
|
||||||
|
6. **甲骨文反代方式确认**:frp 隧道(参照 FAM 项目方案)还是 nginx 反代
|
||||||
|
|||||||
52
nginx.conf
Normal file
52
nginx.conf
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
user nginx;
|
||||||
|
worker_processes auto;
|
||||||
|
|
||||||
|
error_log /var/log/nginx/error.log notice;
|
||||||
|
pid /var/run/nginx.pid;
|
||||||
|
|
||||||
|
events {
|
||||||
|
worker_connections 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
http {
|
||||||
|
include /etc/nginx/mime.types;
|
||||||
|
default_type application/octet-stream;
|
||||||
|
|
||||||
|
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||||
|
'$status $body_bytes_sent "$http_referer" '
|
||||||
|
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||||
|
|
||||||
|
access_log /var/log/nginx/access.log main;
|
||||||
|
|
||||||
|
sendfile on;
|
||||||
|
keepalive_timeout 65;
|
||||||
|
|
||||||
|
# 域名/IP 未确定前,先用 _ 通配 server_name(见 SDD 8.4 待确认事项)
|
||||||
|
server {
|
||||||
|
listen 443 ssl;
|
||||||
|
server_name _;
|
||||||
|
|
||||||
|
ssl_certificate /etc/nginx/certs/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/nginx/certs/privkey.pem;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://lobe-chat:3210;
|
||||||
|
proxy_http_version 1.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;
|
||||||
|
|
||||||
|
# 关闭缓冲/缓存以支持流式输出(SSE)
|
||||||
|
proxy_buffering off;
|
||||||
|
proxy_cache off;
|
||||||
|
proxy_read_timeout 300s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name _;
|
||||||
|
return 301 https://$host$request_uri;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user