NSSM

原生系统服务管理器(the Native System Service Manager)

NSSM 能把任何可执行程序变成一个正规的 Windows 服务,并且让它一直活着: 应用崩溃或意外退出时自动重启;可以把输出捕获到日志文件、优雅地关闭应用、 以任意账户运行,功能远不止于此。没有配置文件、没有运行库依赖—— 一个 exe 加注册表就够了。

v3.0.3 公共领域(Public Domain) 支持 Windows XP 及以后 x86 & x64 图形界面 + 命令行

NSSM 能做什么

NSSM 是一个类似于 srvany 和 cygrunsrv 的服务辅助程序, 但具备一个真正的服务管理器该有的功能。它可以把任何应用作为 NT 服务启动, 并在应用因任何原因失败时自动重启服务。

任何程序都能变成服务

控制台工具、用 cmd /c 启动的脚本、Java 程序、游戏服务器、Node.js 应用——只要能从命令行启动,NSSM 就能把它作为服务运行。

自动重启

应用崩溃或退出后自动拉起。节流机制和可配置的重启延迟,避免一个坏掉的应用反复空转吃掉 CPU。

优雅关闭

停止服务时依次尝试 Control-C、窗口消息和线程消息,最后才调用 TerminateProcess()。每一级都有可配置的超时,也可以按需禁用。

日志与轮转

把 stdin/stdout/stderr 重定向到文件,支持毫秒级时间戳前缀、按大小或时间的在线轮转,以及针对被其他进程占用文件的 copy-and-truncate 轮转。

环境变量控制

用 AppEnvironment 和 AppEnvironmentExtra 替换或扩展服务环境,完整支持 %VAR% 展开。

优先级与 CPU 亲和

设置进程优先级,用 0-2,4 这样的简单写法把应用绑定到指定 CPU。

事件钩子

在启动、停止、退出、日志轮转、电源事件的前后运行你自己的命令。钩子能读到一整套 NSSM_* 环境变量,了解事件的来龙去脉。

任意账户运行

LocalSystem、虚拟服务账号或任意用户账户。启动类型、显示名称、描述、依赖关系、服务类型都能用命令行或图形界面设置。

图形界面 + 完整命令行

用友好的图形界面安装和编辑服务,也可以全程脚本化操作;用 nssm dump 一键导出任何服务的配置。

关于这个分支

NSSM 由 Iain Patterson 编写并以公共领域(public domain)授权发布,原站为 nssm.cc。上游最后一个版本(2.24)发布于 2017 年。 本项目是持续维护的延续版,包含以下改进,并与原版命令语法、注册表结构 100% 兼容。

持续维护

修复持续进行:卸载服务不再需要重启、日志线程稳定性、钩子与节流的竞态、内存安全等问题都已解决。

删除服务免重启

nssm remove 会先停止服务,遇到 ERROR_SERVICE_MARKED_FOR_DELETE 时自动重试——不用再为了重装一个服务而重启电脑。

安全加固

DLL 加载使用 LOAD_LIBRARY_SEARCH_SYSTEM32,并修复了缓冲区溢出、资源泄漏和空指针崩溃等一系列问题。

经过测试

catch2 单元测试和 Pester 集成测试套件在每次改动时于 CI 中运行,覆盖服务生命周期、参数读写和崩溃恢复。

对老系统友好

发布版二进制使用 Visual Studio 2008 编译,可运行于 Windows XP 及以后的 32 位与 64 位系统。日常开发使用 VS2019+。

sc.exe 风格别名

nssm delete 是 nssm remove 的别名,与 sc.exe 的习惯一致。

为什么没有配置文件? 与原版 NSSM 相同,本分支的配置保存在注册表 HKLM\SYSTEM\CurrentControlSet\Services\<服务名>\Parameters 下。目前暂不支持 WinSW 那样的 XML/YAML 配置文件——脚本化请用 nssm set,备份或迁移服务请用 nssm dump,它会导出一份 可直接执行的批处理脚本。

快速上手

