简介:nssm-2.24.zip 面向需要将 Spring Boot 应用部署为 Windows 后台服务的 Java 开发者与运维人员,尤其适合不熟悉 Windows 服务底层机制、希望免去复杂配置的初中级使用者。NSSM 以简捷高效著称,只需选定 Java 执行文件、配置 jar 路径与启动参数、设定工作目录,即可把应用平滑注册为系统服务,并内置日志管理与自动恢复机制,异常中断后可自动重启,便于故障排查与长期稳定运行。压缩包共 35 个文件,约 344KB,包含 13 个 h 头文件与 12 个 cpp 源文件构成的核心实现,另有 2 个 exe 可执行程序、2 个 txt 说明文档,以及 rc、mc、cmd、vcproj、sln、ico 等工程与资源文件,覆盖 win32 与 win64 两套可执行版本,源码与工程结构完整。目前已有 266 人学习下载,适合希望快速落地 Spring Boot Windows 服务化部署、并了解其内部实现与排错思路的读者参考。
1. nssm-2.24.zip 到底是什么:把一个 exe 变成 Windows 服务的最后一公里
手里有个自己写的采集程序、一个 Python 脚本、一个 Node 小工具,双击能跑,关掉窗口就停,服务器一重启就彻底失联。这种场景下,nssm-2.24.zip 就是那个被反复翻出来的压缩包。nssm 全称 Non-Sucking Service Manager,干的事非常单一:把任意一个可执行程序注册成 Windows 原生服务,让它开机自启、崩溃自拉、日志可控。2.24 是它流传最广的一个版本号,网上搜 nssm 出来的教程九成都在用它。
它解决的不是“怎么写程序”,而是“怎么让程序在 Windows 上像个服务一样活着”。适合谁?适合那些不想为了一个后台进程去啃 Windows Service API、不想装一堆运行时、只想把现成的 exe 或脚本挂上去就跑的运维和开发。读完这篇,你能拿到一套从解压到排错的完整路径,而不是只知道“有个工具叫 nssm”。
2. 解压之后先别急着 install:nssm 的目录结构与版本选择
2.1 32 位和 64 位到底选哪个
nssm-2.24.zip 解压出来通常长这样:根目录下有一个win32文件夹和一个win64文件夹,各自里面放着一份nssm.exe。这不是让你两个都用,而是按目标机器的架构二选一。
判断方法很直接,在目标机器上开 PowerShell:
# 查看操作系统架构,AMD64 就选 win64 echo $env:PROCESSOR_ARCHITECTURE输出AMD64用win64\nssm.exe,输出x86用win32\nssm.exe。选错的后果不是立刻报错,而是服务能装上、能启动,但在某些调用路径上行为诡异,这种玄学问题排查起来最费时间。
我一般会把选中的那份nssm.exe单独复制到一个固定目录,比如C:\tools\nssm\nssm.exe,然后把该目录加进系统 PATH。这样后面所有命令直接敲nssm就行,不用每次写一长串路径。注意:nssm 本身不需要安装,它就是个绿色 exe,复制走就能用。
2.2 为什么是 2.24 而不是更新的版本
nssm 官方后来有过 2.24 之后的构建,但 2.24 之所以被大量教程和脚本锁定,是因为它的命令行接口稳定、行为可预期,网上能搜到的参数说明几乎都对应这个版本。生产环境里,一个“大家都知道怎么用”的旧版本,往往比一个“参数可能变了”的新版本更省心。
需要说清楚的是:nssm 不是唯一方案。Windows 自带的sc create也能注册服务,但它对“程序崩溃后自动重启”“工作目录设置”“stdout/stderr 重定向”这些需求支持得很别扭,经常要配合一堆包装脚本。nssm 的价值就在于把这些常见诉求做成了几个参数。选它的理由不是它多强,而是它把 80% 的场景用最低成本覆盖了。
2.3 服务账户:LocalSystem 不是万能钥匙
安装服务时会涉及运行账户。默认走 LocalSystem,权限最大,能访问大多数本地资源。但如果你的程序要访问网络共享、要读某个域用户才能读的目录,LocalSystem 反而会失败,因为它是本机账户,出去访问时身份不对。
常见做法是改成具体的域账户或本地管理员账户:
# 安装时指定运行账户,注意域名或机器名前缀 nssm install MyService "C:\path\to\app.exe" nssm set MyService ObjectName "DOMAIN\user" "password"参数说明:ObjectName设的是服务登录身份,第一个值是账户名,第二个是密码。密码里有特殊字符时用引号包住。改完账户后建议手动nssm restart MyService验证一次,因为账户权限问题往往要等服务真正跑起来访问资源时才暴露。
3. 用 nssm 把程序注册成服务的完整命令链路
3.1 最小可用安装:三条命令跑通
假设你有一个C:\apps\collector\collector.exe,要把它做成开机自启的服务。最简路径如下:
# 第一步:注册服务,指定可执行文件 nssm install CollectorService "C:\apps\collector\collector.exe" # 第二步:设置工作目录,程序里如果用相对路径读配置,这步不能省 nssm set CollectorService AppDirectory "C:\apps\collector" # 第三步:启动服务 nssm start CollectorService逻辑说明:install只负责把服务登记进系统,不会自动启动。AppDirectory决定进程的工作目录,很多程序读config.json用的是相对路径,不设这个就会去C:\Windows\System32找,然后报“配置文件不存在”。start才是真正拉起进程。
参数说明:服务名CollectorService自己起,别用中文和空格,后面所有命令都靠它引用。可执行文件路径必须用绝对路径,且路径里有空格时整个用引号包住。
3.2 带启动参数的程序怎么配
如果程序需要命令行参数,比如collector.exe --mode=prod --port=8080,不能直接塞进 install 的第二个参数里,要用AppParameters:
# 先正常安装 nssm install CollectorService "C:\apps\collector\collector.exe" # 再单独设置启动参数 nssm set CollectorService AppParameters "--mode=prod --port=8080" # 设置工作目录 nssm set CollectorService AppDirectory "C:\apps\collector"逻辑说明:nssm 把“可执行文件”和“参数”拆成两个配置项,这样改参数不用重装服务。AppParameters的值会原样拼在 exe 后面,所以参数格式要和你手动在命令行敲的完全一致。
参数说明:如果参数值本身带空格,比如某个路径参数,要在参数内部再加一层引号,写成--config="C:\my config\a.json"。这层引号是给程序看的,不是给 nssm 看的。
3.3 日志重定向:别让程序输出石沉大海
服务方式运行的程序,stdout 和 stderr 默认没有地方去,程序里print或console.log的东西直接消失。排查问题时这是最坑的一点。nssm 支持把输出写到文件:
# 标准输出重定向到文件 nssm set CollectorService AppStdout "C:\apps\collector\logs\stdout.log" # 标准错误重定向到文件 nssm set CollectorService AppStderr "C:\apps\collector\logs\stderr.log" # 开启输出文件自动轮转,避免日志无限增长 nssm set CollectorService AppRotateFiles 1 nssm set CollectorService AppRotateBytes 10485760逻辑说明:AppStdout和AppStderr分别接管两类输出。AppRotateFiles 1打开轮转,AppRotateBytes设单文件上限,单位是字节,10485760 就是 10MB。超过就切新文件。
参数说明:日志目录必须提前存在,nssm 不会帮你建目录,目录不存在时输出直接丢弃,服务照跑不误,这种“服务正常但没日志”的情况最容易让人误判。建议在安装前先mkdir好。
3.4 崩溃自动重启:AppExit 与 AppThrottle
服务最核心的价值之一是挂了能自己起来。nssm 默认对非零退出码会尝试重启,但重启节奏要控制,否则程序有启动即崩的 bug 时会疯狂重启刷爆日志。
# 设置退出后的动作:restart 表示重启 nssm set CollectorService AppExit Default Restart # 设置重启节流,单位毫秒,这里 5000 表示 5 秒内最多重启一次 nssm set CollectorService AppThrottle 5000 # 设置启动失败后的重试延迟 nssm set CollectorService AppRestartDelay 3000逻辑说明:AppExit Default Restart是兜底策略,程序任何非正常退出都触发重启。AppThrottle防止重启风暴,AppRestartDelay控制两次重启之间的间隔。
参数说明:AppThrottle设太小(比如 1000)在程序快速崩溃时仍可能产生大量重启记录;设太大(比如 60000)又会让真正需要快速恢复的服务等太久。5000 到 10000 是常见区间,按业务对恢复速度的要求调。
4. 避坑与排查:nssm 服务起不来的五类真实翻车
4.1 服务显示已启动,但进程秒退
现象:nssm start返回成功,服务状态显示 Running,但过几秒再看已经停了,日志里什么都没有。
原因:程序自身启动就失败,比如依赖的 DLL 缺失、配置文件路径不对、端口被占用。因为进程退得太快,nssm 还没来得及捕获输出。
解决:先把AppStdout和AppStderr配好,然后手动在命令行用同样的工作目录和参数跑一遍 exe,看真实报错。命令行能复现的问题,不要指望服务方式能自己好。
4.2 工作目录没设,相对路径全废
现象:命令行手动跑正常,做成服务就读不到配置、找不到模板文件。
原因:服务的默认工作目录是C:\Windows\System32,程序里所有相对路径都基于它解析。
解决:nssm set <服务名> AppDirectory "<程序所在目录>",然后重启服务。这是最高频的一个坑,几乎每个第一次用 nssm 的人都会踩。
4.3 账户权限不足,访问网络资源被拒
现象:服务能启动,但一访问共享目录或数据库就报权限错误,换成手动运行又正常。
原因:服务默认以 LocalSystem 运行,访问外部资源时身份和当前登录用户不同。
解决:nssm set <服务名> ObjectName "<有权限的账户>" "<密码>",然后重启。改完账户后,原来 LocalSystem 能访问的本地路径可能反而不能访问了,要一并检查。
4.4 日志文件不轮转,磁盘被写满
现象:服务跑了几个月,某天突然所有程序异常,一看磁盘满了,罪魁祸首是某个几十 GB 的 stdout.log。
原因:只设了AppStdout,没开轮转。
解决:补上AppRotateFiles 1和AppRotateBytes,然后重启服务。已经写大的日志文件要手动清理。注意轮转只在服务重启或达到阈值时触发,不是实时切割。
4.5 卸载不干净,重装报服务已存在
现象:nssm remove之后重新 install,提示服务名已存在。
原因:remove 时如果没加confirm,或者服务正在运行,可能没删干净。
解决:先nssm stop <服务名>,再nssm remove <服务名> confirm。如果还残留,用sc query <服务名>确认,必要时用sc delete <服务名>兜底。删完再重装。
5. 进阶技巧:用 nssm 管理多实例与验证服务真实状态
5.1 同一程序跑多实例的命名与端口隔离
一个采集程序要同时跑三个不同数据源,最省事的做法是装三个服务,靠服务名和启动参数区分:
# 实例一 nssm install Collector_A "C:\apps\collector\collector.exe" nssm set Collector_A AppParameters "--source=A --port=9001" nssm set Collector_A AppDirectory "C:\apps\collector" # 实例二 nssm install Collector_B "C:\apps\collector\collector.exe" nssm set Collector_B AppParameters "--source=B --port=9002" nssm set Collector_B AppDirectory "C:\apps\collector"逻辑说明:三个服务共用同一个 exe,靠AppParameters里的--source和--port隔离。这样升级程序时只换一个 exe,三个服务重启即可,不用分别维护三份代码。
参数说明:端口一定要错开,否则第二个实例启动时端口冲突直接失败。服务名建议带业务含义,别用Service1、Service2,半年后自己都认不出来。
5.2 怎么确认服务是真的在干活
服务状态 Running 只代表进程活着,不代表业务正常。我一般用三层验证:
| 验证层 | 方法 | 判断标准 |
|---|---|---|
| 进程层 | nssm status <服务名> | 返回 SERVICE_RUNNING |
| 日志层 | 看 AppStdout 最后几行 | 有近期时间戳的正常输出 |
| 业务层 | 访问程序暴露的端口或检查输出文件 | 数据在更新,端口有响应 |
只看第一层是不够的。我踩过的坑就是服务 Running、日志停在三天前、业务早就卡死了,因为程序内部线程挂了但主进程没退。所以业务层验证不能省,最好配个外部监控定时打一下。
5.3 升级 exe 时的正确姿势
程序要更新,直接覆盖正在运行的 exe 会失败,因为文件被占用。正确顺序是:
# 停服务 nssm stop CollectorService # 确认进程已退出,必要时等几秒 timeout /t 3 # 替换 exe copy /Y "C:\build\collector.exe" "C:\apps\collector\collector.exe" # 启动服务 nssm start CollectorService逻辑说明:stop之后进程不会瞬间消失,给系统一点时间释放文件句柄。copy /Y覆盖时不提示确认。
参数说明:如果程序有多个实例,每个都要停、换、起。换完记得看一眼日志确认新版本正常启动,别换完就不管了。
5.4 我自己的习惯
用了几年 nssm,我现在装任何服务都会先做三件事:建好日志目录、设好 AppDirectory、配好 AppStdout 和 AppStderr。这三步花不了一分钟,但能省掉后面大量的“服务在跑但不知道在干嘛”的时间。nssm 本身不复杂,复杂的是程序自己的依赖和环境,把日志这扇窗留好,出问题时才有后悔药可吃。希望帮到你。
本文还有配套的精品资源,点击获取