Files
wenchuanyi/deploy/IIS部署与FTP发布.md
T
fanhongcai a30da88d04 docs: 部署手册按线上实战排错校正(目录结构/故障排查速查/500.30排查流程)
- 新增第0章目录结构认知:IIS 站点根=ContentRoot,前端产物需传嵌套 wwwroot/wwwroot,后端产物传 /wwwroot/
- 新增故障排查速查:500.30(publish漏传DLL/外来runtime文件/数据库连不上)、404静态资源、502 outofprocess、FTP 550(文件被IIS锁定)、FTP限流、配置不生效
- 新增500.30标准排查流程(开stdout/比对文件清单/检查目录结构)
- 更新发布方式(FTP 端口21、密码同数据库密码)与部署架构说明,按 2026-08-24 线上实战经验校正
2026-08-24 02:04:40 +08:00

169 lines
7.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 文传易 · IIS 部署与 FTP 发布手册
> 目标环境:Windows Server + IIS 10 + .NET 8 Hosting Bundle
> 站点地址:`https://wenchuanyi.bbitcn.net`
> 发布方式:FTP`ftp://116.198.221.125`,端口 21,用户 `wenchuanyi`,密码同数据库密码)
> **本文档已按 2026-08-24 线上实战排错结果校正,照此执行可避免再踩坑。**
---
## 0. 目录结构(最重要的认知,务必先看)
IIS 站点物理根 = **ContentRoot**(应用工作目录),也是后端产物所在目录;
ASP.NET Core 的静态文件 WebRoot = **ContentRoot\wwwroot(嵌套)**
实测服务器目录映射(FTP 的 `/wwwroot` ↔ 磁盘 `D:\wwwroot\wenchuanyi\wwwroot`):
```
D:\wwwroot\wenchuanyi\wwwroot\ ← FTP /wwwroot ContentRoot,后端产物 + web.config
├── web.config ← inprocess + dotnet(见第 3 节)
├── WenChuanyi.Api.dll / .exe / deps.json / runtimeconfig.json
├── appsettings.json ← 数据库 localhost / OSS / 上传限制
├── *.dllMySql.Data / BouncyCastle / ZstdSharp …) ← 缺一不可!
└── wwwroot\ ← FTP /wwwroot/wwwroot (嵌套 WebRoot,前端产物!)
├── index.html
└── assets\index-*.js / *.css
```
> **规则:后端产物传 `/wwwroot/`,前端产物传 `/wwwroot/wwwroot/`(嵌套)。**
> 前端产物若只放站点根(`/wwwroot/`),页面能 200IIS 默认文档/fallback)但 `/assets/*.js` 必然 404。
---
## 1. 部署架构
```
浏览器 → https://wenchuanyi.bbitcn.net
IIS + ANCMAspNetCoreModuleV2InProcess
├── /assets/*、/ → ASP.NET Core UseDefaultFiles+UseStaticFiles(只读嵌套 WebRoot
├── /#/pickup 等 SPA → MapFallbackToFile("index.html") 兜底(hash 路由)
└── /api、/api/open → 后端控制器
数据库:MySQL 同机 localhost:3306(库/用户 wenchuanyi
存储:阿里云 OSS(凭据在 appsettings.json,文件不入库)
```
---
## 2. 服务器一次性准备(首次部署前)
1. **安装 .NET 8 Hosting Bundle**dotnet.microsoft.com/download/dotnet/8.0)。
2. **创建 IIS 站点**:物理路径指向 `D:\wwwroot\wenchuanyi\wwwroot`(后端产物目录);
应用程序池 .NET CLR 版本选「**无托管代码**」(InProcess 由 ANCM 托管)。
3. **HTTPS 证书**:为 `wenchuanyi.bbitcn.net` 绑定 SSL 证书。
4. **防火墙**:放行 80 / 443(测试期 5280)。
---
## 3. web.config(不要乱改)
`dotnet publish` 自动生成的**默认配置**就是正确配置,保持原样:
```xml
<aspNetCore processPath="dotnet" arguments=".\WenChuanyi.Api.dll"
stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="inprocess" />
```
-**必须 `inprocess + dotnet`**Framework-dependent 标准)。
- ❌ 不要改成 `outofprocess + exe`——实测会导致 502/runtime 探测失败。
-`stdoutLogEnabled` 平时为 false;排障时才临时开 true,**查完必须改回 false**(改 web.config 会触发应用重启)。
---
## 4. 构建发布包(开发机)
```powershell
# 后端
cd backend/WenChuanyi.Api
dotnet publish -c Release # 输出 bin/Release/net8.0/publish/
# 前端
cd frontend
npm run build # 输出 dist/index.html + assets/
```
`publish/` 目录**所有文件**都要上传(约 24 个文件 / 12.4MB),框架依赖模式**不含** coreclr.dll 等 runtime 文件。
---
## 5. 敏感配置(appsettings.json,不入库)
| 配置节 | 键 | 值 |
| --- | --- | --- |
| `ConnectionStrings:MySql` | Data Source | **`localhost`**(MySQL 与站点同机,勿用公网 IP 回环) |
| `ConnectionStrings:MySql` | Password | `r7P^f*v7rFts` |
| `Oss` | AccessKeyId / Secret | 阿里云 OSS 凭据 |
| `App` | BaseUrl | `https://wenchuanyi.bbitcn.net` |
改连接串后**必须重启应用**(上传 web.config 或回收应用池)才生效——FreeSql 连接字符串启动时固定。
---
## 6. FTP 发布
### 6.1 上传清单(位置错了就会出上面的 404/500)
```
后端 publish/ 全部文件(web.config、appsettings.json、*.dll、*.exe、runtimes/ → FTP /wwwroot/
前端 dist/index.html + assets/ 全部 → FTP /wwwroot/wwwroot/
```
### 6.2 脚本
- `deploy/ftp_upload.ps1`:完整发布(后端 publish + 前端 build + FTP 递归上传)。
- `deploy/ftp_fast.ps1`:快速覆盖上传当前产物。
- `deploy/ftp_sync.ps1`:只补传缺失/大小不符的文件(推荐增量修复)。
- `deploy/ftp_apply.ps1`:定向更新(appsettings / web.config / 嵌套 assets)。
### 6.3 发布后生效
上传 **web.config** 或**回收应用程序池**使新版本生效:
```powershell
C:\Windows\System32\inetsrv\appcmd recycle apppool /apppool.name:wenchuanyi
```
> 无法远程回收时:重传一次 web.config(内容不变也行)即可触发 ANCM 重启。
---
## 7. 发布后验证清单(照做)
```powershell
# 1. 首页
curl.exe -s -o NUL -w "%{http_code}\n" https://wenchuanyi.bbitcn.net/
# → 200
# 2. JS / CSS 静态资源(最关键!之前 404 就出在这)
curl.exe -s -o NUL -w "%{http_code} %{size_download}\n" https://wenchuanyi.bbitcn.net/assets/index-Bwz67ZeI.js
# → 200 1558667
# 3. API(返回业务校验/JSON 而非 404 即后端存活)
curl.exe -s https://wenchuanyi.bbitcn.net/api/files/by-tag/__probe__
# → {"message":"标签无效"} HTTP 400(正常业务响应)
# 4. 全流程:上传 → 取件码 → 下载;管理列表可见
```
---
## 8. 故障排查速查(本次实战总结)
| 现象 | 原因 | 处理 |
| --- | --- | --- |
| **500.30** app failed to start | ① publish 文件**漏传**(本次漏 `MySql.Data.dll``K4os.Compression.LZ4.dll`FreeSql.MySql 运行必需);② 站点根混入外来 runtime 文件(coreclr/hostfxr/hostpolicy/aspnetcorev2_inprocess 等);③ 数据库连不上(启动时 `SyncStructure` 抛错) | 对比本地 `publish/` 与服务器文件清单;删掉外来 runtime 文件;开 stdout 看具体异常 |
| **404 静态资源**`/assets/*.js`) | 前端产物放错目录——只放站点根没放**嵌套 `wwwroot/wwwroot`** | 前端产物必须传 `/wwwroot/wwwroot/` |
| **502 / outofprocess 探测失败** | web.config 被改成 `outofprocess + exe` | 恢复 `inprocess + dotnet` |
| **FTP 上传 550** | 目标文件已存在且被 IIS 进程锁定;或服务器限流 | **先 DeleteFile 再上传**,或临时名上传 + Rename;串行 + 重试 |
| **FTP 连接频繁中断** | 服务器对高频连接限流 | 所有 FTP 脚本已串行 + 每次间隔 + 校验大小重试 |
| **改配置不生效** | appsettings/代码变了但没重启应用 | 重传 web.config 或回收应用池 |
### 排查 500.30 的标准流程
1. **开 stdout**web.config 改 `stdoutLogEnabled="true"` → 等待重启 → 下载 `logs/stdout_*.log` 看异常 → 查完改回 false。
2. **比对文件**:本地 `publish/` 文件清单(名字+大小)vs FTP `/wwwroot/` 清单,找出缺失项。
3. **看目录结构**:确认前后端产物分别在 `/wwwroot/``/wwwroot/wwwroot/`,站点根无多余 runtime 文件。
---
## 9. 安全提示
- `appsettings.json` 含数据库密码与 OSS 凭据,**不要上传到代码仓库 / 不要外传**(已在 .gitignore)。
- FTP 凭据仅运维持有,建议定期轮换。
- 日志不会打印 OSS 凭据、数据库密码与文件内容明文。