所有命令都需要管理员权限的命令提示符。下面的例子把一个 Node.js 应用安装为 名为 myapp 的服务,请替换成你自己的路径。

  1. 安装服务

    最快的方式——所有参数直接写在命令行上:

    nssm install myapp "C:\apps\node\node.exe" "C:\apps\myapp\server.js"

    或者不带程序路径运行 nssm install myapp,会打开图形安装界面。路径中有空格必须加引号。

  2. 调整基本配置

    rem 程序的启动目录
    nssm set myapp AppDirectory C:\apps\myapp
    
    rem 把 stdout 和 stderr 记录到日志文件
    nssm set myapp AppStdout C:\logs\myapp.out.log
    nssm set myapp AppStderr C:\logs\myapp.err.log
    
    rem 每 10 MB 轮转一次日志,并在每行前面加时间戳
    nssm set myapp AppRotateFiles 1
    nssm set myapp AppRotateBytes 10485760
    nssm set myapp AppTimestampLog 1
    
    rem 让服务显示为"我的应用"并附上描述
    nssm set myapp DisplayName "My Application"
    nssm set myapp Description "My web application server"
  3. 启动服务

    nssm start myapp

    确认它在运行:

    nssm status myapp
    nssm processes myapp
  4. 日常管理

    nssm restart myapp
    nssm stop myapp
    nssm list

    也可以用 services.msc 或 sc.exe 来控制——NSSM 管理的就是普通的 Windows 服务。

  5. 备份或迁移

    nssm dump myapp

    输出一份可重建该服务的批处理脚本。在另一台机器上(先复制过去 nssm.exe)执行即可克隆服务。nssm dump myapp myapp2 会展示 myapp 的配置,但生成的命令针对名为 myapp2 的服务。

  6. 卸载服务

    nssm remove myapp confirm

    NSSM 会先停止服务再删除。即使服务正在运行也不需要重启系统。

图形界面方式: 运行 nssm install(不带参数)或 nssm edit myapp,即可在对话框里配置一切——路径、日志、轮转、环境变量、 优先级、亲和性、钩子——不必敲命令行。

命令参考

凡是出现 <servicename> 的地方,既可以填服务的注册表键名, 也可以填它的显示名称。不带参数运行 nssm 可以查看内置帮助。

命令语法说明
installnssm install <服务名> [<程序> [<参数>]]安装服务。给了程序路径就直接创建;不给则打开图形安装界面。
removenssm remove <服务名> [confirm]停止并删除服务。不带 confirm 时弹图形确认框。delete 是别名。
editnssm edit <服务名>打开已安装服务的图形编辑界面。
getnssm get <服务名> <参数名>打印参数当前值。
setnssm set <服务名> <参数名> <值>设置参数。其余所有参数用空格拼接后作为值。
resetnssm reset <服务名> <参数名>把参数恢复为默认值。unset 是别名。
dumpnssm dump <服务名> [<新名字>]输出可重建该服务配置的批处理命令,引号与转义都已处理好。
startnssm start <服务名>启动服务。
stopnssm stop <服务名>停止服务。
restartnssm restart <服务名>先停止再启动服务。
pausenssm pause <服务名>暂停服务(同时暂停重启尝试)。
continuenssm continue <服务名>恢复已暂停的服务。
statusnssm status <服务名>输出服务状态文本,如 SERVICE_RUNNING。成功时退出码为 0。
statuscodenssm statuscode <服务名>以数字服务状态作为退出码,如 SERVICE_RUNNING 为 4。适合脚本判断。
rotatenssm rotate <服务名>触发一次按需日志轮转(需开启在线轮转)。
listnssm list [all]列出 NSSM 管理的服务;加 all 则列出系统上所有服务。
processesnssm processes <服务名>显示该服务启动的进程 PID 与可执行文件路径。
versionnssm version打印 NSSM 版本与编译配置。

配置参考

所有配置都保存在注册表 HKLM\SYSTEM\CurrentControlSet\Services\<服务名>\Parameters 下,用 nssm get / nssm set / nssm reset 管理。 命令行上的参数名与下面的注册表值名称一致。

应用程序

参数类型含义
Application路径要运行的程序的完整路径。相对路径按 NSSM 启动时所在目录解析。
AppParameters字符串传给应用程序的命令行参数。
AppDirectory路径应用程序的工作目录。
AppExit字符串应用退出后的动作,见退出动作。可按退出码单独设置:nssm set <服务> AppExit <退出码> <动作>。

进程控制

参数类型含义
AppThrottleREG_DWORD(毫秒)应用运行不足此时长(默认 1500)视为启动失败,重启间隔会逐次拉长,最长 4 分钟。在 services.msc 里发送"继续"可立即重试。
AppRestartDelayREG_DWORD(毫秒)重启应用前无条件等待的时长,即使上次是干净退出也生效。与节流时长取较大者。
AppPriorityREG_DWORD优先级,例如 nssm set <服务> AppPriority NORMAL_PRIORITY_CLASS。可选值:REALTIME、HIGH、ABOVE_NORMAL、NORMAL、BELOW_NORMAL、IDLE(均带 _PRIORITY_CLASS 后缀)。
AppAffinityREG_SZ逗号分隔、从 0 起算的 CPU 列表,支持区间,如 0-2,4。32 位 NSSM 最多管理 32 个 CPU。
AppNoConsoleREG_DWORD设为 1 时不创建默认的控制台窗口。
AppKillProcessTreeREG_DWORD设为 0 时停止动作只作用于主进程,不再作用于整个进程树。

I/O 重定向

