ARTICLE DETAIL

资讯详情

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

NSSM 2.10 实战:把 exe 封装成 Windows 服务,实现开机自启与崩溃重启

NSSM 2.10 实战:把 exe 封装成 Windows 服务,实现开机自启与崩溃重启 简介这份压缩包提供 NSSM 2.10 在 Windows 平台上的完整发行资源面向需要把任意可执行程序或脚本注册为 Windows 服务的开发与运维人员用于解决普通程序无法随系统自动启动、无人值守运行的问题。NSSMNon-Sucking Service Manager以轻量、可直观配置服务参数而著称支持设置服务名、启动参数、依赖关系与日志输出能替代系统自带服务管理工具处理非标准启动问题并已适配 Windows 10 环境。包内共 24 个文件其中 win32 与 win64 目录各含一个可直接运行的 nssm.exe另外还有 7 个头文件和 6 个 C 源文件对应服务注册、事件记录、注册表操作等实现配套 .sln/.vcproj/.dsp 工程文件、README 与 ChangeLog 便于编译和查阅版本差异整体大小仅 158KB。目前已有 223 人浏览学习。解压后既能直接调用命令行或界面工具将应用封装为后台服务也能通过源码深入理解 Windows 服务管理机制适合服务自启、无人值守运行和故障诊断等场景。1. 在 win10 上把 exe 变成服务为什么绕不开 nssm-2.10NSSM 全称 Non-Sucking Service Managernssm-2.10 这个版本是很多运维手里一直留着的 Windows 服务封装工具 ZIP 包。它解决一个特别具体的痛点在 win10 上想把任意一个 exe、批处理或脚本变成开机自启、崩溃自动重启、日志有地方落的 Windows 服务靠任务计划程序和 sc.exe 都差点意思。NSSM 2.10 虽然版本老但在 win10 专业版和 22H2 上依然能正常注册服务配置入口直观服务一旦注册进服务管理器就和系统服务一样受 SCM服务控制管理器统一管理开机自启、依赖关系、恢复策略都能在图形界面里调。适合谁被 nginx、MySQL、Java 应用在 Windows 上开机自启问题折磨过的运维和开发以及所有想把手写脚本变成“真正的服务”的人。2. 选型NSSM 和 winsw、sc.exe 的边界在哪里在动手之前先把 Windows 下把程序变服务的四条路说清楚系统自带的 sc.exe、Windows Resource Kit 里的 srvany、winsw 和 NSSM。选错方案的代价不在安装那一刻而在后面投入使用时反复调不通。这一章把每个方案的边界捋一遍你就能理解为什么大家最后普遍落到 NSSM 上。2.1 sc.exe 只负责注册不负责把服务养活sc.exe 是 Windows 自带的能创建服务但它的能力边界很清楚把服务注册进去、设置启动类型、查询状态仅此而已。它不会帮你管理日志不会在进程崩溃后自动恢复也不太适合作为长期守护方案。常见做法是只拿它做最基础的注册和删除真正的守护逻辑交给 NSSM 这类封装工具。用 sc.exe 创建服务的命令长这样sc create MyService binPath C:\tools\app.exe --port 8080 start auto这条命令把 app.exe 注册成名为 MyService 的服务开机自启。注意 sc.exe 对格式非常挑剔binPath的等号后面必须有空格start auto也一样少一个空格命令就会报参数错误。把这个例子放在这里不是让你用它而是让你对比后面的 NSSM 用法sc.exe 创建的服务的 ImagePath 直接指向你的程序程序一旦崩了服务就停止没有任何恢复策略日志要么程序自己写文件要么你看不到任何输出。这对 nginx、MySQL 这类需要长时间跑的进程来说不够用。比 sc.exe 更老一点的还有 Windows Resource Kit 里的 srvany它能把任意程序注册为服务但同样没有日志重定向、没有进程守护、没有图形配置界面配置全靠改注册表现在已经很少有人在新项目里用了。如果你的同事提起 srvany把它当作一个历史方案就行不值得为此引入新的依赖。所以在 win10 环境下sc.exe 更适合做一次性注册工具不适合做长期守护方案。如果只是临时注册一个服务用 sc.exe 没问题如果这个程序是生产依赖后面迟早要换成 NSSM 或 winsw。2.2 winsw 和 NSSM 都托管程序差在配置方式和运维习惯winsw 是另一个流行方案很多人在“nginx 服务使用 winsw 还是 nssm”这个问题上纠结。winsw 的核心是 XML 配置把一个 exe 包在配置文件里然后安装成服务。它的优点是配置文件可以进版本库适合批量部署和自动化运维缺点是调试时改配置要改 XML、重装服务win10 上新手容易在 XML 格式上翻车。一个典型的 winsw 配置大概是这样的service idMyService/id nameMyService/name descriptionMy demo service/description executableC:\tools\app.exe/executable arguments--port 8080/arguments log moderoll-by-size sizeThreshold10240/sizeThreshold /log /service然后执行winsw install、winsw start。这套流程在纯命令行环境里非常干净但如果你的使用场景是“在 win10 服务器上手工装服务、时不时看日志、调参数”NSSM 的 nssm edit 图形界面会更顺手日志重定向、退出码策略、环境变量都能在窗口里直接改。我的判断是批量部署、有配置管理工具的团队用 winsw单机手工运维、需要经常调试的选 NSSM。两者都能把 nginx 这类程序托管成服务差别不在能力而在使用习惯。2.3 NSSM 2.10 的适用边界和反例NSSM 也不是万能的。它托管的是“一个可执行文件 参数 工作目录 环境变量”服务启动时由 NSSM 创建一个被托管进程并监控这个进程的退出码。以下三类场景不适合直接用 NSSM。第一类带图形界面的交互程序。NSSM 托管的服务运行在 Session 0服务会话普通 GUI 程序在服务会话里显示不出来窗口不会出现在你的桌面上程序可能启动后一直停在初始化界面。第二类自身会 fork 子进程并且主进程会提前退出的程序。NSSM 判断服务是否存活看的是你配置的那个启动进程主进程一旦正常退出NSSM 会认为服务结束不会继续等子进程。像某些 Java 启动器主进程拉起来 JVM 后就退出直接用 NSSM 托管的服务会反复重启。第三类需要多实例且每个实例配置差异很大的程序。NSSM 支持注册多个服务名但每个服务名的配置要单独维护服务多了以后注册表里的配置项会变得难管理这种情况更建议用容器或虚拟机托管。理解了这个边界后面的配置逻辑就顺了你只需要关心“NSSM 启动哪个进程、这个进程怎么退出、退出后怎么办”。至于进程内部怎么 workNSSM 不关心也不需要关心。3. 用 NSSM 2.10 在 win10 装服务的完整命令链这一章开始动手。假设场景是手头有一个 app.exe比如一个自己写的 Web 服务要在 win10 上跑成开机自启的服务。按下面的顺序走每一步都有对应的命令和检查方式。3.1 解压和路径准备32 位和 64 位别拿错nssm-2.10 的 ZIP 解压后里面一般有 win32 和 win64 两个目录分别对应 32 位和 64 位版本的 nssm.exe。win10 基本都是 64 位系统应该拿 win64 目录下的 nssm.exe。拿错的话也不是完全不能用NSSM 32 位版在 64 位系统上也能注册服务但服务管理器里部分显示可能异常而且 32 位进程去启动 64 位程序时会遇到文件重定向问题属于能省就别省的操作。常见做法是把 nssm.exe 单独放到一个固定目录比如 C:\tools\nssm\nssm.exe而不是每次从解压临时目录运行。因为 NSSM 安装服务时会把自身路径写入注册表服务安装后再移动 nssm.exe服务启动时找不到主程序会直接失败。这也是新手容易踩的坑。准备好之后用管理员权限打开 CMD 或 PowerShell。注意必须是管理员权限普通终端在创建服务时大概率会报“拒绝访问”。3.2 交互式安装先 nssm install 打开图形界面最简单的安装方式是直接运行nssm install MyService这条命令会弹出 NSSM 的 GUI 配置窗口。在 Path 一栏填 app.exe 的完整路径比如 C:\app\app.exeStartup directory 会自动带出来一般不用改Arguments 填需要带的参数比如--port 8080。填完之后点击 Install service服务就注册成功了。GUI 的好处是选项卡里能看到 Logs、Environment、Exit actions 这些参数适合第一次使用的人熟悉 NSSM 有哪些配置项。GUI 窗口在服务器远程桌面里偶尔会出现显示不全的情况而且每次改配置都要开窗口批量操作效率太低。所以我更常用的是下面的命令行方式。打开图形界面的命令同样适用于已有服务运行nssm edit MyService就会打开配置窗口修改现有服务。3.3 命令行安装一台机器上能复制的完整命令在脚本化或远程维护场景里用命令行装服务是更可控的方式。完整命令如下nssm install MyService C:\app\app.exe --port 8080 nssm set MyService AppDirectory C:\app nssm set MyService AppStdout C:\app\logs\stdout.log nssm set MyService AppStderr C:\app\logs\stderr.log nssm set MyService AppRotateFiles 1 nssm start MyService逐条说明。第一条把服务名定义为 MyService程序路径和参数写在后面第二条设置 AppDirectory这个参数指定程序的工作目录。很多程序启动时要读当前目录下的配置文件不设这一项程序可能起不来这是后面避坑章的主角第三条和第四条把标准输出和标准错误重定向到文件方便排查问题第五条开启日志轮转第六条启动服务。安装完成后用nssm status MyService查看状态输出 SERVICE_RUNNING 就说明正常运行。如果用nssm start MyService启动时提示服务已经启动多半是安装之后服务的启动类型是“自动”系统已经拉起来了。3.4 服务参数查询与批量修改服务装好之后参数不是写死的随时可以改。常用命令是 nssm set、nssm get、nssm edit 三件套。nssm get 用来读当前值比如nssm get MyService AppDirectory nssm get MyService AppExitnssm set 用来改值。下面命令把日志文件路径改到 D 盘nssm set MyService AppStdout D:\logs\app.log nssm restart MyServicenssm edit 则是打开图形界面。三者的选择规律是查看用 get脚本修改用 set人工调试用 edit。注意改完配置后已经在运行的服务不会马上生效需要 restart 一次。NSSM 自己没有热加载机制这点和 nginx -s reload 不一样别指望改配置即时生效。4. 日志、环境变量和恢复策略让服务真正跑得久服务能启动了只是第一步。实际跑生产的时候日志、环境变量、异常退出策略才是决定这个服务能不能长期跑下去的关键。这一章把 NSSM 里最常用的几组参数讲透。4.1 日志重定向不写出来就不知道死在哪在上一章的安装命令里已经出现了 AppStdout 和 AppStderr。这两个参数做的事情是把被托管进程的标准输出和标准错误写到文件。很多程序尤其是 nginx、脚本类程序本身不写日志文件只往控制台打印直接注册成服务后输出无处可去报错信息全丢。配置日志文件时建议 stdout 和 stderr 分开两个文件避免出错信息被正常日志刷掉。文件目录一定要提前建好NSSM 不会自动创建目录如果路径不存在输出会静默失败日志文件不会出现你还会以为程序没输出。日志轮转在 3.3 已经开过这里重点说两个参数。AppRotateFiles1 开启轮转AppRotateBytes 指定轮转阈值。例如nssm set MyService AppRotateFiles 1 nssm set MyService AppRotateBytes 1048576010485760 是 10MB 的字节数。达到这个大小后NSSM 会把当前日志重命名为带时间戳的文件再新建一个空日志继续写相当于自己做了一个按文件大小切割的轮转避免日志无限膨胀写满磁盘。4.2 环境变量和工作目录两个最容易忽视的配置win10 下跑服务经常出现“服务显示运行中但程序内部报找不到文件、找不到命令”的现象。原因有两个都出在 NSSM 的默认行为上。第一个是工作目录。服务由 SCM 启动默认工作目录不是程序所在目录而是 system32 之类的系统目录。程序如果是相对路径读取配置文件就会读到不存在的位置。解决办法就是把 AppDirectory 设置成程序目录上一章已经做了。第二个是环境变量。NSSM 默认继承的是系统环境变量不会加载用户环境变量也不会自动把程序目录加进 PATH。如果你的服务需要调用别的命令比如脚本里调 python、git需要额外配置。NSSM 在 GUI 的 Environment 选项卡里可以逐条加命令行则用 AppEnvironmentExtranssm set MyService AppEnvironmentExtra PATHC:\Python311;C:\Program Files\Git\bin注意这个参数设置的是 PATH 的追加片段和系统 PATH 是叠加关系不是覆盖。如果你在 win10 上安装 MySQL 5.7 之后想让 MySQL 服务读对配置文件同样要确认工作目录是 MySQL 的 bin 目录否则它会去默认位置找 my.ini。4.3 进程守护退出码策略和自动重启NSSM 最被看重的功能是“进程死了自动拉起”对应配置在 Exit actions 里。核心是两个参数AppExit 和 AppRestartDelay。AppExit 决定不同退出码对应的动作。最简单的设置是任何退出码都重启nssm set MyService AppExit Default Restart这条命令的意思是如果进程退出且退出码不是专门定义的某个值默认执行 Restart。也可以只针对特定退出码做处理比如退出码 0 是正常结束不需要重启退出码 1 是崩溃要重启nssm set MyService AppExit 0 Exit nssm set MyService AppExit 1 RestartAppRestartDelay 是重启延迟单位毫秒。这个参数非常关键不设置的话进程退出后 NSSM 会马上重启。如果程序启动时需要初始化数据库等资源瞬间的高频重启会打满 CPU形成重启风暴。常规做法是设 5 到 10 秒nssm set MyService AppRestartDelay 5000设置了 5 秒延迟后进程即使持续崩溃系统也有喘息空间方便你去看日志定位问题。4.4 服务依赖让先启动的服务先起来当多个服务之间有先后关系时比如 nginx 依赖本机 MySQL需要配置服务依赖。NSSM 对应的参数是 AppDependOnService多个依赖之间用斜杠分隔nssm set MyService AppDependOnService MySQL57这里的 MySQL57 是 MySQL 服务在系统里的服务名不是显示名。可以用sc query | findstr MySQL查准确的服务名。配置依赖后SCM 在启动 MyService 之前会先启动 MySQL57如果 MySQL57 启动失败MyService 也不会启动避免出现下游服务先跑起来、连接数据库失败再退出的尴尬。5. 避坑NSSM 服务起不来的 5 个常见死法下面这些问题是实操里反复遇到的按现象、原因、解决的顺序写每条都是在 win10 上直接用 NSSM 跑服务时真实会踩到的坑。5.1 服务状态是 Running但进程列表里根本没有程序现象服务管理器里 MyService 显示“正在运行”但任务管理器里找不到 app.exe。原因NSSM 实际是启动了进程但进程启动后立刻退出SCM 看到 NSSM 还没报告退出就暂时显示运行中。最常见的原因是 AppDirectory 没设置程序启动时工作目录不对读不到配置然后自己退出。另一个常见原因是程序路径填成快捷方式或安装引导程序安装引导程序启动后立即退出真正的业务进程还没起来。解决先nssm edit MyService检查 Path 和 Startup directory确认 Path 指向真正的 exeAppDirectory 指向 exe 所在目录。如果仍然秒退把 AppStdout 和 AppStderr 配好看程序自己输出了什么错误。5.2 服务在“启动中”和“已停止”之间反复横跳现象服务管理器里状态一直变来变去CPU 占用飙升事件查看器里全是同一个服务的启动失败记录。原因典型的重启风暴。配置了 AppExit Default Restart但没设置 AppRestartDelay进程一崩立即拉起拉起来又崩形成循环。解决先把恢复策略改成不重启确认程序本身能手动跑起来nssm set MyService AppExit Default Exit nssm stop MyService nssm start MyService确认稳定运行后再设置 AppExit Default Restart 和 AppRestartDelay 5000。这样即使再崩也有 5 秒间隔不会把 CPU 打满。5.3 日志文件涨到几个 GB系统盘被写满现象C 盘剩余空间快速下降打开日志文件发现里面有几 GB 内容。原因没开启日志轮转。NSSM 默认情况下会把 stdout 和 stderr 无限追加到同一个文件服务跑几个月后文件大小很恐怖磁盘被写满后整个系统变卡服务也会因为磁盘写不进去而异常退出。解决给日志配好轮转nssm set MyService AppRotateFiles 1 nssm set MyService AppRotateBytes 10485760顺带检查一下日志是不是 stdout 和 stderr 混在同一个文件里混在一起排查问题会非常痛苦建议分开。5.4 重启服务时旧进程没被杀死端口被占用现象执行 nssm restart 后新进程起不来提示端口被占用查进程发现旧的 app.exe 还在。原因NSSM 停止服务时默认给进程发一个 CtrlC 或 WM_CLOSE 信号进程如果没做优雅退出NSSM 会等一段时间再强制结束。但如果程序对信号无响应NSSM 判断超时后可能没有真正杀掉整个进程树子进程还活着。解决配置停止方法更直接一点nssm set MyService AppStopMethodConsole 5000 nssm set MyService AppStopMethodWindow 5000 nssm set MyService AppStopMethodThreads 5000 nssm set MyService AppKillProcessTree 1前几行把三阶段优雅退出等待时间收紧到 5 秒最后一行是强制杀掉整个进程树。如果确认程序不需要做清理工作可以把超时调成 1000让服务停止和重启更快。5.5 win10 上装服务报“拒绝访问”或者服务无法启动现象nssm install 报拒绝访问或者服务装好后启动报“服务未能在及时时间内响应”。原因终端不是管理员权限或者程序路径放在带用户名的目录下比如 C:\Users\张三\app.exe。NSSM 的服务默认以 LocalSystem 账户运行LocalSystem 能读大多数系统目录但对个别用户目录有访问限制。win10 的 UAC 也会拦普通权限的命令行操作。解决全程用管理员身份打开 CMD 或 PowerShell服务程序放到 C:\app、C:\tools 这类公共目录路径里不要带用户名也不要用中文路径。如果程序必须读某个用户目录的数据可以在服务的 Log on 选项卡里改成指定账户并填好密码但普通场景不建议这么干账户密码过期会造成服务起不来。6. 进阶装完服务后的验证清单和配置迁移技巧6.1 验证清单别让“看起来在跑”骗了你服务装完不能算完建议按下面的清单验证一遍再投入使用nssm status 显示 SERVICE_RUNNING。服务管理器里确认启动类型是“自动”。手动重启一次 win10看服务是否自动拉起。用 nssm stop 停掉服务验证崩溃自动恢复策略是否生效。查看日志目录有 stdout.log 和 stderr.log 输出。这套验证在 win10 22H2 和 win10 专业版上都适用。如果你配了服务依赖还要额外验证一下先启动的服务没起来时下游服务是不是也被挡住了。6.2 用注册表导出迁移 NSSM 配置配置迁移是一个实用技巧。NSSM 的服务配置并不存在 NSSM 自己的配置文件里而是写在注册表 HKLM\SYSTEM\CurrentControlSet\Services服务名 下。所以迁移服务到新机器时除了把程序和 nssm.exe 复制过去还可以用 reg export 把配置导出来reg export HKLM\SYSTEM\CurrentControlSet\Services\MyService C:\backup\myservice.reg新机器上重新安装 NSSM 服务后导入注册表并重启服务即可。但注意 ImagePath 里写的是 nssm.exe 的绝对路径两台机器如果 nssm 所在目录不同导入后要手工改一下否则服务找不到 nssm 本体。我自己的习惯是每次装完一个新服务把安装命令、关键参数、日志路径这三样用记事本存一份放在 nssm.exe 旁边。Windows 服务这东西装的时候十分钟排查的时候可能耗一下午留一份命令清单就是给自己留后悔药。遇到服务异常先看 stderr 日志再下结论别急着重启多数问题在日志里都有明确答案。希望帮到你。本文还有配套的精品资源点击获取
返回列表