四端上传
This commit is contained in:
1 parent
25bbb5f9c8
commit
c6e2cb4d5b
276 files changed
+17812
-3
No files matched your search
+263
@@ -0,0 +1,263 @@
|
||||
# 部署指南
|
||||
|
||||
面向接手部署的人。按顺序执行即可,每一步都有验证方法。
|
||||
|
||||
---
|
||||
|
||||
## 0. 变量约定
|
||||
|
||||
下文用占位符代替真实域名,部署时替换:
|
||||
|
||||
只需要**三个域名**:管理后台直接调用 `<API域名>`(服务端同一进程内含 `/admin/v1/*`),
|
||||
不需要单独的接口域名。
|
||||
|
||||
| 占位符 | 含义 | 举例 |
|
||||
|---|---|---|
|
||||
| `<API域名>` | 服务端 API 域名 | `yelaymaths-api.example.com` |
|
||||
| `<后台域名>` | 管理后台域名 | `yelaymaths-admin.example.com` |
|
||||
| `<数据域名>` | 课程数据(图片 / 视频)域名 | `yelaymaths-data.example.com` |
|
||||
|
||||
> ⚠️ **三个域名都不能含下划线。** 下划线不是合法的主机名字符(RFC 1034/1035 只允许字母、数字、连字符),
|
||||
> 后果是 Let's Encrypt 拒签证书、微信「request 合法域名」校验也会拒绝。
|
||||
>
|
||||
> 用中划线:`yelaymaths-api.example.com`,不要用 `yelaymaths_api.example.com`。
|
||||
|
||||
---
|
||||
|
||||
## 1. 服务器准备(宝塔面板)
|
||||
|
||||
1. 软件商店安装:**MySQL 5.7**、**Nginx**、**Node 版本管理器**(选 Node 22 LTS)。
|
||||
2. 防火墙放行 80 / 443。
|
||||
3. 建 3 个站点,各配 Let's Encrypt 证书:
|
||||
|
||||
| 站点 | 反向代理到 |
|
||||
|---|---|
|
||||
| `<API域名>` | `http://127.0.0.1:3000` |
|
||||
| `<后台域名>` | `http://127.0.0.1:3001` |
|
||||
|
||||
> 这两个站点**都不是静态站点**,反向代理必须配,只上传文件不会工作。
|
||||
|
||||
4. 建数据端站点 `<数据域名>`,根目录指向课程数据目录(见第 6 节)。
|
||||
|
||||
---
|
||||
|
||||
## 2. 数据库
|
||||
|
||||
1. 新建数据库 `yelaymaths`,字符集 `utf8mb4`。
|
||||
2. 新建数据库账号并授权。
|
||||
|
||||
> **关于 Prisma 权限**:`prisma migrate dev` 需要 `CREATE DATABASE` 权限来建影子库,宝塔默认账号没有。
|
||||
> 生产环境**只用** `pnpm prisma:migrate`(即 `prisma migrate deploy`),它不建影子库,无需额外权限。
|
||||
|
||||
3. **备份旧库**(迁移前必做):
|
||||
|
||||
```bash
|
||||
mysqldump -u <用户> -p api_yeomai_site > /root/backup/api_yeomai_site_$(date +%F).sql
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 部署服务端
|
||||
|
||||
```bash
|
||||
cd /www/wwwroot
|
||||
git clone <仓库地址> yelaymaths
|
||||
cd yelaymaths/yelaymaths_api
|
||||
pnpm install
|
||||
cp .env.example .env
|
||||
vi .env # 按下表填写
|
||||
```
|
||||
|
||||
### 必须填写的环境变量
|
||||
|
||||
| 变量 | 说明 |
|
||||
|---|---|
|
||||
| `DATABASE_URL` | `mysql://用户:密码@127.0.0.1:3306/yelaymaths` |
|
||||
| `LEGACY_DATABASE_URL` | 旧库连接串,仅迁移脚本使用 |
|
||||
| `API_BASE_URL` | `https://<API域名>` |
|
||||
| `STATIC_BASE_URL` | `https://<数据域名>` |
|
||||
| `ADMIN_ORIGIN` | `https://<后台域名>`(跨域白名单) |
|
||||
| `JWT_ACCESS_SECRET` | 随机 32 位以上 |
|
||||
| `JWT_REFRESH_SECRET` | 随机 32 位以上 |
|
||||
| `SESSION_KEY_ENC_SECRET` | 随机 32 位以上,用于加密存储用户 sessionKey |
|
||||
| `MEDIA_SIGN_SECRET` | 随机 32 位以上,用于播放地址签名 |
|
||||
| `WX_APPID` | `wx3fbaf897825bf04f` |
|
||||
| `WX_APPSECRET` | 小程序密钥 |
|
||||
| `WX_OFFER_ID` / `WX_PAY_APPKEY` | 虚拟支付参数,未开通可留空 |
|
||||
| `DATA_ROOT` | 课程数据目录的**绝对路径** |
|
||||
|
||||
> 生成随机密钥:`openssl rand -hex 32`
|
||||
>
|
||||
> ⚠️ `STATIC_BASE_URL` 必须在跑数据迁移**之前**填对。旧库里有 48 处内容写死了旧域名,
|
||||
> 迁移时会按这个变量改写;填错会导致图片与视频全部 404。
|
||||
|
||||
### 建表、迁移、启动
|
||||
|
||||
```bash
|
||||
pnpm prisma:generate
|
||||
pnpm prisma:migrate # 建表
|
||||
pnpm legacy:check # 体检
|
||||
pnpm legacy:migrate -- --dry-run # 核对行数
|
||||
pnpm legacy:migrate # 正式迁移
|
||||
pnpm build
|
||||
```
|
||||
|
||||
在宝塔「Node 项目」里新建项目:
|
||||
|
||||
- 项目目录:`/www/wwwroot/yelaymaths/yelaymaths_api`
|
||||
- 启动文件:`dist/main.js`
|
||||
- 端口:`3000`
|
||||
- 运行方式:PM2
|
||||
|
||||
**验证**:`curl https://<API域名>/healthz` 应返回 `{"code":0,...,"db":"ok"}`。
|
||||
若 `db` 为 `down`,说明数据库连接串不对。
|
||||
|
||||
---
|
||||
|
||||
## 4. 部署管理后台
|
||||
|
||||
```bash
|
||||
cd /www/wwwroot/yelaymaths/yelaymaths_admin
|
||||
pnpm install
|
||||
cp .env.example .env.local
|
||||
vi .env.local # NEXT_PUBLIC_API_BASE_URL=https://<API域名>
|
||||
pnpm build
|
||||
```
|
||||
|
||||
同样用宝塔「Node 项目」启动:
|
||||
|
||||
- 启动文件:`node_modules/next/dist/bin/next`,参数 `start -p 3001`
|
||||
- 或直接用 `pnpm start`
|
||||
- 端口:`3001`
|
||||
|
||||
**验证**:打开 `https://<后台域名>`,应看到登录页。
|
||||
首次使用点「创建管理员账号」,创建完成后切回登录。
|
||||
|
||||
> 该接口只在系统中没有任何管理员时生效,之后调用会返回「已存在」,因此可以安全保留。
|
||||
|
||||
---
|
||||
|
||||
## 5. 部署课程数据端
|
||||
|
||||
把旧服务器的资源目录复制到 `<数据域名>` 站点根目录:
|
||||
|
||||
| 来源 | 目标 | 体积参考 |
|
||||
|---|---|---|
|
||||
| 旧站 `Images/` | `<根>/Images/` | 约 195 MB |
|
||||
| 旧站 `WebPages/` | `<根>/WebPages/` | 约 21 MB |
|
||||
| 旧站 `Course/` | `<根>/Course/` | 视频文件 |
|
||||
| 旧站 `FreeVideos/` | `<根>/FreeVideos/` | 视频文件 |
|
||||
|
||||
再从旧小程序的 `static/image/` 复制三张占位图到 `<根>/Images/Placeholder/`:
|
||||
|
||||
```
|
||||
Images/Placeholder/user.png
|
||||
Images/Placeholder/defaultAvatar.png
|
||||
Images/Placeholder/weixin.png
|
||||
```
|
||||
|
||||
**目录名与文件名不可更改**,前端是拼路径访问的。完整约定见
|
||||
[`yelaymaths_data.yeomai.site/README.md`](../yelaymaths_data.yeomai.site/README.md)。
|
||||
|
||||
### ⚠️ 付费视频目录必须挡住
|
||||
|
||||
付费视频的鉴权由服务端 `/media/*` 签名通道提供(地址有效期 30 分钟,HLS 的 `.ts` 分片也逐行带签名)。
|
||||
但如果 `Course/` 目录同时被数据域名公开暴露,任何人猜到路径就能直接下载,这套防护等于没有。
|
||||
|
||||
**在数据端站点的 Nginx 配置里加一条:**
|
||||
|
||||
```nginx
|
||||
location ^~ /Course/ {
|
||||
deny all;
|
||||
}
|
||||
```
|
||||
|
||||
免费内容(`Images/`、`WebPages/`、`FreeVideos/`)保持公开即可。
|
||||
|
||||
> 若后续改用 CDN,把 `MediaService.buildSignedUrl` 换成 CDN 厂商的签名方式,并在 CDN 侧对 `Course/` 开鉴权。
|
||||
|
||||
---
|
||||
|
||||
## 6. 配置小程序
|
||||
|
||||
1. 编辑 `yelaymaths/config/index.js`:
|
||||
|
||||
```js
|
||||
API_BASE_URL: 'https://<API域名>',
|
||||
STATIC_BASE_URL: 'https://<数据域名>',
|
||||
```
|
||||
|
||||
2. 用微信开发者工具打开 `yelaymaths/`,执行【工具 → 构建 npm】。
|
||||
3. 上传并提交审核。
|
||||
|
||||
> 小程序**不打包任何业务图片**,只保留 6 个 tabBar 图标(约 19 KB)。
|
||||
> tabBar 图标必须本地,这是微信的限制,无法改为网络图。
|
||||
|
||||
---
|
||||
|
||||
## 7. 微信小程序后台配置
|
||||
|
||||
| 配置项 | 位置 | 值 |
|
||||
|---|---|---|
|
||||
| request 合法域名 | 开发 → 开发管理 → 开发设置 | `https://<API域名>` |
|
||||
| 发货推送 URL | 虚拟支付 → 基本配置 | `https://<API域名>/v1/payments/notify` |
|
||||
| 小程序简称 | 虚拟支付 → 基础配置 | iOS 支付必需 |
|
||||
| 苹果 IAP 支付 | 虚拟支付 → 基础配置 | iOS 支付需开启 |
|
||||
| 支付道具 | 虚拟支付 → 道具管理 | 每门课建一个,记下道具 ID 与价格 |
|
||||
|
||||
> `<image>` 与 `<video>` 的资源域名**不受合法域名限制**,所以数据域名与 CDN 都不需要加白名单。
|
||||
|
||||
创建完道具后,在管理后台「支付商品」里把 `课程 ID`、`微信道具 ID`、`价格(分)` 填进去,
|
||||
价格必须与微信后台完全一致(单位:分)。
|
||||
|
||||
---
|
||||
|
||||
## 8. 上线顺序
|
||||
|
||||
建议严格按此顺序,每步都可独立验证:
|
||||
|
||||
1. 服务器与数据库就绪 → 备份旧库
|
||||
2. 部署服务端 → `/healthz` 返回 `db: ok`
|
||||
3. 建表 + 数据迁移 → 行数校验通过
|
||||
4. 部署管理后台 → 能登录,用户数与旧库一致
|
||||
5. 部署数据端 → 浏览器直接打开一张图片能显示
|
||||
6. 小程序改配置并上传 → 真机验证:首页图片、试听播放、已购课程播放
|
||||
7. 微信后台配域名与支付 → 用一笔小额真实订单验证:支付 → 发货 → 课程出现在「知识」页
|
||||
|
||||
---
|
||||
|
||||
## 9. 上线后验证清单
|
||||
|
||||
- [ ] `/healthz` 返回 `db: ok`
|
||||
- [ ] 管理后台用户数 = 284(迁移前旧库数量)
|
||||
- [ ] 随机挑一个老用户,其「已购课程」与升级前一致
|
||||
- [ ] 首页轮播、新课长图、试听封面图片全部能加载
|
||||
- [ ] `pages/VideoDetailsPage/VideoDetailsPage` 的公式图能显示
|
||||
- [ ] 免费试听能播放
|
||||
- [ ] 已购课程能播放(走 `/media/...` 签名地址)
|
||||
- [ ] 未登录状态下访问受保护页面会跳转登录
|
||||
- [ ] 未购买课程看不到课时列表(直接请求接口返回 3000 错误码)
|
||||
- [ ] 支付一笔小额订单,课程正确开通
|
||||
- [ ] 管理后台能看到这笔订单,状态为「已开通」
|
||||
|
||||
---
|
||||
|
||||
## 10. 回滚
|
||||
|
||||
- 旧服务端与旧数据库**保留不动**,直到新系统稳定运行一段时间。
|
||||
- 小程序出现严重问题时,可在微信后台回退到上一个版本。
|
||||
- 数据库出问题时用第 2 节的备份恢复。
|
||||
|
||||
---
|
||||
|
||||
## 11. 安全提醒
|
||||
|
||||
以下密钥曾在旧代码与数据库导出文件中明文出现,**必须全部轮换**:
|
||||
|
||||
- 旧数据库账号密码
|
||||
- 阿里云 AccessKey(旧短信模块使用,该模块已删除)
|
||||
- 163 邮箱授权码(旧邮件脚本使用,已删除)
|
||||
- 小程序 AppSecret
|
||||
|
||||
> ⚠️ **AppSecret 不能提前换**。旧 PHP 服务仍在使用它,一换线上小程序立刻无法登录。
|
||||
> 正确做法是:新后端上线并确认可用后,再在微信后台重置 AppSecret 并同步更新新后端配置。
|
||||
Reference in new issue
Block a user