Files
wenchuanyi/deploy/IIS部署与FTP发布.md
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

7.5 KiB
Raw Permalink Blame History

文传易 · IIS 部署与 FTP 发布手册

目标环境:Windows Server + IIS 10 + .NET 8 Hosting Bundle 站点地址:https://wenchuanyi.bbitcn.net 发布方式:FTPftp://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 Bundledotnet.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 自动生成的默认配置就是正确配置,保持原样:

<aspNetCore processPath="dotnet" arguments=".\WenChuanyi.Api.dll"
            stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="inprocess" />
  • 必须 inprocess + dotnetFramework-dependent 标准)。
  • 不要改成 outofprocess + exe——实测会导致 502/runtime 探测失败。
  • stdoutLogEnabled 平时为 false;排障时才临时开 true,查完必须改回 false(改 web.config 会触发应用重启)。

4. 构建发布包(开发机)

# 后端
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回收应用程序池使新版本生效:

C:\Windows\System32\inetsrv\appcmd recycle apppool /apppool.name:wenchuanyi

无法远程回收时:重传一次 web.config(内容不变也行)即可触发 ANCM 重启。


7. 发布后验证清单(照做)

# 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.dllK4os.Compression.LZ4.dllFreeSql.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. 开 stdoutweb.config 改 stdoutLogEnabled="true" → 等待重启 → 下载 logs/stdout_*.log 看异常 → 查完改回 false。
  2. 比对文件:本地 publish/ 文件清单(名字+大小)vs FTP /wwwroot/ 清单,找出缺失项。
  3. 看目录结构:确认前后端产物分别在 /wwwroot//wwwroot/wwwroot/,站点根无多余 runtime 文件。

9. 安全提示

  • appsettings.json 含数据库密码与 OSS 凭据,不要上传到代码仓库 / 不要外传(已在 .gitignore)。
  • FTP 凭据仅运维持有,建议定期轮换。
  • 日志不会打印 OSS 凭据、数据库密码与文件内容明文。