把一台没连外网的外网 Windows Server 装好 IIS,打开浏览器访问 localhost,外网看到那个默认的外网 IIS 欢迎页——这事儿本身没难度。真正让人抓狂的外网是后面:你要在这台机器上跑一个 Web 应用,但没法用 Web Platform Installer 在线拉组件,外网没法 nuget restore,外网甚至连 Google 都搜不了。外网我上个月就在一个军工单位的外网机房里干了整整三天这种事,下面是外网我踩出来的路。
先说一个反直觉的外网事实:IIS 的核心功能根本不依赖外网。Windows Server 的外网安装镜像里已经包含了 IIS 的全部角色文件,你只需要在「服务器管理器」里勾选对应角色即可。外网问题出在依赖链上——ASP.NET Core Runtime、外网URL Rewrite 模块、外网ARR 反向代理、外网PHP、Node.js,这些东西默认不在系统镜像里,而它们的官方安装包又习惯性地从网上拽东西。
我的做法是找一台能上网的机器,把需要的 MSI 或 EXE 安装包全部下载下来。微软的下载中心有个坑:很多安装包是 Web Installer,双击后它才去下载真正的 payload。你得找 Offline Installer 或 Standalone 版本。比如 .NET Framework 4.8 的离线包大概 120MB,ASP.NET Core Runtime 的 Hosting Bundle 大约 50MB。URL Rewrite 2.0 和 ARR 3.0 在微软 IIS 官网有直接的 MSI 链接,这两个加起来不到 10MB。
下载完拷进 U 盘,插到内网机器上按顺序装。注意顺序:先装 .NET Framework,再装 IIS 角色,最后装 URL Rewrite 和 ARR。顺序错了会出现模块注册不上的情况,我遇到过 URL Rewrite 装完在 IIS 管理器里死活不显示图标,卸载重装才解决。
如果你面对的是 Server Core 或者图形界面被裁剪过的系统,可以用 DISM 命令行离线启用 IIS。把 Windows Server 的 install.wim 挂载到某个目录,然后执行:
dism /online /enable-feature /featurename:IIS-WebServerRole /all /source:D:\sources\sxs 这个 /source 参数指向镜像里的 sxs 文件夹,DISM 会从那里提取 IIS 的组件文件。没有这个参数,DISM 会尝试联网下载,然后失败。我见过有人卡在这一步以为是权限问题,其实是没指定源路径。
假设你要部署一个 ASP.NET Core 应用。发布的时候用 dotnet publish -c Release -r win-x64 --self-contained,这样会把运行时一起打包进去,目标机器上连 ASP.NET Core Runtime 都不用装。代价是发布目录会大很多,大概 80MB 起步,但省去了在内网装运行时的麻烦。
如果应用依赖 NuGet 包,在能上网的机器上先 dotnet restore,然后把整个 ~/.nuget/packages 目录拷过去,或者用 nuget locals all -list 找到缓存路径整个搬。更干净的做法是在项目里配一个本地 NuGet 源,把 .nupkg 文件全放进去。
Node.js 应用同理。npm 的离线方案是 npm pack 把所有依赖打成 tgz,或者用 npm install --offline 配合本地 cache。但实际操作中 npm 的离线体验远不如 NuGet,我最后是直接在联网机器上 npm install 完,把整个 node_modules 目录拷过去的。
内网机器做 HTTPS 需要证书。没有外网就没法用 Let's Encrypt 自动签发。我的做法是在内网自建一个 CA,用 OpenSSL 签一个服务器证书,然后把这个 CA 的根证书导入到所有需要访问的客户端的「受信任的根证书颁发机构」里。IIS 里绑定证书的时候选那个 .pfx 文件,输入导出时设的密码就行。
有个细节:Chrome 对自签名证书的容忍度越来越低,如果证书的 SAN 里没有写 IP 地址或主机名,浏览器会直接拦截。签证书的时候务必把 CN 和 SAN 都填对。
整个过程最耗时间的不是技术本身,而是找安装包和确认版本兼容性。我的建议是提前在联网环境里把所有安装包和依赖整理成一个目录,写一个 install.bat 按顺序静默安装,到了内网机器上直接跑脚本。这样即使面对十台机器,也能在半小时内全部搞定。