# 群晖 NAS + Cloudflare Tunnel + 未认证企微 部署指南

> **适用范围**：阶段一功能测试
> **目标域名**：`itdesk.amanzac.com`
> **最后更新**：2026-06-07

---

## 架构总览

```
                    HTTPS                          HTTP
员工手机 ──────────→ Cloudflare Edge ──────────→ cloudflared ──→ nginx:80
(企微H5)            (自动SSL+CDN)        Tunnel       容器          │
                                                              ┌────┴────┐
                                                              │  路由分发  │
                                                              └────┬────┘
                                                        ┌──────┼──────┐
                                                        │      │      │
                                                   /itdesk/ /itagent/ /api/
                                                   H5员工端  坐席工作台 后端
```

**关键特点**：
- ✅ 无需公网 IP
- ✅ 无需 SSL 证书（Cloudflare 自动处理）
- ✅ 无需开放 NAS 端口
- ✅ 未认证企微可正常使用 OAuth2 + 消息 API

---

## §1 前置条件检查清单

| # | 条件 | 你的状态 | 说明 |
|---|------|---------|------|
| 1 | 群晖 NAS（DS220+ 及以上） | ✅ 已确认 | 需支持 Docker（ARM 机型需确认镜像兼容） |
| 2 | Container Manager 已安装 | ✅ 已确认 | 套件中心安装 |
| 3 | Cloudflare 账号 | ✅ 已确认 | 免费版即可 |
| 4 | 域名 `amanzac.com` 已托管 Cloudflare | ✅ 已确认 | DNS 管理 → Cloudflare |
| 5 | 企微管理后台权限 | ✅ 已确认 | 需配置自建应用 |
| 6 | SSH 访问 NAS | ⬜ 待确认 | 需开启 SSH 以执行 docker compose 命令 |

---

## §2 Cloudflare Tunnel 配置

### 2.1 创建 Tunnel

