ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

IIS安装配置与网站部署:应用程序池权限与.NET 8托管解析

IIS安装配置与网站部署:应用程序池权限与.NET 8托管解析 很多人第一次接触 IIS都是被一句把网站放上去就行给骗进来的。装完 IIS、放好文件、浏览器一敲 localhost结果要么 404要么 403要么一个莫名其妙的 503回头翻教程发现别人的界面跟你完全不一样。我在真实环境里配过的 IIS 站点从 Windows 10 本地调试到 Windows Server 2019 上的正式站点都有踩过的坑基本集中在三块功能项没勾对、应用程序池权限没理顺、托管模型选错了。这篇就把 IIS 安装配置和简单网站部署整条链路拆开讲清楚包括静态站点、ASP.NET Core比如 .NET 8 在 IIS 功能列表里根本找不到这件事、以及那个让很多人抓狂的应用程序池权限设置失败 0x80005000。不管你是第一次装 IIS还是配过几次但总在权限和 500 错误上卡壳下面这些内容都能直接照着做。1. 装 IIS 之前先把这几件事想清楚1.1 Win10/Win11 与 Windows Server 的安装入口差别IIS 不属于默认安装的组件它是 Windows 的可选功能。桌面版和服务器版的入口长得完全不一样这是导致照着教程做但找不到按钮的头号原因。Windows 10 / Windows 11 上你有三个入口随便哪个都行按Win R输入optionalfeatures回车直接打开Windows 功能对话框。这是最快的方式我一般都用这个。控制面板 → 程序和功能 → 启用或关闭 Windows 功能。设置 → 系统 → 可选功能 → 更多 Windows 功能Win11 的新路径。Windows Server 2019 / 2022 上桌面版是走服务器管理器 → 添加角色和功能 → Web 服务器(IIS)这条路Server Core 没有图形界面只能用 PowerShellInstall-WindowsFeature -Name Web-Server -IncludeManagementTools这里有个细节值得说桌面版的 IIS 版本号跟着系统走Server 2019 对应 IIS 10Server 2022 也是 IIS 10版本号虽然一样但默认启用的模块集合和桌面版不同。所以你在 Win11 上验证通的配置搬到 Server 2019 上不一定原样跑得起来——尤其是身份验证模块桌面版默认装的东西更少。另外提醒一句装 IIS 的过程会往系统里写一个W3SVC服务和一个WASWindows Process Activation Service服务两者是父子关系。装完之后别急着配站点先确认这两个服务是正在运行后面很多奇怪报错都是它们没起来造成的。1.2 功能勾选清单哪些是必需的哪些是可选装但早晚要用的Windows 功能树里 IIS 展开之后有几十个勾选项全勾上不是不行但没必要而且会增加攻击面。我按必修 / 建议装 / 用到再装三档给你梳理一遍。分类功能项建议说明Web 管理工具IIS 管理控制台必修没它就只能用命令行日常运维别省这个常见 HTTP 功能静态内容必修不勾的话 HTML、图片一律返回 404.3这是新手第一个坑常见 HTTP 功能默认文档必修不勾的话访问目录不会自动找 index.html常见 HTTP 功能目录浏览用到再装调试期开着方便正式环境建议关掉常见 HTTP 功能HTTP 错误、HTTP 重定向建议装错误页和 301 跳转要用运行状况和诊断HTTP 日志必修排错全靠它运行状况和诊断请求监视器、跟踪建议装配失败请求跟踪FREB必须要有安全性请求筛选必修默认就在很多 404/403 和它有关安全性Windows 身份验证用到再装内网系统、域环境做免登录才需要应用程序开发功能.NET Extensibility、ASP.NET 4.x看情况跑经典 ASP.NET 才勾应用程序开发功能WebSocket 协议用到再装实时通信、SignalR 要用应用程序开发功能CGI、ISAPI 扩展/筛选器尽量别装老系统遗留安全风险高静态内容这一项是我见过最多人漏勾的。症状很典型IIS 装好了管理界面能打开默认站点也能看到欢迎页但你新建一个站点放一堆 HTML访问就是 404.3提示由于扩展配置问题而无法提供您请求的页面。原因就是静态文件处理器没注册IIS 根本不认识.html。不用重装回到启用或关闭 Windows 功能把静态内容勾上确定等服务重启完就好。还有一点Windows 10/11 的万维网服务节点下默认是不勾 ASP.NET 的所以你打开 IIS 管理器看不到ASP.NET那一组图标。需要跑 .aspx 的时候再回来勾顺便勾上 .NET Extensibility。1.3 用命令行装一遍顺便解决网上教程和我界面不一样的问题图形界面点来点去容易漏服务器上批量装的时候我更喜欢用命令行一次到位、可复制、可写进部署脚本。DISM 方式桌面版和服务器版都支持dism /online /enable-feature /featurename:IIS-WebServerRole /all /norestart dism /online /enable-feature /featurename:IIS-WebServer /all /norestart dism /online /enable-feature /featurename:IIS-ManagementConsole /all /norestart dism /online /enable-feature /featurename:IIS-StaticContent /all /norestart dism /online /enable-feature /featurename:IIS-DefaultDocument /all /norestart dism /online /enable-feature /featurename:IIS-HttpLogging /all /norestartPowerShell 方式桌面版Enable-WindowsOptionalFeature -Online -FeatureName IIS-WebServerRole, IIS-WebServer, IIS-ManagementConsole, IIS-StaticContent -All想知道系统里到底有哪些可用的 IIS 功能名可以跑一句dism /online /get-features | findstr /i IIS用命令行的好处不只是快。当你在服务器上装完再想加模块时图形界面点完要等一会儿命令行加/all会自动把依赖项一起装上省掉勾了 ASP.NET 但没装 ISAPI 扩展导致页面报错这类连带问题。2. 装完之后的第一件事让默认站点先跑通2.1 用 localhost 验证 IIS 是否真的在监听IIS 装完会自动创建一个叫Default Web Site的站点物理路径是C:\inetpub\wwwroot绑定*:80:。浏览器打开http://localhost看到那个蓝白色的 IIS 欢迎页说明安装这一步是成功的。如果看不到别急着怀疑配置先做三个基础检查# 1. 服务状态 sc query W3SVC sc query WAS # 2. 端口监听 netstat -ano | findstr :80 # 3. 谁在占 80 tasklist | findstr 上面查到的PIDnetstat那一步很关键。如果 80 端口被占了netstat会显示LISTENING的进程 ID把 ID 拿去tasklist一查就知道是谁。最常见的占用者有三个SQL Server Reporting Services、Skype老版本、以及某些装了 Java 服务的机器比如 Tomcat 或者用 80 端口的应用。我之前有台测试机装了某个开发工具之后 80 端口就被悄悄占了IIS 启动时不会报错只是站点起不来找了一下午才发现。还有一种情况是netstat显示0.0.0.0:80是 IIS 自己但访问超时——那大概率是防火墙拦了。Windows 防火墙在装 IIS 的时候通常会自动放行万维网服务(HTTP 流量入站)规则但如果规则被禁用了就得手动加netsh advfirewall firewall add rule nameIIS-HTTP-80 dirin actionallow protocolTCP localport802.2 80 端口被占用时的排查顺序假设 80 被占了你有两条路把占用者干掉或者让 IIS 换个端口。生产环境里我一般建议保留 80 给 IIS把别的服务挪走因为域名解析默认走 80你换端口就意味着用户访问要带端口号体验很差。真要换端口就在 IIS 管理器里选中站点 → 右侧绑定 → 编辑 → 把 80 改成比如 8080。改完记得三件事一起做否则还是访问不了防火墙放行新端口云服务器的话安全组也要放行新端口本地 IIS 部署最容易忘的一环用netstat -ano | findstr :8080确认新端口真的被 IIS 监听了。我还遇到过一种假占用netstat显示 80 是被一个已经退出的进程占着属于 TIME_WAIT 或者僵尸监听。这种情况重启一下W3SVC服务就好iisresetiisreset会重启 IIS 相关的全部服务是万能的先重启一下操作。但它有代价所有站点会中断几秒到几十秒生产环境慎用尤其是有长连接的业务。更温和的做法是只回收出问题的应用程序池或者在services.msc里单独重启World Wide Web Publishing Service。2.3 把默认站点留着还是删掉我的习惯是默认站点留着不动新建自己的站点。理由有三个。一是默认站点是 IIS 安装成功的活体证明出问题时它是最好的对照组——如果默认站点能访问、你的站点不能问题就一定在你的站点配置上而不是 IIS 本身。二是删掉默认站点之后日志目录C:\inetpub\logs\LogFiles\W3SVC1的编号会乱排查历史问题时容易对不上。三是默认站点的物理路径wwwroot是系统目录权限结构比较特殊很多教程让人把项目直接丢进去结果后面遇到一堆权限和文件锁定的怪问题。默认站点的正确用法是留着当探针别往里放业务代码。你自己的站点点建立时物理路径选一个独立目录比如D:\sites\demo这样备份、迁移、改权限都清爽不用去碰系统目录。如果你确实想删掉它也建议先把它的绑定改成 8080 或者干脆停掉而不是直接删除——删了之后某些依赖默认站点存在的第三方安装程序比如某些老版本的 .NET 安装包会报错。3. 应用程序池IIS 里最容易被忽略、也最容易出事的对象3.1 应用程序池、网站、物理路径三者的关系这三个概念是 IIS 的核心但很多人装了几年也没搞清楚。我打个比方网站是门面它管的是 URL、域名、端口也就是用户从哪儿进来。物理路径是仓库它管的是文件实际在磁盘的哪个位置。应用程序池是工人它管的是用哪个身份、哪套运行时去处理这些请求。用户请求进来 → 网站根据绑定匹配 → 找到物理路径里的文件 → 交给绑定的应用程序池处理 → 应用程序池以某个身份读取文件并返回结果。这三者的绑定关系在IIS 管理器 → 网站 → 选中站点 → 右侧的基本设置里能看到。应用程序池和网站不是一对一强制关系多个网站可以共用一个应用程序池内网一堆小站点为了省内存经常这么干。但我不推荐一个池崩了挂在上面的所有站点一起挂而且权限隔离也做不了。3.2 托管管道模式与 .NET CLR 版本怎么选新建应用程序池时有两个下拉框经常让人犹豫选项可选值怎么选.NET CLR 版本v4.0 / v2.0 / 无托管代码经典 ASP.NET 4.x 选 v4.0纯静态和 ASP.NET Core 选无托管代码托管管道模式集成 / 经典新项目一律选集成只有老 WebForm 或依赖 ISAPI 的老系统才用经典集成模式和经典模式的差别简单说就是经典模式下请求要经过 IIS 自己的 ISAPI 管道再转交给 ASP.NET两套机制并行集成模式下两者合一URL 重写、授权规则这些模块能统一生效。现在遇到的所有新项目答案都是集成 对应的 CLR 版本。这里有个新手最容易犯的错部署纯静态站点或者 ASP.NET Core 站点时应用程序池的 .NET CLR 版本一定要选无托管代码。如果选了 v4.0IIS 会尝试用 .NET Framework 的管道去处理静态站点可能还能跑但 ASP.NET Core 站点会直接报 500.19 或者 502.5因为它的运行时根本不是 .NET Framework。3.3 应用程序池标识与目录权限的正确做法这一节是整篇文章的重点之一因为访问被拒绝和权限这两个词能解释掉一线运维 80% 的疑难杂症。应用程序池的标识决定了两件事进程以谁的身份运行以及匿名请求以谁的身份读文件在默认的匿名身份验证配置下。可选值有这么几个ApplicationPoolIdentity默认IIS 为每个应用程序池动态创建的一个虚拟账户名字叫IIS AppPool\池名。这是最推荐的做法。NetworkService老版本的默认值权限比 ApplicationPoolIdentity 宽隔离性差一些。LocalSystem最高权限本地系统账户。能用但等于把整个系统的权限交出去了除非有特殊需求否则不要用。自定义账户用一个指定的本地或域账户跑需要自己输密码。跨机器访问共享目录时才需要。推荐用ApplicationPoolIdentity然后给站点目录授予这个虚拟账户读权限。命令是icacls D:\sites\demo /grant IIS AppPool\demo:(OI)(CI)(RX) /T参数解释一下别抄错了(OI)是对象继承(CI)是容器继承这两个保证子文件夹和文件也拿到权限。(RX)是读取和执行静态站点够了。/T表示递归到所有子目录。如果站点需要往某个目录写文件比如上传目录、日志目录、缓存目录只给那个子目录写权限不要整个站点给写icacls D:\sites\demo\uploads /grant IIS AppPool\demo:(OI)(CI)(M) /T(M)是修改权限包含读写和删除。注意网上大量教程会让你直接给Everyone完全控制或者给IIS_IUSRS写权限。前者等于把服务器开放给所有登录用户后者范围也太宽。正确做法是精准授权到应用程序池虚拟账户出问题时用有效权限功能验证而不是靠猜。3.4 快速故障保护和闲置回收网站莫名其妙的 503讲两个应用程序池的默认行为它们经常让人以为服务器坏了。第一个是快速故障保护Rapid-Fail Protection。默认配置下如果一个应用程序池在 5 分钟内连续崩溃 5 次IIS 会把它标记为不可用之后所有请求一律返回 503 Service Unavailable而且不会自动恢复除非你手动启动它。症状是网站本来好好的某天开始突然一直 503重启服务能好一阵过一会儿又 503。排查方法是在应用程序池 → 选中池 → 高级设置 → 快速故障保护里看是不是被禁用了同时去看事件查看器的Windows 日志 → 应用程序那里面会有进程崩溃的记录。临时救急可以把启用快速故障保护关掉但根本原因一定是应用自身在崩把崩溃修好才是正解。第二个是闲置超时和定期回收。默认闲置 20 分钟就回收工作进程回收之后第一个请求要重新加载应用会明显变慢。如果你们的监控告警对响应时间敏感这个首次访问慢会被反复误报。解决办法是把这个池的启动模式改成AlwaysRunning再配合预加载功能# 让应用池常驻 C:\Windows\System32\inetsrv\appcmd set apppool demo /startMode:AlwaysRunning # 给站点开启预加载 C:\Windows\System32\inetsrv\appcmd set app demo/ /preloadEnabled:true改完之后IIS 启动时就会主动把应用加载起来第一个真实用户不会吃到那几秒的冷启动。4. 部署一个纯静态站点从目录规划到外网访问4.1 目录规划不要把站点放在 C:\inetpub\wwwroot 下面这是我最想强调的一条经验。把项目放在系统盘的系统目录里短期省事长期全是麻烦系统盘空间容易满、备份策略要单独处理、权限继承链复杂wwwroot有一堆来自父目录的继承权限、重装系统时容易丢代码。我习惯的目录结构是这样D:\sites\ ├── demo\ # 站点根目录 │ ├── index.html │ ├── css\ │ ├── js\ │ └── uploads\ # 单独授权写权限 ├── demo2\ └── logs\ # 如果要把日志也挪出来把站点放数据盘还有个附带好处如果你把 IIS 日志目录也改到数据盘系统盘被日志写满导致服务器假死的风险就没有了。IIS 的默认日志路径是C:\inetpub\logs\LogFiles访问量大的站点一天能写几百 MB 到几个 GB我见过不止一次因为日志撑爆系统盘导致整个服务不可用的案例。在IIS 管理器 → 选中服务器节点 → 日志里可以把目录改到D:\logs\iis。4.2 添加网站与绑定设置的具体操作操作路径IIS 管理器 → 左侧展开服务器 → 右键网站 → 添加网站。弹出的对话框里有四项要填网站名称随便起但建议和目录名、应用程序池名保持一致。我见过有人网站叫 A、池叫 B、目录叫 C半年后自己都分不清。物理路径选D:\sites\demo。绑定类型httpIP 地址选全部未分配端口按需填主机名留空局域网 IP 访问或填域名域名访问。应用程序池点选择可以新建一个同名池。建完立刻做三件事应用程序池的 .NET CLR 版本确认为无托管代码静态站点给目录授权应用程序池虚拟账户读权限上一节的icacls命令在默认文档里加上index.html——这一步很多人会忘因为 IIS 的默认文档列表里只有Default.htm、Default.asp、index.htm、iisstart.htm这几个没有index.html。不加上它访问站点根路径会返回 403.14 目录列表被拒绝。关于主机名这里补充一句如果你打算用一个域名指向这台机器主机名就填完整域名比如demo.example.com。同一个 IP 可以绑多个域名靠主机头区分这是 IIS 上跑多个站点的标准做法。绑完之后本地验证可以用 hosts 文件临时指向127.0.0.1 demo.example.com改 hosts 记得用管理员权限编辑C:\Windows\System32\drivers\etc\hosts改完ipconfig /flushdns刷一下缓存。4.3 MIME 类型那些打开就下载、或者报 404.3 的文件静态站点跑起来之后第二个高频问题就来了某些文件类型访问不了或者浏览器不解析直接下载。原因在于 IIS 只认识它在 MIME 类型列表里注册过的扩展名。列表里没有的要么返回 404.3要么以application/octet-stream返回导致浏览器下载。现代前端项目里最常缺的几种扩展名MIME 类型什么时候需要.jsonapplication/json接口 mock、配置文件.woffapplication/font-woff老版本字体文件.woff2font/woff2现在的主流字体格式.webmanifestapplication/manifestjsonPWA.wasmapplication/wasmWebAssembly比如 Unity WebGL.apk / .ipaapplication/vnd.android.package-archive应用分发页添加方式有两种。图形界面选中站点 → MIME 类型 → 添加填扩展名和类型。命令行更适合批量C:\Windows\System32\inetsrv\appcmd set config demo -section:staticContent [fileExtension.json,mimeTypeapplication/json]Unity 发布 WebGL 到 IIS 这个场景值得单独说因为它的坑比普通静态站点深一层。Unity WebGL 构建产物里有一堆.wasm、.data、.js文件而且如果开启了 Brotli 或 Gzip 压缩产出的还是.br、.gz文件。这时候光加 MIME 类型还不够浏览器要求这些预压缩文件必须带Content-Encoding: br或Content-Encoding: gzip响应头IIS 默认不会加结果就是页面加载时报无法解压或者一直卡在加载进度条。两个解决方向简单粗暴Unity 的 Publishing Settings 里把 Compression Format 改成Disabled或者勾上Decompression Fallback。代价是包体积变大、加载变慢但一定跑得起来。正规做法在站点根目录放一个web.config配置httpCompression和rewrite规则把.br和.gz请求映射到原始文件并加上对应的 Content-Encoding 头。这个需要 URL Rewrite 模块而且配置比较绕调试成本高。我自己做内部演示和测试环境时基本都选第一个方案先把功能跑通再考虑优化。顺便提一句热词里那个根据以下步骤在网站根目录下部署验证文件的场景——很多平台做站点归属验证时会要求你把一个特定的验证文件比如xxx.txt放到网站根目录然后通过http://你的域名/xxx.txt能访问到就算通过。这本质上就是在验证你的 IIS 站点是否真的对外可用。做这种验证时有三个要点文件必须放在站点根目录而不是子目录文件名和后缀必须一字不差有些平台给的是无后缀文件这时候要确认 IIS 的 MIME 配置不会拦它无后缀文件一般走默认的application/octet-stream能访问即可验证期间别改绑定或重启服务否则验证程序可能刚好在切换瞬间抓取失败。4.4 防火墙与局域网、外网访问的验证顺序站点在服务器本机能访问之后别急着告诉别人部署好了按这个顺序逐层验证本机回环http://localhost:端口通不过就是 IIS 配置问题。本机内网 IPhttp://192.168.x.x:端口这一步不通通常是站点绑定里 IP 限定了127.0.0.1改成全部未分配。局域网另一台机器这一步不通八成是 Windows 防火墙没放行端口。通过域名访问这一步不通检查 DNS 解析、云服务器安全组、以及主机头是否正确。外网访问如果是云服务器重点检查安全组规则和是否有公网 IP / 端口映射。这五层顺序千万别跳。我见过太多人在外网访问不了上折腾半天最后发现服务器本机都访问不了问题从头到尾都在 IIS 配置里。从内到外逐层排除能把问题范围快速缩小到一个层面比漫无目的地换配置高效得多。5. 部署 ASP.NET 站点.NET 8 在 IIS 功能列表里找不到是怎么回事5.1 ASP.NET Core 与经典 ASP.NET 的托管差别这是很多人第一次接触 .NET 8 加 IIS 时的困惑打开启用或关闭 Windows 功能IIS 下面的应用程序开发功能里只有ASP.NET 4.x、ASP.NET这些老选项根本找不到 .NET 8 的影子。原因很明确.NET 8 属于 .NET旧称 .NET Core体系跟 .NET Framework 是两套完全独立的运行时。IIS 的 Windows 功能里集成的是 .NET Framework从 4.8 之后就基本停止大版本演进了。.NET 8 的运行时和 ASP.NET Core 运行时都需要单独安装。那么 IIS 是怎么跑 .NET 8 站点的靠一个叫ASP.NET Core ModuleANCM的 IIS 原生模块。这个模块的职责是接收 IIS 转过来的请求启动并管理你的 .NET 8 应用进程dotnet xxx.dll然后把请求转发给它进程内托管模式或者通过端口转发进程外托管模式。所以部署 .NET 8 站点的正确顺序是先装 IIS包括 Web 管理工具和静态内容这些基础项再装 .NET 8 的Hosting Bundle注意不是只装 Runtime一定要是 Hosting Bundle它才会把 ANCM 一起装上建站点、建应用程序池选无托管代码iisreset或者重启一下 IIS让 ANCM 模块生效。5.2 Hosting Bundle 安装与 AspNetCoreModuleV2 的验证Hosting Bundle 的安装包名字类似dotnet-hosting-8.0.x-win.exe装完之后做两个验证。第一个确认运行时装上了dotnet --list-runtimes输出里应该能看到Microsoft.AspNetCore.App 8.0.x和Microsoft.NETCore.App 8.0.x。如果只有前者没有后者说明装的是 ASP.NET Core Runtime 而不是 Hosting BundleIIS 那边会起不来。第二个确认 ANCM 模块注册到了 IISC:\Windows\System32\inetsrv\appcmd list modules | findstr AspNetCore能看到AspNetCoreModuleV2才算成功。看不到的话多半是安装顺序反了——Hosting Bundle 装的时候找不到 IIS 就不会注册模块。这时候重装一遍 Hosting Bundle 就行不用卸 IIS。站点的web.config由发布工具自动生成长这样configuration system.webServer handlers add nameaspNetCore path* verb* modulesAspNetCoreModuleV2 resourceTypeUnspecified / /handlers aspNetCore processPathdotnet arguments.\MyApp.dll stdoutLogEnabledfalse stdoutLogFile.\logs\stdout hostingModelinprocess / /system.webServer /configurationhostingModel有两个值inprocess默认性能好应用跑在 IIS 工作进程内部和outofprocess应用作为独立进程跑IIS 通过端口转发。除非有特殊理由一律用inprocess。出问题需要排查时把stdoutLogEnabled改成true日志会写到logs\stdout目录这是定位应用启动失败最有效的手段。注意一点启动日志目录必须先存在否则日志写不出来你打开文件发现是空的会误以为是应用没报错。手动建一下mkdir D:\sites\myapp\logs5.3 500.19 / 500.30 / 502.5 三个高频错误的定位方法.NET 8 站点部署失败绝大多数时候遇到的是这三个状态码之一含义完全不同状态码含义最常见的根因500.19配置错误web.config 里用了 IIS 不认识的节比如 aspNetCore说明 ANCM 没装或没注册500.30应用启动失败代码异常、依赖缺失、连接串错误要去 stdout 日志看502.5进程启动失败dotnet 运行时找不到或者 dll 路径写错了503服务不可用应用程序池被禁用或没启动先查池状态500.19 是最容易误判的。因为它的错误信息会很长一堆 XML 行号和此配置节未在此路径上锁定之类的描述看着像配置文件语法错误其实核心信息是IIS 不认识 aspNetCore 这个节。遇到 500.19 先做一件事确认 Hosting Bundle 装了没有appcmd list modules里有没有AspNetCoreModuleV2。500.30 就必须看日志了。把stdoutLogEnabled打开重启应用池访问一次然后去看logs\stdout目录下生成的日志文件。里面会直接打印应用启动时的异常堆栈比在浏览器里猜快一百倍。我也建议同时看事件查看器的Windows 日志 → 应用程序IIS 会把一些宿主层面的错误写在那里。502.5 的典型场景是发布时选错了目标运行时。比如发布配置选了win-x64的自包含模式但复制到服务器上时漏了dotnet相关的文件或者用了dotnet MyApp.dll但 dll 文件名和 web.config 里写的不一致。核对一下web.config里的arguments指向的文件在磁盘上是否真实存在基本就能定位。5.4 经典 ASP.NET 4.x 别忘了 aspnet_regiis如果你的站点是老的 ASP.NET WebForm 或者 MVC 5走的是 .NET Framework 4.x那就得回到Windows 功能里把ASP.NET 4.x和ISAPI 扩展勾上。装完之后通常还要注册一下C:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet_regiis.exe -i不过要注意在比较新的 Windows 版本上aspnet_regiis -i已经被标记为不推荐使用因为 IIS 装了 .NET 功能之后一般会自动注册好。所以正确顺序是先装 IIS 的 .NET 相关功能再检查站点能不能跑跑不起来再考虑用dism重新启用功能而不是上来就敲aspnet_regiis。另外经典 ASP.NET 站点的应用程序池CLR 版本要选v4.0管道模式选集成。如果站点里有老式的 ISAPI 组件或者自定义 HTTP 模块可能需要切到经典模式但这是个兜底选项不是首选。6. 应用程序池权限设置失败 0x80005000的完整排查链路6.1 先把报错场景还原清楚这个报错我在域环境的内网服务器上遇到过两次每次都挺费时间所以单独拉一节讲透。完整报错通常是这样的在 IIS 管理器里选中应用程序池 → 高级设置 → 进程模型 → 标识 → 选自定义账户 → 填账号密码 → 确定 → 弹出提示应用程序池权限设置失败请手动为其设置 LocalSystem 权限 未知错误 (0x80005000)注意这句话的含义IIS 想通过 ADSIActive Directory Service Interfaces去给应用程序池绑定一个身份但是这次绑定操作失败了。IIS 没能完成配置所以给了个兜底建议——你手动给它设为 LocalSystem 吧但这只是个绕行方案不是修复方案。0x80005000这个错误码在 Windows 的错误体系里对应的是无效的 ADsPath / 名称解析失败这一类。翻译成人话就是IIS 拿着你给的这个账户名或者它自己拼出来的账户路径在实际的系统或域里找不到对应的对象。6.2 从服务状态查到账户解析按这个顺序排查从便宜到贵第一步先确认服务是活的。这个报错有时候只是因为 WAS 服务处于停止或半死不活的状态sc query WAS sc query W3SVC两个都应该是RUNNING。不是的话先启动再重试一次设置。我遇到的一次就是 WAS 服务卡住了重启之后同样的操作一次成功。第二步确认你填的账户名格式是对的。这是最常见的坑。自定义账户的填写规则本地账户机器名\用户名或者.\用户名不能只写用户名也不能写 IP。域账户域名\用户名或者用户名域名。只写一个administratorIIS 在某些环境下拼不出正确的路径就会返回 0x80005000。第三步确认机器名和 DNS 解析。0x80005000 的深层原因经常是计算机名解析不了。检查两件事# 当前计算机名 hostname # 名称解析是否正常 nslookup 当前计算机名 ping 当前计算机名如果ping自己的机器名都不通那就是 hosts 或者 DNS 的问题。尤其是改过计算机名的服务器域里还记着旧名字ADSI 用新名字查域对象就查不到。处理方式是补一条 hosts 记录或者重建机器账户退出域再加回域。第四步域环境检查信任关系。如果是加域的机器用这条命令看一下域信任状态nltest /sc_query:域名返回的信任状态异常或者域控不可达都会导致 ADSI 绑定失败。这种情况通常不是 IIS 的问题得找负责域环境的人一起看。第五步考虑是不是真的需要自定义账户。说实话90% 的场景下你根本不需要自定义账户。除非站点需要访问网络共享、需要访问另一个域的资源、或者需要连数据库用 Windows 身份验证否则直接用默认的ApplicationPoolIdentity就好根本不碰这个设置项也就不会遇到这个报错。6.3 修复方案与验证按严重程度给出三套方案场景处理方式只是想让它跑起来标识保持 ApplicationPoolIdentity给站点目录授权虚拟账户问题消失确实需要自定义账户本地账户用机器名\用户名格式重填先确认用户名和密码正确域环境且解析异常修 hosts / DNS或退出域重新加域再重试如果非要先让站点跑起来应急可以按报错的建议临时用LocalSystemC:\Windows\System32\inetsrv\appcmd set apppool demo /processModel.identityType:LocalSystem然后立刻iisreset。但这只是应急别留在生产环境。LocalSystem 权限过大等于把整台机器的控制权交给了站点进程一旦站点有上传漏洞或者代码执行漏洞攻击面会大得离谱。用完记得改回ApplicationPoolIdentity。验证是否修好最直接的方法有两条在 IIS 管理器里重新做一次那个设置操作不再弹错就说明通了直接访问站点能正常返回内容就说明权限链路是通的。6.4 顺带说说 applicationHost.config 相关报错热词里还有一个报错和这个沾边执行此操作时出错文件名: c:\windows\system32\inetsrv\config\applicationHost.config这个文件是 IIS 的全局配置文件所有站点、应用程序池、模块、绑定的定义都写在这里面。它出问题症状通常是整个 IIS 管理器都打不开或者一操作就报错。常见原因和处理方式文件被别的进程占用了比如你正在用记事本打开它或者某个杀毒软件、编辑器锁着它。关掉编辑器再操作。文件损坏被不完整的写入或者意外断电搞坏。这时候别直接编辑它——正确做法是用备份还原appcmd restore backup一条命令解决。权限被改动了这个文件默认只有 Administrators 和 SYSTEM 有完全控制。如果被误改用icacls恢复 ACL。32 位与 64 位混淆IIS 管理器在某些场景下会去读SysWOW64\inetsrv\config下的同名文件32 位版本。如果你在 64 位的system32里改了配置用 32 位组件跑的应用读的是另一个文件就会看到我明明改了但不生效。改配置统一用 IIS 管理器或者appcmd它们会处理位数的差异手改文件容易踩这个坑。制作一份可以随时回滚的配置备份下节详细说。7. 配置备份与还原改配置之前先留一条后路7.1 appcmd 备份与还原IIS 自带一个配置备份机制备份的是整个 IIS 配置站点、池、模块、绑定不包括站点文件内容。命令就这么几条# 手工创建一份命名备份 C:\Windows\System32\inetsrv\appcmd add backup before_migration_20250601 # 列出所有备份 C:\Windows\System32\inetsrv\appcmd list backups # 还原到某个指定备份 C:\Windows\System32\inetsrv\appcmd restore backup before_migration_20250601另外IIS 默认每天会自动生成一份配置备份存在C:\inetpub\history下面带时间戳。这个自动备份在出大事的时候能救命比如你手滑删了一个关键绑定或者改崩了模块配置去这个目录找一个时间最近的拷回去就行。我的习惯是任何一次涉及站点、绑定、应用程序池、模块的改动之前先敲一遍appcmd add backup用日期加改动内容的命名方式比如20250601_before_ssl_binding。这条命令零点几秒就跑完了收益却是无限的。相比那些改错了只能重装 IIS的惨剧这个成本几乎为零。顺便说一下如果你想单独导出配置的一部分可以用C:\Windows\System32\inetsrv\appcmd list config /section:system.applicationHost/sites /xml sites.xml这样能把所有站点定义导出成 XML方便对比两套环境之间的差异。排查测试环境能跑、生产环境不能跑这类问题时把两边的 XML diff 一下差异一目了然。7.2 导出站点与应用池到新机器换机器或者做环境迁移时靠手工在图形界面里一个个点是很容易错的。.NET 站点的迁移有个原则能用发布工具就绝不手工拷文件。Visual Studio 的发布功能可以直接把站点发到目标服务器的文件夹或者 Web Deploy 端点web.config会一起生成比你自己拼文件靠谱得多。如果是纯静态站点那简单把整个目录拷过去然后在新机器上重建站点# 1. 建应用池 C:\Windows\System32\inetsrv\appcmd add apppool /name:demo /managedRuntimeVersion: /managedPipelineMode:Integrated # 2. 建站点 C:\Windows\System32\inetsrv\appcmd add site /name:demo /physicalPath:D:\sites\demo /bindings:http/*:80:demo.example.com # 3. 绑定应用池 C:\Windows\System32\inetsrv\appcmd set app demo/ /applicationPool:demo # 4. 授权目录 icacls D:\sites\demo /grant IIS AppPool\demo:(OI)(CI)(RX) /T这四步下来一个站点在新机器上就成型了比点鼠标快而且可以写进部署脚本重复执行。迁移时的几个注意事项目标机器的 IIS 版本要匹配低版本可能不支持高版本用到的配置节原机器上如果有自定义的 HTTP 模块或者 ISAPI 筛选器新机器上也得装否则配置还原了但请求处理链路断了HTTPS 证书的私钥别忘了导出——证书本身可以重新申请但私钥要是丢了配置里的绑定就会失效站点直接起不来。7.3 我踩过的几个配置坑最后分享几个实际踩过的坑都属于文档里不写但真会出事的类型。第一个坑改绑定的时候顺手删了原来的绑定。我想加一个 8080 的绑定点了添加但选成了编辑把原来的 80 覆盖掉了站点瞬间对所有人不可访问。后来靠appcmd list backups找到最近的自动备份才恢复。从那以后我改绑定之前必先备份。第二个坑给站点目录授权时用错了路径。站点路径写的是D:\sites\demo但我icacls的时候手滑写成了D:\site\demo少了个 s命令还是执行成功了——因为默认目录不存在时会创建目录并授权。结果站点目录权限一点没变访问还是 403。icacls执行完一定要手动确认一遍用右键属性 → 安全 → 高级看有没有IIS AppPool\demo这条。第三个坑在经典模式下配 URL 重写规则规则明明写对了就是不生效。查了半天发现经典模式下 URL 重写模块没被加载。切回集成模式问题立刻消失。这也是为什么我一直建议新项目一律用集成模式——省下来的时间比省下来的那点兼容性值钱多了。这几年我配 IIS 最深的体会是它本身并不复杂复杂的是默认值和你的预期不一致。静态内容默认不装、index.html 默认不在默认文档列表、应用程序池默认会闲置回收、快速故障保护默认会禁池、局域网匿名访问默认走应用池虚拟账户——每一项单拎出来都很合理但组合在一起就是新手的一连串问号。把这几个默认值挨个确认一遍IIS 的部署流程基本不会再有意外。如果你手头正好有一台闲置的 Windows 机器按上面这几节的顺序从头走一遍从装功能到建站点到配权限走完一次之后这套东西就真正变成你自己的了。
返回列表