参数类型含义
AppStdin
AppStdout
AppStderr
路径分别连接应用 stdin、stdout、stderr 的文件。把 stdout 和 stderr 设为同一路径即可一起捕获。路径必须对服务账户可写。
AppStdout/Stderr/Stdin
ShareMode、CreationDisposition、
FlagsAndAttributes
REG_DWORD微调每个流的 CreateFile() 参数,如 AppStdoutShareMode、AppStdoutCreationDisposition、AppStdoutFlagsAndAttributes。缺省时使用合理默认值。
AppTimestampLogREG_DWORD设为 1 时给每行重定向输出加毫秒级时间戳前缀,如 2016-09-06 10:17:09.451 消息内容。

日志轮转

参数类型含义
AppRotateFilesREG_DWORD非零开启轮转。旧文件会按时间戳重命名,如 nssm-20131221T113939.457.log。
AppRotateOnlineREG_DWORD非零开启在线轮转(运行中轮转,并支持 nssm rotate)。此时 NSSM 会接管应用的 I/O,实现更复杂;默认关闭。
AppRotateSeconds
AppRotateBytes
AppRotateBytesHigh
REG_DWORD文件的最后写入时间不足此秒数 / 文件不足此大小时跳过轮转。两者可组合;AppRotateBytesHigh 把大小上限扩展到 64 位。
AppRotateDelayREG_DWORD(毫秒)轮转后暂停片刻,让日志读取程序来得及感知文件变化。
AppStdoutCopyAndTruncate
AppStderrCopyAndTruncate
REG_DWORD以"先复制再清空原文件"的方式轮转,适用于被其他进程占用而无法改名的文件。期间会临时占用双倍磁盘空间。

退出动作

NSSM 读取以应用退出码命名的 AppExit 值,找不到时回退到默认值。 退出码可到 Windows 事件日志里查。按退出码设置用 nssm set <服务> AppExit <退出码> <动作>,默认动作用 nssm set <服务> AppExit Default <动作>。

取值行为
Restart重启应用(默认行为)。
Ignore应用退出但服务继续运行(模拟 srvany,通常不是你想要的)。
Exit服务干净地停止,让 Windows 的恢复机制接管。
Suicide模拟崩溃以触发 Vista 之前的恢复机制。仅当显式配置了退出码 0 时才对退出码 0 生效。

停止应用的方式

服务停止时 NSSM 按顺序尝试四种方式,每种默认超时 1500 毫秒,作用于整个进程树:

  1. 在应用的控制台产生 Control-C 事件。
  2. 向应用的窗口发送 WM_CLOSE。
  3. 向应用的线程发送 WM_QUIT。
  4. 调用 TerminateProcess()。
参数类型含义
AppStopMethodSkipREG_DWORD 位掩码跳过某些方式:1 = 不发 Control-C,2 = 不发 WM_CLOSE,4 = 不发 WM_QUIT,8 = 不调 TerminateProcess()。慎用 8——应用可能因此永远不会退出。
AppStopMethodConsole
AppStopMethodWindow
AppStopMethodThreads
REG_DWORD(毫秒)各方式的超时。计时按进程树里的每个进程分别计算,总停止时间可能超过各超时之和。

环境变量

参数类型含义
AppEnvironment多字符串整体替换服务环境。已定义过的变量无法再被引用。
AppEnvironmentExtra多字符串在服务环境后追加。大多数人应该用它。
Environment多字符串Windows 标准服务环境块(对所有服务生效,不限 NSSM)。先按字母排序再并入系统环境。

每条是 KEY=VALUE;变量按出现顺序展开,所以 PATH=C:\bin;%PATH% 在 AppEnvironmentExtra 里能正常工作。 命令行下每对键值是一个独立参数,+KEY=VALUE / -KEY 可以增删单个变量:

nssm set myapp AppEnvironmentExtra JAVA_HOME=C:\jdk-17
nssm set myapp AppEnvironmentExtra +PATH=C:\apps\myapp\bin
nssm set myapp AppEnvironmentExtra -JAVA_HOME

系统级服务设置

这些对应标准的服务注册表值,对非 NSSM 管理的服务同样可以读写:

参数含义
DisplayNameservices.msc 里显示的友好名称。
Description服务描述。
Start启动类型:SERVICE_AUTO_START、SERVICE_DELAYED_START、SERVICE_DEMAND_START、SERVICE_DISABLED。
TypeSERVICE_WIN32_OWN_PROCESS(默认)或 SERVICE_INTERACTIVE_PROCESS(仅限 LocalSystem)。
ObjectName运行账户:nssm set <服务> ObjectName <用户> <密码>。内置账户(LocalSystem、LocalService、NetworkService、NT Service\<服务>)不需要密码。
DependOnService
DependOnGroup
依赖,每项一个参数;前缀 +/- 可增删单项,如 nssm set <服务> DependOnService +RpcSs。
ImagePath服务可执行文件路径(即 NSSM 自己)。
Name只读:服务的注册表键名。只知道显示名时很有用。