1. 登录 [Cloudflare Zero Trust](https://one.dash.cloudflare.com/)
2. 左侧菜单 → **Networks** → **Tunnels**
3. 点击 **Create a tunnel**
4. 选择 **Cloudflared** 类型
5. 输入 Tunnel 名称，如 `itdesk-nas`
6. 点击 **Save tunnel**

### 2.2 获取 Tunnel Token

创建完成后，页面会显示安装命令，其中包含 Token：

```bash
# 示例安装命令
cloudflared service install eyJhIjoiNjM1...
#                            ^^^^^^^^^^^^
#                            这就是 Token
```

**复制这个 Token**，后面要填到 `.env` 文件中。

### 2.3 配置 Tunnel 路由（Public Hostname）

在 Tunnel 创建页面，配置 **Public Hostname**：

| 字段 | 填写 | 说明 |
|------|------|------|
| Subdomain | `itdesk` | 前缀 |
| Domain | `amanzac.com` | 你的域名 |
| Type | `HTTP` | 容器内是 HTTP |
| URL | `nginx` | Docker 容器名（同一网络内） |

> ⚠️ 注意：Type 选 **HTTP**（不是 HTTPS），因为 cloudflared 和 nginx 之间走的是容器内网 HTTP。SSL 由 Cloudflare Edge 终止。

点击 **Save tunnel**。

### 2.4 验证 DNS 记录

Cloudflare 会自动创建一条 CNAME 记录：
- `itdesk.amanzac.com` → `cfargotunnel.com`

可在 Cloudflare Dashboard → DNS → Records 中确认。

---

## §3 项目文件部署到 NAS

### 3.1 上传项目文件

**方式一：Git Clone（推荐）**

如果 NAS 上有 Git：
```bash
# SSH 登录 NAS
ssh admin@NAS_IP

# 创建项目目录
mkdir -p /volume1/docker/wecom-it-desk
cd /volume1/docker/wecom-it-desk

# 克隆项目
git clone <你的仓库地址> .
```

**方式二：SCP 上传**

从开发机上传构建好的文件：
```powershell
# 在 Windows PowerShell 中执行
# 上传核心文件（不含 node_modules 和 .git）
scp -r "D:\资料\03-项目开发\wecom_it_smart_desk\docker-compose.nas.yml" admin@NAS_IP:/volume1/docker/wecom-it-desk/
scp -r "D:\资料\03-项目开发\wecom_it_smart_desk\.env.nas" admin@NAS_IP:/volume1/docker/wecom-it-desk/
scp -r "D:\资料\03-项目开发\wecom_it_smart_desk\nginx" admin@NAS_IP:/volume1/docker/wecom-it-desk/
scp -r "D:\资料\03-项目开发\wecom_it_smart_desk\backend" admin@NAS_IP:/volume1/docker/wecom-it-desk/
scp -r "D:\资料\03-项目开发\wecom_it_smart_desk\frontend-h5\dist" admin@NAS_IP:/volume1/docker/wecom-it-desk/frontend-h5/dist/
scp -r "D:\资料\03-项目开发\wecom_it_smart_desk\frontend-agent\dist" admin@NAS_IP:/volume1/docker/wecom-it-desk/frontend-agent/dist/
```

**方式三：群晖 File Station**

把构建产物打包成 zip，通过 File Station 上传到 `/docker/wecom-it-desk/` 然后解压。

### 3.2 配置环境变量

```bash
cd /volume1/docker/wecom-it-desk

# 复制模板
cp .env.nas .env

# 编辑 .env 文件
vi .env
```

**必须修改的项**：

```bash
# 1. 填入 Cloudflare Tunnel Token（从 §2.2 获取）
CF_TUNNEL_TOKEN=eyJhIjoiNjM1...    # ← 替换为你的实际 Token

# 2. 修改数据库密码
POSTGRES_PASSWORD=YourStrongPassword123!    # ← 替换为强密码

# 3. 如果 NAS 能访问公司内网 Dify，填入 Dify 配置
#    如果不能访问，留空即可（AI 功能暂不可用，不影响阶段一）
DIFY_API_URL=
DIFY_API_KEY=
```

### 3.3 构建前端（如果还没构建）

前端需要先在开发机（Windows）上构建，再上传 dist/ 目录：

```powershell
# 在 Windows 开发机上
cd "D:\资料\03-项目开发\wecom_it_smart_desk"

# 构建坐席端
cd frontend-agent
npm install
npx vite build

# 构建 H5 员工端
cd ..\frontend-h5
npm install
npx vite build
```

构建产物在 `frontend-agent/dist/` 和 `frontend-h5/dist/` 中。

---

## §4 启动服务

### 4.1 SSH 登录 NAS 启动

```bash
# SSH 登录 NAS
ssh admin@NAS_IP

# 进入项目目录
cd /volume1/docker/wecom-it-desk

# 启动所有容器（5 个容器）
docker compose -f docker-compose.nas.yml up -d

# 等待约 30 秒，检查状态
docker compose -f docker-compose.nas.yml ps
```

**预期输出**：

| 容器名 | 状态 | 说明 |
|--------|------|------|
| wecom_it_cloudflared | Running | Cloudflare Tunnel |
| wecom_it_nginx | Up (healthy) | 反向代理 |
| wecom_it_backend | Up | FastAPI 后端 |
| wecom_it_postgres | Up (healthy) | PostgreSQL |
| wecom_it_redis | Up (healthy) | Redis |

### 4.2 验证服务

```bash
# 1. 内网验证（在 NAS 上执行）
curl http://localhost:18080/api/health
# 预期输出: {"status":"ok","service":"wecom-it-smart-desk"}

# 2. 内网验证前端
curl http://localhost:18080/itdesk/health
# 预期输出: healthy

# 3. 公网验证（从任意有网络的设备）
curl https://itdesk.amanzac.com/api/health
# 预期输出: {"status":"ok","service":"wecom-it-smart-desk"}

# 4. 浏览器访问
# H5 员工端: https://itdesk.amanzac.com/itdesk/
# 坐席工作台: https://itdesk.amanzac.com/itagent/
```

### 4.3 常用运维命令

```bash
# 查看日志
docker compose -f docker-compose.nas.yml logs -f backend    # 后端日志
docker compose -f docker-compose.nas.yml logs -f cloudflared # Tunnel 日志
docker compose -f docker-compose.nas.yml logs -f nginx       # Nginx 日志

# 重启某个服务
docker compose -f docker-compose.nas.yml restart backend

# 停止所有服务
docker compose -f docker-compose.nas.yml down

# 更新并重启（代码更新后）
docker compose -f docker-compose.nas.yml up -d --build
```

---

## §5 企微自建应用配置

### 5.1 创建自建应用

1. 登录 [企微管理后台](https://work.weixin.qq.com/wework_admin/frame)
2. **应用管理** → **自建** → **创建应用**
3. 填写：
   - 应用名称：`智能IT支持服务台`
   - 应用logo：上传一个图标
   - 可见范围：选择测试部门/人员

### 5.2 配置网页授权（OAuth2）

在应用详情页 → **网页授权及JS-SDK**：

| 配置项 | 填写 | 说明 |
|--------|------|------|
| 可信域名 | `itdesk.amanzac.com` | OAuth2 回调域名 |

> **验证方式**：Cloudflare Tunnel 已提供 HTTPS，下载企微提供的验证文件，放到 `frontend-h5/dist/` 根目录后重新构建。

### 5.3 配置应用主页

在应用详情页 → **应用主页**：

```
https://itdesk.amanzac.com/itdesk/
```

员工点击企微中的应用入口，直接打开 H5 页面。

### 5.4 配置接收消息（回调 URL）

在应用详情页 → **接收消息** → **设置API接收**：

| 配置项 | 填写 | 说明 |
|--------|------|------|
| URL | `https://itdesk.amanzac.com/api/wecom/callback` | 企微消息推送地址 |
| Token | `wAqMCP` | 与 .env 中 WECOM_TOKEN 一致 |
| EncodingAESKey | `KQY3cEsBc3rdi3xua9rPd5WxH8kYOhyASzWZQf75aJS` | 与 .env 中一致 |

> 点击保存时，企微会向 URL 发送验证请求，后端必须正常响应才能保存成功。

### 5.5 修改 AI 机器人转人工链接

在现有 AI 机器人的 Dify 工作流中，将转人工关键字触发的链接从：

```
旧链接：https://work.weixin.qq.com/XXXX（员工服务入口）
```

改为：

```
新链接：https://itdesk.amanzac.com/itdesk/
```

> 这样员工点击转人工链接后，会跳转到 H5 自建应用页面（而非企微员工服务窗口）。

---

## §6 阶段一功能测试清单

### 6.1 基础连通性测试

| # | 测试项 | 方法 | 预期结果 | 状态 |
|---|--------|------|---------|------|
| 1 | Cloudflare Tunnel 连通 | 浏览器访问 `https://itdesk.amanzac.com/` | 页面正常加载 | ⬜ |
| 2 | 后端 API 健康 | 浏览器访问 `https://itdesk.amanzac.com/api/health` | 返回 `{"status":"ok"}` | ⬜ |
| 3 | H5 员工端页面 | 浏览器访问 `https://itdesk.amanzac.com/itdesk/` | H5 页面渲染 | ⬜ |
| 4 | 坐席工作台页面 | 浏览器访问 `https://itdesk.amanzac.com/itagent/` | 工作台页面渲染 | ⬜ |

### 6.2 OAuth2 登录测试

| # | 测试项 | 方法 | 预期结果 | 状态 |
|---|--------|------|---------|------|
| 5 | OAuth2 静默授权 | 在企微内点击应用入口 | H5 页面自动登录，显示员工身份 | ⬜ |
| 6 | 身份识别 | 授权后查看 H5 页面 | 显示当前用户姓名/工号 | ⬜ |

### 6.3 坐席工作台测试

| # | 测试项 | 方法 | 预期结果 | 状态 |
|---|--------|------|---------|------|
| 7 | 会话列表 | 坐席登录工作台 | 显示进行中的会话 | ⬜ |
| 8 | 聊天窗口 | 点击某个会话 | 显示完整对话记录 | ⬜ |
| 9 | 发送消息 | 坐席输入文本发送 | 消息发送成功 | ⬜ |
| 10 | 快速回复 | 点击快速回复面板 | 三级导航正常，模板可填入 | ⬜ |

### 6.4 端到端流程测试

| # | 测试项 | 方法 | 预期结果 | 状态 |
|---|--------|------|---------|------|
| 11 | AI 对话 → 转人工 | 员工与 AI 对话，触发转人工关键字 | 推送 H5 链接 | ⬜ |
| 12 | 员工点击 H5 链接 | 点击推送的链接 | 跳转到 H5 页面，自动登录 | ⬜ |
| 13 | 坐席收到会话 | 员工进入 H5 后 | 坐席工作台出现新会话 | ⬜ |
| 14 | 坐席回复 | 坐席使用快速回复 | 员工 H5 页面显示回复 | ⬜ |
| 15 | 企微通知 | 坐席回复后 | 员工收到企微应用消息通知 | ⬜ |

---

## §7 故障排查

### 7.1 Cloudflare Tunnel 连不上

```bash
# 检查 cloudflared 容器日志
docker compose -f docker-compose.nas.yml logs cloudflared

# 常见错误：
# ERR error="failed to connect to Cloudflare edge"
# → 检查 Token 是否正确
# → 检查 NAS 是否能访问外网
```

### 7.2 企微回调验证失败

```bash
# 检查后端是否收到回调请求
docker compose -f docker-compose.nas.yml logs backend | grep callback

# 常见原因：
# 1. Token / EncodingAESKey 与 .env 不一致
# 2. 后端回调路由路径不对（应为 /api/wecom/callback）
# 3. Nginx 反代配置未正确转发
```

### 7.3 OAuth2 授权失败

```
常见原因：
1. 可信域名未配置或未验证 → 企微管理后台检查
2. redirect_uri 与可信域名不匹配 → 检查回调 URL
3. CorpID 不正确 → 检查 .env 中的 WECOM_CORP_ID
```

### 7.4 容器状态异常

```bash
# 查看所有容器状态
docker compose -f docker-compose.nas.yml ps

# 查看特定容器详细日志
docker compose -f docker-compose.nas.yml logs --tail 100 backend

# 重启所有容器
docker compose -f docker-compose.nas.yml restart

# 完全重建（代码更新后）
docker compose -f docker-compose.nas.yml down
docker compose -f docker-compose.nas.yml up -d --build
```

---

## §8 与正式部署的区别

| 维度 | NAS 部署（测试） | 正式部署 |
|------|----------------|---------|
| 域名 | `itdesk.amanzac.com` | `it-dataquery.dc.servyou-it.com` |
| 内网穿透 | Cloudflare Tunnel | 公司内网直连 |
| HTTPS | Cloudflare 自动 | Nginx + 公司 CA 证书 |
| 数据库密码 | 测试密码 | 强密码 + 审计 |
| AI 引擎 | 可能不可用（Dify 在内网） | 可用 |
| 员工数 | 测试人员（<10人） | 全公司 |
| 企业微信认证 | 未认证（200人上限） | 已认证 |
| 数据持久化 | Docker Volume | K8s PVC / 独立 PG 集群 |

---

## 附录 A：Cloudflare Tunnel 原理简述

```
                    传统方式                         Cloudflare Tunnel
            ┌─────────────────┐                ┌─────────────────┐
互联网 ────→ │ 开放端口 + 公网IP  │    互联网 ────→ │ Cloudflare Edge  │
            │ + SSL 证书       │                │ (自动HTTPS)      │
            │ + DDNS/域名解析   │                └────────┬────────┘
            └─────────────────┘                          │
                    ↑                                    │ Tunnel（长连接）
                    │                                    │
            ┌─────────────────┐                ┌─────────────────┐
            │    NAS/服务器     │    cloudflared │    NAS/服务器     │
            │   (必须可达)      │    ←──主动连接──→│   (无需开放端口)  │
            └─────────────────┘                └─────────────────┘

优势：
1. 无需公网 IP — cloudflared 主动外连，不需要入站端口
2. 无需 SSL 证书 — Cloudflare Edge 自动处理 HTTPS
3. 无需 DDNS — 域名始终指向 Cloudflare
4. 更安全 — 不暴露 NAS 任何端口到公网
```
