ARTICLE DETAIL

资讯详情

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

WinSW在Win7上失败真相-实测与修复

WinSW在Win7上失败真相-实测与修复 nginx 做成 Windows 服务Win8 稳跑两年Win7 三天两头起不来都说 WinSW 不支持 Win7 —— 拆开 exe 和日志后真相是另一个摘要同一套 nginx 服务化方案在 Win8 上稳定跑了两年零失败换到 Win7 就频繁起不来。网上流传的解释是WinSW 不支持 Win7。本文拆开 exe 的 PE 头、翻完 WinSW 的 wrapper.log、对照官方 XML 规范后给出一个恰好相反的结论WinSW 支持 Win7而且现场那个 exe 就是 Win7 能跑的那个构建。真正坑人的是下错构建 / 缺运行时 / 一个被抄了十年的 XML 陷阱。一、现场两台机器两种命运甲方环境里有两台 Windows 加 nginx用的都是WinSW 改名成nginx-service.exe 一个同名 XML 配置这套流网上流传最广的那套教程机器 A机器 B系统Windows 8Windows 7 SP1 64 位nginx1.21.6D:\nginx-1.21.61.22.1E:\nginx-1.22.1表现服务自启一直正常频繁起不来手动双击 exe 还会弹框Win7 上双击那个nginx-service.exe弹的是这个Windows 服务启动失败无法从命令行或调试程序启动服务。必须首先安装 Windows 服务使用 installutil.exe然后用 ServerExplorer、Windows 服务管理工具或 NET START 命令启动它。这台机器的系统信息 —— Win7 专业版 SP1 64 位一台 2011 年前后的台式机 —— 见./images/02-win7-system-info.pngFramework64下有v4.0.30319说明 .NET 4.x 是装了的见./images/03-framework64-dir.png。于是WinSW 不支持 Win7这个说法就在项目里传开了。但它错了而且错得挺有代表性。二、先把WinSW 不支持 Win7这句拆开2.1 官方声明WinSW 明确支持 Win7WinSWv2.12.0稳定版2023-01的 README 原文WinSW offers executables for .NET Framework 2.0, 4.0 and 4.6.1.It can run on Windows platforms which have these versions of .NET Framework installed.For systems without .NET Framework, the project provides native 64-bit and 32-bit executables which are based on.NET Core 3.1.结论.NET Framework 2.0 / 4.0 / 4.6.1 三个构建只要系统装了对应运行时就能跑。而 .NET Framework 4.6.1 的官方系统要求是可在 Windows 7 SP1 和 Windows Server 2008 R2 SP1 上安装。再看 WinSW3.x默认分支预发布的 READMEWinSW 3 can run on Windows platforms with.NET Framework 4.6.1 or laterversions installed.For systems without .NET Framework, the project provides native 64-bit and 32-bit executables based on.NET 7..NET 7 system requirements:Supported since Windows 10, version 1607, Windows Server (Core) 2012 R2 and Nano Server, version 1809.看清楚这里的区别 ——同一个 release 页面上的两个 exe最低系统要求差了十万八千里下一节展开。2.2 实测现场那个 exe恰恰就是 Win7 能跑的那个我把现场目录截图里的文件尺寸和 WinSW v2.12.0 官方 release 的资产清单做了比对尺寸数据来自 GitHub Releases API文件名里的 “833 KB” 就是指纹。Windows 资源管理器显示的 833 KB 852,480 字节 ÷ 1024 832.5 KB —— 和WinSW.NET4.exe一个字节都不差。我把这个 exe 下下来拆了 PE 头和导入表自写 Python 解析OptionalHeader Import Directory检查项WinSW.NET4.exev2.12.0结论文件大小852,480 字节 832.5 KB → 资源管理器显示 833 KB与现场 exe 完全一致架构x86 (0x014c)32 位 .NET 程序跑在 64 位系统上没问题PE SubsystemVersion4.0Win7 6.1远低于 Win7加载器不会拒绝是否托管程序是CLR 目录存在内容其实是 IL 代码不是原生机器码导入 DLL只有mscoree.dll这是 .NET Framework 的引导壳。它自己不实现任何逻辑全靠系统里的 .NET Framework 运行时把代码跑起来内嵌 CLR 版本串v4.0.30319目标运行时 .NET Framework 4.0也就是说现场这份 833 KB 的 nginx-service.exe 就是 WinSW 的 .NET Framework 4.0 构建 —— 对 Win7 最友好的那个版本。它不需要 .NET Core、不需要 .NET 7、PE 头也不是仅支持 Win10的设定。2.3 日志实证它在 Win8 上跑了两年一次没失败拿到机器 AWin8的nginx-service.wrapper.log后一切都对上了节选2023-04-25 23:51:27,093 INFO - Installing service nginx (nginx)... 2023-04-25 23:51:27,116 INFO - Service nginx (nginx) was installed successfully. 2023-04-25 23:52:51,056 DEBUG - Starting WinSW in service mode 2023-04-25 23:52:51,102 INFO - Starting D:\nginx-1.21.6\nginx.exe 2023-04-25 23:52:51,136 INFO - Started process 12524 ... 2023-10-02 10:11:26,333 INFO - Started process 6668 2024-07-04 00:47:35,003 INFO - Stopping nginx 2024-07-04 00:47:35,004 DEBUG - ProcessKill 6668 2024-07-04 00:47:35,026 DEBUG - Process 7064 canceled with code -1073741510. ... 2025-08-20 18:35:20,220 INFO - Started process 6332逐条读出来的结论日志现象含义9 次Starting WinSW in service mode→ 9 次Started process NNNN零失败、零异常退出服务一旦被 SCM 拉起nginx 都能在 0.5–1.8 秒内正常启动。nginx 本体、路径、工作目录、80 端口全部没问题启动条目稀疏2023-10-02、2024-08-18、2024-10-29、2025-08-20 各一次这些正是开机自启留下的记录 → 自启在这两年里一直是有效的4 次停止全是ProcessKill直杀worker 子进程canceled with code -10737415100xC000013A服务从来没被优雅停止过原因见第五节这是个配置陷阱不是 Win7 的锅2024-07-04 出现 8 条密集停/起间隔约 2 分钟人工调配置后重启服务可忽略所以不是 WinSW 不支持 Win7也不是 nginx 起不来。问题要么在选了哪个 exe要么在配置和服务注册层要么就是 Win7 特有的依赖缺失 —— 而 Win7 那台现在缺的恰恰就是一份能说话的日志。三、WinSW 在 Win7 上真正会失败的 5 类原因按命中概率 × 排查成本排序逐条给判断方法。① 下错了构建最常见也最容易避免WinSW 每个 release 里都有 5 个 exe运行前提完全不同v2.12.0 实测尺寸构建大小运行时Win7 SP1 能不能跑WinSW.NET2.exe860,672 B (841 KB).NET Framework 2.0/3.5✅ Win7 自带 3.5.1WinSW.NET4.exe852,480 B (833 KB).NET Framework 4.0✅ 需装 .NET 4.x现场用的就是这个WinSW.NET461.exe655,872 B (641 KB).NET Framework 4.6.1✅ 需装 4.6.1且 Win7 要先打 SHA-2 补丁WinSW-x86.exe17,253,337 B (≈16.5 MB)自包含v2 是 .NET Core 3.1⚠️ 需 UCRTKB2999226WinSW-x64.exe18,243,033 B (≈17.4 MB)自包含v2 是 .NET Core 3.1v3 是 .NET 7⚠️ v2 勉强可需 UCRTv3 必失败.NET 7 只支持 Win10 1607网上大量WinSW 在 Win7 上跑不起来的帖子根源就在这GitHub Releases 页面默认展示的是最新的 3.x 预发布版而它那个 18 MB 的WinSW-x64.exe是基于 .NET 7 的官方只支持 Windows 10 1607。照着最新版下在 Win7 上必然失败。正确做法是回到2.12.0 稳定版选WinSW.NET4.exe833 KB。3 秒判断你手上是哪个dir D:\nginx-1.21.6\nginx-service.exe对照上表的字节数即可。833 KB 那一档就是 .NET Framework 4.0 构建Win7 可用。② .NET Framework 缺失或版本不足.NET Framework 构建的 WinSW 是纯托管程序实测导入表里只有mscoree.dll—— 目标机没装对应版本的 .NET Framework它连第一行代码都执行不了。三个硬事实干净的 Win7 SP1 只自带 .NET Framework 3.5.1Framework64 下只有 v2.0.50727 / v3.0 / v3.5有v4.0.30319这个目录不等于装了 .NET 4.x.NET 4.5 是就地升级目录名仍叫 v4.0.30319。正确判断HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full下的Release值或dir C:\Windows\Microsoft.NET\Framework64\v4.0.30319\里有没有大量 dll干净系统里这个目录基本是空的Win7 上装 .NET Framework4.6.1 及以上必须先装SHA-2 代码签名支持补丁KB4474419 KB4490628否则安装程序直接报错 —— 这是 Win7 特有的坎Win8 及以后没这个问题。③ 架构选错x86 版跑在 64 位 Windows 上一般没问题现场就是 x86 版跑在 64 位 Win7/Win8 上反过来则必失败64 位版丢到 32 位系统上会报不是有效的 Win32 应用程序0xC000007B。④ 杀软/安全软件拦截国内现场的高频项。WinSW 要写服务注册表、要创建子进程、要常驻 —— 很容易被拦。表现包括install报错、服务装上但起不来、exe 被杀软修复后体积变了。如果 exe 的字节数和官方对不上先怀疑这个。⑤ 与系统版本无关的配置层问题最容易被误算到系统不支持头上启动类型没写成自动sc qc nginx看START_TYPE2AUTO_START / 3DEMAND_START / 4DISABLED服务根本没装成功sc query nginx报 1060XML 里id变了但服务没重装服务账户默认 LocalSystem一般没问题改成域账号后密码过期 → 事件 7000 1069开机时 80 端口被抢http.sys、IIS、Skype、某些安全软件都会占Win7 上这个特别常见→ 事件 7000/7009/7031/7034依赖顺序nginx 反代的后端没起来导致启动慢被 SCM 判超时30 秒→ 事件 7009。四、Win7 那台机器 B现在该抓什么证据只要三条命令就能把它分流到上面五类原因里的某一条REM 1) 服务注册状态看存不存在、启动类型对不对 sc query nginx sc qc nginx REM 2) 日志里有没有最近这次开机的痕迹把日期换成你最后一次重启的年份/月份 findstr /c:2026 E:\nginx-1.22.1\nginx-service.wrapper.log findstr /c:2025 E:\nginx-1.22.1\nginx-service.wrapper.log REM 3) 事件查看器里按服务名过滤导出为文本方便回传 wevtutil qe System /q:*[System[Provider[NameService Control Manager]]] /c:40 /rd:true /f:text | findstr /i nginx 7000 7009 7031 7034分流表findstr结果sc qc结果结论有当次开机记录且Started process之后无异常START_TYPE2服务起来了 → 问题在起来了但端口/后端不通查 nginx 日志与端口无当次开机记录START_TYPE3 / 4SCM 根本没启动它→ 改自动启动即可本文方案 A无记录报 1060/1056服务不存在服务注册丢了 → 重新install有Starting WinSW但没有Started process任意WinSW 起来了但拉不起 nginx → 看.err.log/ XML 路径 / 权限另外两个小细节值得同时确认机器 B 的目录里到底有没有nginx-service.xml弹窗提到installutil.exe说明那个nginx-service.exe是用.NETServiceBase写的服务程序这是ServiceBase.Run的标准报错文案WinSW 双击时不会这么说。如果机器 B 目录里只有 exe 和xxx.exe.config、没有 XML那它用的就是另一套包装器修法完全不同往下看第五节末尾。nginx.pid有没有残留dir E:\nginx-1.22.1\logs\nginx.pid—— 强杀过的 nginx 会留下它。五、XML 里那个被抄了十年的陷阱stopexecutable这一条与 Win7/Win8 无关但必须说 —— 因为它看起来像配好了实际从未生效属于典型的沉默故障。网上那套教程模板里写的是stopexecutableD:\nginx-1.21.6\nginx.exe -s stop/stopexecutable对照官方v2.12.0的 XML 规范doc/xmlConfigFile.mdstopargument/stopexecutableHowever, ifstopargumentselement is present, winsw will instead launch another process ofexecutable(orstopexecutableif that’s specified) with the specified arguments…When you use thestoparguments, you must usestartargumentsinstead ofarguments.stopexecutable只接受可执行文件路径停止参数必须写在stoparguments复数、单个元素里。模板把-s stop拼进路径后WinSW 会去找一个字面叫nginx.exe -s stop的文件 —— 找不到于是静默退回强杀。这就是机器 A 日志里只有ProcessKill、从来没有优雅停止的原因。正确写法executableD:\nginx-1.21.6\nginx.exe/executableworkingdirectoryD:\nginx-1.21.6/workingdirectorystopexecutableD:\nginx-1.21.6\nginx.exe/stopexecutablestoparguments-s stop/stoparguments顺手记住三条 WinSW 的官方默认值/语义能省很多猜startmode默认就是Automatic可选 Boot / System / Automatic / Manual所以开机不自启通常不是漏了这一项而是服务压根没被 SCM 拉到停止流程stoptimeout默认为 15 秒先尝试 CtrlC超时才TerminateProcess配好stoparguments后WinSW 会改为先跑停止命令并等它退出这才是优雅停止失败恢复用onfailure actionrestart delay10 sec/resetfailure1 hour/resetfailure等价于sc failure但写在 XML 里更不容易丢。关于机器 B 那个 installutil 弹窗「必须首先安装 Windows 服务使用 installutil.exe」是.NETServiceBase程序被直接运行时的标准提示 —— 只有服务 exe在服务模式下由 SCM 启动ServiceBase.Run才会成功。所以如果双击时弹它→ 正常现象不代表 exe 坏了但说明这台机器的服务很可能从来没被正确安装成 Windows 服务这本身就能解释频繁起不来如果开机时自动弹它→ 说明有人把这个 exe 塞进了「启动」文件夹或计划任务里 —— 这是交付雷区nginx 会以登录用户身份运行还会和服务方式双开冲突。请务必检查msconfig的启动项和任务计划程序。六、我给你的三个现场文件怎么用、能修什么这一节是实操部分。三个文件都是纯 ASCII CRLF 换行Win7 的 GBK 控制台不会乱码。6.1check-winsw-evidence.bat—— 只读取证先跑这个双击即可需要管理员。它不改任何东西在脚本同目录生成winsw-evidence.txt一次收齐 13 项现场信息项为什么需要sc qc/sc query nginx服务存不存在、启动类型是 2/3/4 —— 直击开机不自启wmic os get lastbootuptime最后开机时间—— 用来和日志时间线对账wrapper 日志全文 findstr 2026过滤 命中计数判断这次开机 WinSW 到底有没有被拉起来nginx-service.xml全文检查stopexecutable陷阱、路径、服务名tasklist/netstat :80 :8080nginx 是否在跑、80 端口被谁占logs\nginx.pid是否存在判断有没有强杀残留nginx.exe -t配置语法校验不影响线上只是解析nssm.exe 是否存在最终确认包装器归属避免再套错命令为什么坚持先取证、后修复如果把 nginx 手动启动一次服务启动失败的状态就被冲掉了事件日志和日志时间线的线索也随之消失。远程排障最怕的就是这个。6.2nginx-service.fixed.xml—— 修好配置里的三个坑在原始 XML 基础上改了四处都写了注释stopexecutable改为纯路径补上stoparguments-s stop/stoparguments补workingdirectory—— 让 nginx 无论被谁启动conf/、logs/都相对自己的目录解析等价于 nssm 的AppDirectory这是 nginx 服务化最高频的坑startmodeAutomatic/startmode显式写出depend依赖项留好位置MySQL / Tomcat 的服务名用sc query state all | findstr /i mysql tomcat查出来后取消注释。用法备份原文件 → 用这份内容覆盖 → 保持文件名仍是nginx-service.xml→nginx-service.exe restart或重启机器。文件必须和 exe 同名同目录这是 WinSW 发现配置的方式。6.3fix-nginx-winsw.bat—— 一键修复改配置需管理员默认目标D:\nginx-1.21.6改顶部NGINX_DIR即可。顺序是[0] 打印当前状态 sc query / sc qc [1] 打印 wrapper 日志 ← 修复前先留证据 [2] nginx-service.exe uninstall → install ← 用 WinSW 自己的命令重装服务 [3] sc config nginx start auto sc failure ← Win7 上兜底防止 install 写入不生效 [4] net start 状态验证 [5] 80 端口监听检查第 3 步为什么要sc兜底startmode默认虽然是 Automatic但服务属性写进去了和启动类型真的是自动是两件事用sc qc复核一遍最稳注意start后面必须有空格这是sc的老规矩。跑完必须重启机器复验sc query nginxSTATE : 4 RUNNING—— 只验证手动能启动毫无意义。七、三句话总结WinSW 不支持 Win7是误传。官方三个 .NET Framework 构建都支持 Win7 SP1现场那个 833 KB 的nginx-service.exeWinSW.NET4.exe852,480 字节就是在 Win8 上跑了两年零失败的同一个构建。会翻车的是照着最新版下了 3.x 的 .NET 7 自包含构建17.4 MB这种选型错误。Win7 上要盯的是依赖而不是兼容性干净的 Win7 只有 .NET 3.5.1、装 4.6.1 要 SHA-2 补丁、自包含构建要 UCRTKB2999226、架构只能 x86←x64 不能反过来。别让配置悄悄失效。这次的stopexecutable就是看着配了、其实一直在强杀。判断标准很简单日志里有没有真的执行停止命令以及服务启动失败时有没有一份落盘的输出。最后一句留给同样在做交付的同学开机不启动这类问题先别急着换组件先让日志说话。一份wrapper.log能同时否掉好几个错误方向比换三套方案都快。本文所有二进制尺寸、PE 头、SubsystemVersion、导入表数据均为实测WinSW v2.12.0 取自 GitHub Releasesnssm 2.24 取自 Chocolatey 官方包WinSW 的 XML 语义均引用官方 v2.12.0 文档原文。
返回列表