事件钩子

NSSM 可以在服务事件的前后运行你自己的命令。用 nssm set <服务名> AppEvents <事件>/<动作> <命令> 配置,或直接设置注册表字符串值 Parameters\AppEvents\<事件>\<动作>。

事件/动作时机同步
Start/Pre应用启动之前是
Start/Post应用成功启动之后否
Stop/Pre应用被结束之前是
Exit/Post应用退出并清理完毕之后否
Rotate/Pre、Rotate/Post在线日志轮转前 / 后Pre 为同步
Power/Change、Power/Resume电源状态变化 / 从待机恢复否

钩子继承服务的环境变量,并额外获得 %NSSM_EXE%、 %NSSM_SERVICE_NAME%、%NSSM_EVENT%、 %NSSM_EXITCODE% 等上下文变量;使用前先检查 %NSSM_HOOK_VERSION%。例:系统从待机恢复时自动重启服务:

nssm set myapp AppEvents Power/Resume "%NSSM_EXE% restart %NSSM_SERVICE_NAME%"
全部钩子环境变量(NSSM_HOOK_VERSION ≥ 1)
变量内容
NSSM_EXENSSM 自身路径
NSSM_CONFIGURATION编译信息,如 64-bit debug
NSSM_VERSIONNSSM 版本
NSSM_BUILD_DATENSSM 编译日期
NSSM_PID运行中的 NSSM 进程 PID
NSSM_DEADLINE多少毫秒后钩子会被强制结束
NSSM_SERVICE_NAME服务注册表键名
NSSM_SERVICE_DISPLAYNAME服务显示名
NSSM_COMMAND_LINE启动应用所用的命令行
NSSM_APPLICATION_PID应用进程 PID(可能为空)
NSSM_EVENT / NSSM_ACTION触发钩子的事件类别与动作
NSSM_TRIGGER / NSSM_LAST_CONTROL触发钩子的服务控制 / 最近一次处理的服务控制
NSSM_START_REQUESTED_COUNT累计启动请求数
NSSM_START_COUNT累计成功启动数
NSSM_THROTTLE_COUNT距上次成功启动的慢启动次数
NSSM_EXIT_COUNT累计应用退出次数
NSSM_EXITCODE最近一次应用退出码(可能为空)
NSSM_RUNTIMENSSM 已运行毫秒数
NSSM_APPLICATION_RUNTIME应用自最近一次启动以来的运行毫秒数

Start/Pre 钩子返回退出码 99 时会中止应用启动。把 AppRedirectHooks 设为 1 可让钩子输出进入服务配置的 stdout/stderr。所有钩子超时后都会被强制结束。

常见问题与排障

NSSM 与 sc.exe、srvany 有什么区别?

sc.exe 只是创建服务登记项,要求程序自己实现服务协议;srvany 能承载任意程序但不会重启它。NSSM 既承载任意程序,又对它做监督:失败自动重启、优雅关闭、日志记录、节流和按退出码的策略。

NSSM 支持 WinSW 那样的配置文件吗?

不支持。配置保存在注册表里,与原版 NSSM 完全一致。脚本化用 nssm set;备份或克隆服务用 nssm dump,它输出的批处理脚本可以直接重建全部配置。

服务启动不了

到 Windows 事件日志(应用程序日志,来源为 NSSM)里查具体错误。常见原因:AppDirectory 不对、可执行文件不存在、路径含空格没加引号、服务账户对程序或日志文件没有权限。

端口冲突

应用能启动但一直失败时,检查端口是否被占用:netstat -ano | findstr <端口>,输出里的 PID 就是冲突进程。注意上一个实例可能还在关闭过程中;nssm processes <服务名> 能看到 NSSM 启动了哪些进程。

"服务已标记为删除"

本分支的 nssm remove 会先停止服务并自动重试。如果仍然失败,关掉占用服务句柄的工具(services.msc、事件查看器)再试;2017 年那种"重启电脑解决"的老办法已经不需要了。

用 32 位还是 64 位?

64 位系统用 64 位版。32 位版到处可用,但亲和性最多管理 32 个 CPU,并且在老系统上 nssm processes 读不到 64 位进程的路径。

支持哪些 Windows 版本?

发布版二进制用 Visual Studio 2008 编译,可运行于 Windows XP 及以后的 32 位与 64 位系统。这让 NSSM 很适合继续"养"那些老的 Windows 7 机器。

NSSM 自己的消息输出到哪里?

写到 Windows 事件日志,每类消息有唯一的事件 ID,且跨版本永不改变。你应用的输出则去往 AppStdout/AppStderr 指定的文件。

真的免费吗?

真的——NSSM 是公共领域(public domain)软件。你可以无条件地为任何目的使用它及其源代码。