nsclient¶
Everything check_nsclient does against a running agent lives under the
nsclient sub command:
check_nsclient [GLOBAL OPTIONS] nsclient [CONNECTION OPTIONS] <COMMAND> [ARGS]
The global options (output format, debugging) and
the connection options (--profile,
--timeout-s, --user-agent) are described on the
overview page, as are the output formats
and exit codes every command shares.
Checking the connection¶
ping¶
Confirms the agent is reachable and prints its version as a single line:
$ check_nsclient nsclient ping
Successfully pinged NSClient++ version 0.18.0 2026-08-29
version¶
The same information as a table (and, in json/yaml/csv, as data):
$ check_nsclient nsclient version
╭─────────┬───────────────────╮
│ name │ NSClient++ │
│ version │ 0.18.0 2026-08-29 │
╰─────────┴───────────────────╯
Authentication¶
check_nsclient nsclient auth … obtains and manages the credentials used to
talk to an agent. Logging in stores an API key (and the password used to renew
it) in the operating system credential store and creates a
profile describing the server.
auth login¶
Authenticates against the agent, stores the API key it hands back and creates (or replaces) a profile.
check_nsclient nsclient auth login [OPTIONS] [ID]
| Argument / option | Default | Description |
|---|---|---|
[ID] |
default |
Profile to store the credentials under. |
--url <URL> |
https://localhost:8443 |
Base URL of the agent. |
--username <USER> |
admin |
User to authenticate as. |
--password <PASSWORD> |
prompted | Password. Can also come from CHECK_NSCLIENT_PASSWORD. |
--insecure |
off | Do not validate the TLS certificate. |
--ca <FILE> |
system store | CA bundle to validate the certificate against. |
$ check_nsclient nsclient auth login --password <MY SECURE PASSWORD>
Successfully logged in
The first profile you create becomes the default, so subsequent commands need
no --profile.
Keeping the password out of your shell history¶
--password is optional. When it is omitted the password is read from the
CHECK_NSCLIENT_PASSWORD environment variable, and if that is unset you are
prompted for it (the input is not echoed):
$ check_nsclient nsclient auth login
Password:
Successfully logged in
Both alternatives keep the password out of your shell history and out of the process list.
TLS certificates¶
NSClient++ generates a self-signed certificate on install, which no CA trusts. You therefore have to either point at a CA bundle or accept the certificate as it is:
# validate against a CA bundle (recommended)
$ check_nsclient nsclient auth login --ca "C:\Program Files\NSClient++\security\windows-ca.pem"
# ...or skip validation entirely
$ check_nsclient nsclient auth login --insecure
Without either, the login fails:
$ check_nsclient nsclient auth login --password <PASSWORD>
Error: Failed to login: Failed to login: error sending request for url (https://localhost:8443/api/v2/login): client error (Connect): invalid peer certificate: UnknownIssuer
See Web interface for how to get a certificate browsers and clients trust.
Remote agents¶
Point --url at another host and give the profile a name:
$ check_nsclient nsclient auth login prod --url https://prod-01.example.com:8443 --password <PASSWORD>
Successfully logged in
$ check_nsclient nsclient --profile prod ping
Successfully pinged NSClient++ version 0.18.0 2026-08-29
auth status¶
Shows who the stored credentials authenticate as, and confirms they still work. This is the cheapest way to verify a profile without side effects.
$ check_nsclient nsclient auth status
╭───────────────┬────────────────────────╮
│ profile │ default │
│ url │ https://127.0.0.1:8443 │
│ username │ admin │
│ user │ admin │
│ authenticated │ true │
╰───────────────┴────────────────────────╯
username is what the profile logs in as; user is who the server says you
are. In json:
$ check_nsclient --output json nsclient auth status
{
"profile": "default",
"url": "https://127.0.0.1:8443",
"username": "admin",
"user": "admin",
"authenticated": true
}
The command fails when the credentials are not accepted, so it can be used as a health check:
$ check_nsclient nsclient --profile prod auth status || echo "re-authentication needed"
auth refresh¶
Fetches a new API key using the stored password and replaces the old one.
$ check_nsclient nsclient auth refresh
Token successfully refreshed
You rarely need this: an expired key is renewed automatically on the next
request, provided the password is still in the credential store. Use refresh
when you want the renewal to happen at a predictable moment, for example from
a scheduled job.
auth logout¶
Revokes the API key on the server and removes the profile together with its stored credentials.
$ check_nsclient nsclient auth logout default
Successfully logged out
Revoking on the server matters: without it the key would remain valid until it expired, even though it was gone from your machine.
If the agent cannot be reached, or has already forgotten the key, the local credentials are still removed and the problem is reported as a warning:
Warning: could not revoke the token on the server: Invalid response status from api/v2/login: 500 Internal Server Error
Successfully logged out
Where credentials are stored¶
| Platform | Store |
|---|---|
| Windows | Windows Credential Manager |
| macOS | Keychain |
| Linux | Secret Service (libsecret) |
Two entries are written per profile: <id>_token (the API key) and
<id>_password (used to renew the key). auth logout and
profile remove delete both.
Running under WSL
WSL has no Secret Service by default, so storing the key fails:
Failed to store token in keystore, if you're running under wsl try specifying: check_nsclient --wsl
--wsl switches to a keyring target that works there. Pass it on every
invocation, not just the login.
Queries¶
Queries are the check commands the agent exposes — check_cpu,
check_drivesize and so on. check_nsclient nsclient queries … lists them and
runs them remotely, which makes it a convenient way to try out a check before
wiring it into your monitoring system.
The full list of available checks is in the reference.
queries list¶
$ check_nsclient nsclient queries list
╭───────────────────────────┬───────────────────────────┬──────────────╮
│ name │ title │ plugin │
├───────────────────────────┼───────────────────────────┼──────────────┤
│ check_always_critical │ check_always_critical │ CheckHelpers │
│ check_cpu │ check_cpu │ CheckSystem │
│ check_drivesize │ check_drivesize │ CheckDisk │
│ check_memory │ check_memory │ CheckSystem │
│ check_ok │ check_ok │ CheckHelpers │
│ check_uptime │ check_uptime │ CheckSystem │
╰───────────────────────────┴───────────────────────────┴──────────────╯
name is what you pass to execute. The description is hidden by default:
| Option | Description |
|---|---|
--long |
Also show the description. |
--all |
Include queries from modules that are not loaded. |
$ check_nsclient nsclient queries list --long | head -5
queries show¶
Details for one query:
$ check_nsclient nsclient queries show check_cpu
╭─────────────┬──────────────────────────────────────────────────────╮
│ name │ check_cpu │
│ title │ check_cpu │
│ description │ Check that the load of the CPU(s) are within bounds. │
│ plugin │ CheckSystem │
╰─────────────┴──────────────────────────────────────────────────────╯
--output json additionally carries the query metadata.
queries execute¶
Runs a check and renders the result — the message, the performance data and the status:
$ check_nsclient nsclient queries execute check_cpu
╭──────────┬───────────────────────────────╮
│ command │ check_cpu │
│ output │ OK: CPU load is ok. │
│ total 1m │ 6%, warning: 80, critical: 90 │
│ total 5m │ 2%, warning: 80, critical: 90 │
│ total 5s │ 9%, warning: 80, critical: 90 │
│ result │ OK │
╰──────────┴───────────────────────────────╯
Each performance counter becomes a row. When a check returns several lines they
are numbered (output 1, output 2, …) and counters that repeat across lines
get a (line N) suffix, so nothing is lost.
--output json keeps the structure, which is what you want when a script has
to look at individual values:
$ check_nsclient --output json nsclient queries execute check_ok
{
"command": "check_ok",
"lines": [
{
"message": "No message",
"perf": {}
}
],
"result": 0
}
Note
executealways exits0when the request itself succeeded, even if the check returned CRITICAL — the status is in the output. Useexecute-nagiosif you want the status as the exit code.
An unknown query is not an error at the transport level; the agent answers with an UNKNOWN result:
$ check_nsclient nsclient queries execute no_such_query
╭─────────┬───────────────────────────────────╮
│ command │ no_such_query │
│ output │ Unknown command(s): no_such_query │
│ result │ UNKNOWN │
╰─────────┴───────────────────────────────────╯
queries execute-nagios
Runs a check and behaves like a Nagios plugin: one line of
message|performance data on stdout, and the check status as the exit code.
$ check_nsclient nsclient queries execute-nagios check_cpu
OK: CPU load is ok.|'total 5s'=9%;80;90 'total 1m'=6%;80;90 'total 5m'=2%;80;90
$ echo $?
0
$ check_nsclient nsclient queries execute-nagios check_warning message="disk almost full"
disk almost full
$ echo $?
1
| Exit code | Status |
|---|---|
0 |
OK |
1 |
WARNING |
2 |
CRITICAL |
3 |
UNKNOWN |
This makes check_nsclient usable directly as a check plugin for a monitoring
system that runs checks remotely:
define command {
command_name check_nscp_remote
command_line /usr/bin/check_nsclient nsclient --profile $HOSTNAME$ queries execute-nagios $ARG1$ $ARG2$
}
The other output formats work too and still set the exit code, which is handy when you want both the status and the structured result:
$ check_nsclient --output json nsclient queries execute-nagios check_cpu
{
"command": "check_cpu",
"lines": [
{
"message": "OK: CPU load is ok.",
"perf": "'total 5s'=6%;80;90 'total 1m'=6%;80;90 'total 5m'=6%;80;90"
}
],
"result": "OK"
}
$ echo $?
0
Passing arguments¶
Check arguments are given after the query name, either as key=value or as
--key=value:
$ check_nsclient nsclient queries execute check_cpu --warning="load > 90" --time=5m
$ check_nsclient nsclient queries execute check_cpu warning="load > 90" time=5m
Both forms are equivalent — the leading dashes are stripped before the argument is sent. A bare word becomes a flag with an empty value:
$ check_nsclient nsclient queries execute check_drivesize show-all
Arguments are passed through verbatim and keep their order, so anything the check itself accepts works. The common options page documents the filter, warning and critical syntax shared by most checks.
Note
Quote values containing spaces or shell metacharacters, as with any other command.
--warning="load > 90"— without the quotes the shell would redirect to a file called90.
Aliases¶
An alias is an admin-defined wrapper around a real check command: a short name
bound to a check plus a fixed set of arguments. They are configured under
[/settings/check helpers/alias] (CheckHelpers) or
[/settings/external scripts/alias] (CheckExternalScripts).
aliases list¶
$ check_nsclient nsclient aliases list
╭───────────────────────────┬───────────────────────────┬──────────────────────╮
│ name │ title │ plugin │
├───────────────────────────┼───────────────────────────┼──────────────────────┤
│ alias_cpu │ alias_cpu │ CheckExternalScripts │
│ alias_disk │ alias_disk │ CheckExternalScripts │
│ alias_mem │ alias_mem │ CheckExternalScripts │
│ alias_service │ alias_service │ CheckExternalScripts │
│ checkalwaysok │ CheckAlwaysOK │ CheckHelpers │
│ checkversion │ CheckVersion │ CheckHelpers │
╰───────────────────────────┴───────────────────────────┴──────────────────────╯
| Option | Description |
|---|---|
--long |
Also show the description, which says what the alias expands to. |
--all |
Include aliases from modules that are not loaded. |
--long is how you find out what an alias actually runs:
$ check_nsclient nsclient aliases list --long | grep alias_cpu
│ alias_cpu │ alias_cpu │ Alias for: check_cpu │ CheckExternalScripts │
Running an alias¶
There is no aliases execute. An alias is dispatched by the agent exactly like
a regular query, so run it with queries execute:
$ check_nsclient nsclient queries execute-nagios alias_cpu
OK: CPU load is ok.|'total 5s'=6%;80;90 'total 1m'=6%;80;90 'total 5m'=6%;80;90
The json output makes this explicit with a query_url pointing at the queries
endpoint:
$ check_nsclient --output json nsclient aliases list | jq '.[0]'
{
"name": "alias_cpu",
"title": "alias_cpu",
"description": "Alias for: check_cpu",
"plugin": "CheckExternalScripts",
"query_url": "https://127.0.0.1:8443/api/v2/queries/alias_cpu/",
"metadata": {}
}
Aliases versus queries¶
queries list shows the real check commands;
aliases list shows the wrappers. A name that appears only in aliases list
is an alias, and its description tells you which check it delegates to.
Aliases mostly exist for backwards compatibility with the old check_nt style
command names, and to give a site its own vocabulary for a check that always
takes the same arguments.
Modules¶
Modules are the plugins that give NSClient++ its functionality — the check
commands, the servers and the clients. check_nsclient nsclient modules …
lists them and controls whether they are loaded and enabled.
Loaded versus enabled¶
Two independent flags decide a module’s state:
| Flag | Meaning |
|---|---|
loaded |
The module is loaded into the running process right now. |
enabled |
The module is configured to load on startup (<Module> = enabled). |
You can load a module temporarily without enabling it (it disappears on
restart), or enable one without loading it (it appears on the next restart).
use does both.
modules list¶
Modules that are currently loaded:
$ check_nsclient nsclient modules list
╭──────────────────────┬──────────────────────┬─────────┬────────┬───────╮
│ id │ title │ enabled │ loaded │ alias │
├──────────────────────┼──────────────────────┼─────────┼────────┼───────┤
│ CheckDisk │ CheckDisk │ true │ true │ │
│ CheckExternalScripts │ CheckExternalScripts │ true │ true │ │
│ CheckHelpers │ CheckHelpers │ true │ true │ │
│ CheckSystem │ CheckSystem │ true │ true │ │
│ LUAScript │ LUAScript │ true │ true │ │
│ WEBServer │ WEBServer │ true │ true │ │
│ CommandClient │ CommandClient │ false │ true │ │
╰──────────────────────┴──────────────────────┴─────────┴────────┴───────╯
| Option | Description |
|---|---|
--all |
Also list modules that are not loaded. Slower: every module on disk is inspected. |
--long |
Also show description, name and plugin_id. |
--all is how you find out what else is available:
$ check_nsclient nsclient modules list --all
╭──────────────────────┬──────────────────────┬─────────┬────────┬───────╮
│ id │ title │ enabled │ loaded │ alias │
├──────────────────────┼──────────────────────┼─────────┼────────┼───────┤
│ CheckDisk │ CheckDisk │ true │ true │ │
│ WEBServer │ WEBServer │ true │ true │ │
│ CheckSecurity │ │ false │ false │ │
│ NRPEServer │ │ false │ false │ │
│ Scheduler │ │ false │ false │ │
│ PythonScript │ │ false │ false │ │
╰──────────────────────┴──────────────────────┴─────────┴────────┴───────╯
Modules that are not loaded have no title or description — the agent only reads that out of a module once it is loaded.
modules show¶
$ check_nsclient nsclient modules show CheckSystem
╭─────────────┬────────────────────────────────────────────────────────────────────────────╮
│ id │ CheckSystem │
│ name │ CheckSystem │
│ title │ CheckSystem │
│ description │ Various system related checks, such as CPU load, process state and memory. │
│ enabled │ true │
│ loaded │ true │
│ alias │ │
│ plugin_id │ 3 │
╰─────────────┴────────────────────────────────────────────────────────────────────────────╯
$ check_nsclient --output json nsclient modules show CheckSystem
{
"id": "CheckSystem",
"name": "CheckSystem",
"title": "CheckSystem",
"description": "Various system related checks, such as CPU load, process state and memory.",
"enabled": true,
"loaded": true,
"metadata": {
"alias": "",
"plugin_id": "3"
}
}
$ check_nsclient nsclient modules show NoSuchModule
Error: Failed to fetch module NoSuchModule: Invalid response status from api/v2/modules/NoSuchModule: 404 Not Found: Module not found: NoSuchModule
modules load / unload¶
Loads or unloads the module in the running agent. The configuration is not touched, so a restart undoes it:
$ check_nsclient nsclient modules load CheckNet
Successfully loaded module CheckNet, you can now interact with it but next time the service is restarted it will be unloaded
$ check_nsclient nsclient modules unload CheckNet
Successfully unloaded module CheckNet
Loading a module makes its checks available immediately:
$ check_nsclient nsclient modules load CheckNet
$ check_nsclient nsclient queries execute check_tcp host=example.com port=443
modules enable / disable¶
Changes the configuration only. The running agent is not affected until the module is loaded (or the service restarts):
$ check_nsclient nsclient modules enable CheckNet
Successfully enabled module CheckNet, this module will be available if you restart the service or if you load it
$ check_nsclient nsclient modules disable CheckNet
Successfully disabled module CheckNet, this module will not be available if you restart the service
Note
enableanddisablewrite to the in-memory configuration. Runsettings command saveto persist the change, or it is lost on restart.
modules use¶
The common case: load the module now and enable it for future restarts.
$ check_nsclient nsclient modules use CheckNet
Successfully loaded and enabled module CheckNet
Equivalent to modules load followed by modules enable. If the load fails
the enable is not attempted.
modules upload¶
Uploads a module archive (a .zip zip module)
and loads it:
$ check_nsclient nsclient modules upload MyModule --file ./MyModule.zip
Uploaded and loaded module MyModule
The archive is stored as <module-path>/<ID>.zip on the agent.
Warning
The uploaded archive is loaded immediately and its code runs as the user the NSClient++ service runs as — usually a privileged account. Only upload archives you trust, and consider whether the
modules.postprivilege should be granted at all.
The agent validates the module name and refuses anything that would escape the module directory.
A missing file is reported before anything is sent, without contacting the agent:
$ check_nsclient nsclient modules upload MyModule --file missing.zip
Error: Failed to read missing.zip: The system cannot find the file specified. (os error 2)
Settings¶
check_nsclient nsclient settings … reads and changes the agent configuration
— the same tree you would otherwise edit in nsclient.ini.
Changes are in memory until you save¶
set and delete change the configuration the running agent holds in memory.
Nothing is written to disk until you run settings command save.
The usual sequence is therefore:
$ check_nsclient nsclient settings set --path /settings/WEB/server --key threads --value 20
$ check_nsclient nsclient settings diff # review
$ check_nsclient nsclient settings command save # persist
settings status¶
Where the configuration lives and whether it has unsaved changes:
$ check_nsclient nsclient settings status
╭─────────────┬──────────────────────────────────╮
│ context │ ini:///etc/nsclient/nsclient.ini │
│ type │ ini │
│ has_changed │ false │
╰─────────────┴──────────────────────────────────╯
has_changed: true means there are changes that save has not yet written.
settings list¶
Lists the keys that are actually set, with their values:
$ check_nsclient nsclient settings list --path /modules
╭──────────────────────┬──────────┬─────────╮
│ key │ path │ value │
├──────────────────────┼──────────┼─────────┤
│ CheckDisk │ /modules │ enabled │
│ CheckExternalScripts │ /modules │ enabled │
│ CheckHelpers │ /modules │ enabled │
│ CheckSystem │ /modules │ enabled │
│ LUAScript │ /modules │ enabled │
│ WEBServer │ /modules │ enabled │
╰──────────────────────┴──────────┴─────────╯
| Option | Default | Description |
|---|---|---|
--path <PATH> |
(all) | Only list keys under this path (recursively). |
Without --path the whole store is returned, which on a stock agent is a lot
— filtering is usually what you want.
Note
Values of keys the agent marks sensitive (passwords) are returned as
***.
settings descriptions¶
Every key that can be set, with its type, title and default — the reference for a section:
$ check_nsclient nsclient settings descriptions --path /settings/WEB/server
╭───────────────────────────────┬──────────────────────┬──────────┬───────────┬─────────────────────────────────╮
│ key │ path │ type │ plugins │ title │
├───────────────────────────────┼──────────────────────┼──────────┼───────────┼─────────────────────────────────┤
│ allow anonymous access │ /settings/WEB/server │ bool │ WEBServer │ ALLOW ANONYMOUS ACCESS │
│ allow insecure │ /settings/WEB/server │ bool │ WEBServer │ ALLOW INSECURE (CLEARTEXT HTTP) │
│ allowed hosts │ /settings/WEB/server │ string │ WEBServer │ Allowed hosts │
│ auth rate limit block seconds │ /settings/WEB/server │ int │ WEBServer │ AUTH RATE LIMIT (BLOCK SECONDS) │
│ certificate │ /settings/WEB/server │ string │ WEBServer │ TLS Certificate │
│ password │ /settings/WEB/server │ password │ WEBServer │ Password │
│ port │ /settings/WEB/server │ string │ WEBServer │ Server port │
│ threads │ /settings/WEB/server │ int │ WEBServer │ Server threads │
╰───────────────────────────────┴──────────────────────┴──────────┴───────────┴─────────────────────────────────╯
| Option | Description |
|---|---|
--path <PATH> |
Only describe keys under this path. |
--samples |
Include sample keys (templates showing how a section is filled). |
--long |
Also show description, default value, current value and flags. |
--long (or --output json) is where the actual documentation is:
$ check_nsclient --output json nsclient settings descriptions --path /settings/WEB/server \
| jq '.[] | select(.key == "threads") | {key, type, default_value, description}'
{
"key": "threads",
"type": "int",
"default_value": "10",
"description": "The number of threads in the sever response pool."
}
settings set¶
Sets a single key:
$ check_nsclient nsclient settings set --path /settings/doc-demo --key sample --value demo
Updated /settings/doc-demo/sample
All three options are required. The change is in memory only until you save.
settings diff¶
Everything that changed since the last save — the review step before you persist:
$ check_nsclient nsclient settings diff
╭─────────────┬────────────────────┬────────┬───────────┬───────────╮
│ change_type │ path │ key │ old_value │ new_value │
├─────────────┼────────────────────┼────────┼───────────┼───────────┤
│ added │ /settings/doc-demo │ sample │ │ demo │
│ path_added │ /settings/doc-demo │ │ │ │
╰─────────────┴────────────────────┴────────┴───────────┴───────────╯
change_type is one of added, removed, modified, path_added or
path_removed. Adding a key in a section that did not exist yet reports both
the key and the section, as above.
When there is nothing to save:
$ check_nsclient nsclient settings diff
No unsaved changes
| Option | Description |
|---|---|
--path <PATH> |
Only show changes under this path. |
The is_sensitive column is hidden by default; sensitive values are redacted
to *** by the agent. --output json also reports a count:
$ check_nsclient --output json nsclient settings diff --path /settings/doc-demo
{
"entries": [
{
"change_type": "added",
"path": "/settings/doc-demo",
"key": "sample",
"old_value": "",
"new_value": "demo",
"is_sensitive": false
}
],
"count": 1
}
settings delete¶
Removes a single key:
$ check_nsclient nsclient settings delete --path /settings/doc-demo --key sample
Removed 1 key(s) from /settings/doc-demo/sample
Or a whole section, which has to be asked for explicitly:
$ check_nsclient nsclient settings delete --path /settings/doc-demo --all-keys
Removed 1 key(s) from /settings/doc-demo
Exactly one of --key or --all-keys is required, so a section can never be
wiped by forgetting an argument:
$ check_nsclient nsclient settings delete --path /settings/doc-demo
error: the following required arguments were not provided:
<--key <KEY>|--all-keys>
settings command¶
Drives the configuration store itself:
| Action | Effect |
|---|---|
save |
Write the in-memory configuration to disk. |
load |
Re-read the configuration from disk, discarding unsaved changes. |
reload |
Ask the service to reload (modules are restarted). |
$ check_nsclient nsclient settings command save
Executed Save command
Note
loaddiscards unsaved changes — checkdifffirst.reloadrestarts modules, which briefly interrupts servers such as NRPE or the web interface you are talking to.
A complete example¶
Raise the number of web server threads and make it permanent:
$ check_nsclient nsclient settings descriptions --path /settings/WEB/server --long \
| grep threads
$ check_nsclient nsclient settings set --path /settings/WEB/server --key threads --value 20
Updated /settings/WEB/server/threads
$ check_nsclient nsclient settings diff
╭─────────────┬──────────────────────┬─────────┬───────────┬───────────╮
│ change_type │ path │ key │ old_value │ new_value │
├─────────────┼──────────────────────┼─────────┼───────────┼───────────┤
│ added │ /settings/WEB/server │ threads │ │ 20 │
╰─────────────┴──────────────────────┴─────────┴───────────┴───────────╯
$ check_nsclient nsclient settings command save
Executed Save command
$ check_nsclient nsclient settings command reload
Executed Reload command
Logs¶
The agent keeps its recent log records in memory and exposes them over the API.
check_nsclient nsclient logs … reads that buffer, reports the error counters
and can clear both.
This is the fastest way to find out why a check or a module misbehaves without opening a shell on the host.
logs list¶
$ check_nsclient nsclient logs list --size 3
╭───────┬──────────────────────┬───────────────────────────────────────────────────────────────╮
│ level │ date │ message │
├───────┼──────────────────────┼───────────────────────────────────────────────────────────────┤
│ debug │ 2026-Aug-30 15:45:17 │ Using certificate: /usr/lib/nsclient/security/certificate.pem │
│ debug │ 2026-Aug-30 15:45:17 │ Loading webserver on port: 8443 │
│ debug │ 2026-Aug-30 15:45:17 │ Starting plugin: LUAScript │
╰───────┴──────────────────────┴───────────────────────────────────────────────────────────────╯
| Option | Default | Description |
|---|---|---|
--page <N> |
1 |
Page to read. |
--size <N> |
50 |
Records per page. |
--level <LEVEL> |
(all) | Only records of this level. |
--long |
off | Also show the source file and line. |
Note
The agent rejects
--size 1with400 Bad Request; use2or more.
Filter to the interesting records:
$ check_nsclient nsclient logs list --level error --size 20
--long adds where the record came from, which is what you want when reporting
a problem:
$ check_nsclient nsclient logs list --size 2 --long
╭───────┬──────────────────────┬───────────────────────────────────────────────────┬──────┬───────────────────────────────────────────────────────╮
│ level │ date │ file │ line │ message │
├───────┼──────────────────────┼───────────────────────────────────────────────────┼──────┼───────────────────────────────────────────────────────┤
│ debug │ 2026-Aug-30 15:47:23 │ /__w/nscp/nscp/service/plugins/plugin_manager.cpp │ 966 │ Executing command is target for: CheckExternalScripts │
│ debug │ 2026-Aug-30 15:47:23 │ /__w/nscp/nscp/service/plugins/plugin_manager.cpp │ 1014 │ Executing command in: CheckExternalScripts │
╰───────┴──────────────────────┴───────────────────────────────────────────────────┴──────┴───────────────────────────────────────────────────────╯
In json the pagination is included, so a script knows whether more pages follow:
$ check_nsclient --output json nsclient logs list --size 2
{
"content": [
{
"level": "debug",
"date": "2026-Aug-30 15:47:23",
"file": "/__w/nscp/nscp/service/plugins/plugin_manager.cpp",
"line": 966,
"message": "Executing command is target for: CheckExternalScripts"
},
{
"level": "debug",
"date": "2026-Aug-30 15:47:23",
"file": "/__w/nscp/nscp/service/plugins/plugin_manager.cpp",
"line": 1014,
"message": "Executing command in: CheckExternalScripts"
}
],
"page": 1,
"pages": 26,
"limit": 2,
"count": 52
}
logs status¶
The aggregated error counters — a cheap health check:
$ check_nsclient nsclient logs status
╭────────────┬──────────────────────────────────────────╮
│ errors │ 1 │
│ last_error │ Failed to execute command on CheckSystem │
╰────────────┴──────────────────────────────────────────╯
errors counts the errors logged since the counters were last reset, and
last_error is the most recent one. On a healthy agent:
$ check_nsclient nsclient logs status
╭────────────┬───╮
│ errors │ 0 │
│ last_error │ │
╰────────────┴───╯
This maps nicely onto a monitoring check of the agent itself:
$ errors=$(check_nsclient --output json nsclient logs status | jq .errors)
$ [ "$errors" -eq 0 ] || echo "WARNING: $errors error(s) in the NSClient++ log"
logs reset¶
Resets the counters status reports. The buffered records are kept:
$ check_nsclient nsclient logs reset
Successfully reset log status
Use it after you have acknowledged a problem, so the next status reflects
only new errors.
logs clear¶
Drops the buffered records. The counters are unaffected:
$ check_nsclient nsclient logs clear
Cleared 23 log record(s)
| Command | Clears records | Resets counters |
|---|---|---|
reset |
no | yes |
clear |
yes | no |
Clearing before reproducing a problem gives you a buffer that contains only the relevant records:
$ check_nsclient nsclient logs clear
$ check_nsclient nsclient queries execute check_that_misbehaves
$ check_nsclient nsclient logs list --size 50 --long
logs add¶
Appends a record to the agent log:
$ check_nsclient nsclient logs add --message "reboot scheduled by maintenance script"
Log record added
| Option | Default | Description |
|---|---|---|
--message <TEXT> |
(required) | The message to log. |
--level <LEVEL> |
info |
debug, info, warning or error. |
--file <NAME> |
check_nsclient |
Source attributed to the record. |
--line <N> |
0 |
Line attributed to the record. |
Useful for correlating external activity with what the agent was doing:
$ check_nsclient nsclient logs add --level warning --message "starting deploy $VERSION"
Note
A record logged at
errorlevel increases the error counter thatstatusreports, and so will show up in any check watching it.
Scripts¶
NSClient++ can run external scripts (batch, shell, PowerShell, …) and Lua
scripts as checks. check_nsclient nsclient scripts … lists the runtimes, and
reads, uploads and removes script definitions.
See External scripts for how scripts are configured and secured.
Runtimes¶
A script belongs to a runtime, selected with --runtime:
| Key | Module | Description |
|---|---|---|
ext |
CheckExternalScripts | Anything executed on the command line. |
lua |
LUAScript | Lua scripts running inside NSClient++. |
py |
PythonScript | Python scripts running inside NSClient++. |
Only runtimes whose module is loaded are available.
scripts list-runtimes¶
$ check_nsclient nsclient scripts list-runtimes
╭──────────────────────┬──────┬──────────────────────╮
│ module │ name │ title │
├──────────────────────┼──────┼──────────────────────┤
│ CheckExternalScripts │ ext │ CheckExternalScripts │
│ LUAScript │ lua │ LUAScript │
╰──────────────────────┴──────┴──────────────────────╯
name is what you pass to --runtime.
scripts list¶
The scripts registered as commands in a runtime:
$ check_nsclient nsclient scripts list --runtime ext
╭───────────╮
│ script │
├───────────┤
│ check_doc │
╰───────────╯
| Option | Description |
|---|---|
--runtime |
Runtime to list (required). |
--all |
List every script file found on disk, not only those wired up as a command. |
--all shows what is available to be turned into a command:
$ check_nsclient --output json nsclient scripts list --runtime ext --all
[
"scripts\\check_60s.bat",
"scripts\\check_battery.vbs",
"scripts\\check_files.vbs",
"scripts\\check_long.bat",
"scripts\\check_no_rdp.bat",
"scripts\\check_ok.bat"
]
Note
NSClient++ 0.18.0 does not answer the script listing for the
luaruntime and returns500 No response from module. Usesettings list --path "/settings/lua/scripts"to see the configured Lua scripts instead.
scripts show¶
Prints the definition — the command line that runs when the check is called:
$ check_nsclient nsclient scripts show --runtime ext check_doc
scripts\check_doc
The definition is a command line, so its first token tells you which file is
executed. The API also accepts that path in place of the command name to return
the file’s contents, but only for files the runtime can resolve under its
configured script root; otherwise it answers:
$ check_nsclient nsclient scripts show --runtime ext "scripts/check_doc"
Error: Failed to fetch script scripts/check_doc (ext): Invalid response status from api/v2/scripts/ext/scripts/check_doc: 500 Internal Server Error: Command returned errors: Script not found: scripts/check_doc
Both / and \ work as separators.
scripts add¶
Uploads a script and registers it as a command, replacing any existing definition of the same name:
$ check_nsclient nsclient scripts add --runtime ext check_doc.bat --file ./check_doc.bat
Added check_doc as scripts\check_doc.bat
| Argument / option | Description |
|---|---|
<SCRIPT> |
File name to store the script under. |
--runtime |
Runtime to add it to (required). |
--file <PATH> |
Local file to read the script from (required). |
Note what the confirmation says: the script was stored as
scripts\check_doc.bat and registered as the command check_doc — the
agent keeps the extension for the file and strips it for the command name. So
include the extension in <SCRIPT>, and call the check without it:
$ check_nsclient nsclient scripts show --runtime ext check_doc
scripts\check_doc.bat
$ check_nsclient nsclient queries execute-nagios check_doc
OK: everything is fine
Leaving the extension out stores an extension-less file the agent then cannot execute:
$ check_nsclient nsclient scripts add --runtime ext check_doc --file ./check_doc.bat
Added check_doc as scripts\check_doc
$ check_nsclient nsclient queries execute-nagios check_doc
Failed to execute check_doc: 2: The system cannot find the file specified.
Note
On Linux, NSClient++ 0.18.0 stores the definition with a Windows path separator (
scripts\check_doc.sh) whichever name you use, and the agent then cannot run it:The command (check_doc) returned an invalid return code: 127Uploading works, but on Linux configure the command through the settings commands or
[/settings/external scripts/scripts]instead, where you control the path.
A missing local file is reported before anything is sent:
$ check_nsclient nsclient scripts add --runtime ext check_doc --file missing.sh
Error: Failed to read missing.sh: The system cannot find the file specified. (os error 2)
Warning
An uploaded script runs as the user the NSClient++ service runs as. Treat
scripts.addas an ability to execute arbitrary code on the host and grant it accordingly.Note
This endpoint is a convenience: it cannot set per-script arguments or a dedicated user. Use the settings commands, or
[/settings/external scripts/scripts]in the configuration, when you need that.
scripts delete¶
Removes the script definition:
$ check_nsclient nsclient scripts delete --runtime ext check_doc
Script definition has been removed don't forget to delete any artifact for: scripts\check_doc
As the message says, only the definition goes away — the file itself is left on disk and has to be removed separately.
The API also accepts a script file path here, to delete the file as well, but
just like show that only works for files the runtime resolves under
its configured script root:
$ check_nsclient nsclient scripts delete --runtime ext "scripts/check_doc"
Error: Failed to delete script scripts/check_doc (ext): Invalid response status from api/v2/scripts/ext/scripts/check_doc: 500 Internal Server Error: Command returned errors: Script not found: scripts/check_doc
Note
Removing a definition changes the in-memory configuration. Run
settings command saveto make it permanent, otherwise the script reappears on the next restart orsettings command load.
Metrics¶
NSClient++ collects system metrics continuously — CPU, memory, disk space and
disk I/O — independently of any check. check_nsclient nsclient metrics …
reads the current values, either as data or in the Prometheus/OpenMetrics text
format.
See Prometheus scraping for setting the agent up as a scrape target.
metrics show¶
Every metric as a key/value table:
$ check_nsclient nsclient metrics show
╭─────────────────────────────────┬────────────────────╮
│ disk.io._Total.queue_length │ 0 │
│ disk.io._Total.percent_idle_time│ 100 │
│ system.cpu.total.idle │ 94.06491968367467 │
│ system.cpu.total.kernel │ 1.7618464190929828 │
│ system.cpu.total.total │ 5.935080316325317 │
│ system.cpu.total.user │ 4.173233897232334 │
│ system.mem.physical.% │ 73 │
│ system.mem.physical.avail │ 4389036032 │
│ system.mem.physical.total │ 16554041344 │
│ system.mem.physical.used │ 12165005312 │
╰─────────────────────────────────┴────────────────────╯
The list is long — a container reports one entry per mount point and per block device — so filtering is usually what you want:
$ check_nsclient nsclient metrics show | grep system.mem
--output json keeps the native types (numbers stay numbers), which is what a
script should consume:
$ check_nsclient --output json nsclient metrics show | jq '."system.mem.physical.%"'
73
Note
For the first few seconds after the agent starts, before CheckSystem has completed a collection cycle, the endpoint returns an empty body and the command reports:
Error: Failed to fetch metrics: Empty response from api/v2/metrics (the server may still be starting up, try again shortly)
metrics openmetrics
The same values in the OpenMetrics/Prometheus text exposition format, printed verbatim:
$ check_nsclient nsclient metrics openmetrics
system_cpu_core_0.idle 97.0626
system_cpu_core_0.user 0.586332
system_cpu_core_0.kernel 2.35111
system_cpu_core_0.total 2.93744
system_cpu_core_1.idle 98.8019
system_cpu_core_1.user 0.59802
This is the format a scraper expects, so it can be piped straight into one:
$ check_nsclient nsclient metrics openmetrics > /var/lib/node_exporter/nscp.prom
The body is passed through unchanged in every output format — --output json
does not turn it into JSON, because it is not.
Note
A Prometheus server would normally scrape
/api/v2/openmetricsdirectly rather than go through this command. It is here for ad-hoc inspection and for hosts a scraper cannot reach, where a cron job can push the file instead.
Which one to use¶
| Use case | Command |
|---|---|
| Look at a value by hand | metrics show |
| Feed a script (jq, PowerShell, …) | --output json metrics show |
| Feed Prometheus, or a textfile collector | metrics openmetrics |
Metadata¶
The metadata commands describe what the agent can do rather than what it is doing right now: which performance counters exist on the host, and which submission channels have a listener. Use them to discover what to configure.
metadata list¶
The available metadata resources:
$ check_nsclient nsclient metadata list
╭──────────┬────────────────────────────────┬─────────────────────────────────────────────────╮
│ name │ title │ url │
├──────────┼────────────────────────────────┼─────────────────────────────────────────────────┤
│ counters │ Performance counters │ https://127.0.0.1:8443/api/v2/metadata/counters │
│ channels │ Registered submission channels │ https://127.0.0.1:8443/api/v2/metadata/channels │
╰──────────┴────────────────────────────────┴─────────────────────────────────────────────────╯
More resources may be added in future releases, so this index is the reliable way to see what an agent offers.
metadata counters¶
The Windows performance counters (PDH) discovered on the host — the values you
can hand to check_pdh:
$ check_nsclient nsclient metadata counters
╭─────────────────────────────────────────────────┬──────╮
│ name │ type │
├─────────────────────────────────────────────────┼──────┤
│ \Processor Information(_Total)\% Processor Time │ │
│ \Memory\Available Bytes │ │
│ \PhysicalDisk(_Total)\Avg. Disk Queue Length │ │
╰─────────────────────────────────────────────────┴──────╯
A real host has thousands of them, and the names follow the Windows display language — on a Swedish Windows they come back in Swedish. Searching is therefore the usual reason to run this:
$ check_nsclient --output json nsclient metadata counters | jq -r '.[]' | grep -i "processor time"
Note
NSClient++ 0.18.0 returns a plain list of counter paths, so the
typecolumn is empty. The client also accepts the richer{name, type}form described in the API documentation should a later release start sending it.
Then use it in a check:
$ check_nsclient nsclient queries execute check_pdh "counter=\\Processor(_Total)\\% Processor Time"
Note
This is a Windows feature and needs the CheckSystem module. On Linux the agent has no PDH subsystem and the command fails:
Error: Failed to fetch performance counters: Invalid response status from api/v2/metadata/counters: 500 Internal Server Error: No response from module, is the CheckSystem module loaded?Enumerating every counter on a Windows host can take a long time. Raise the timeout if the default is not enough:
check_nsclient nsclient --timeout-s 300 metadata counters.
See Performance counters (PDH) for what to do with them.
metadata channels¶
The submission channels modules have registered. A channel is the target name a passive check, a scheduled job or an external script submits its result to; the agent then dispatches the payload to the listening module.
$ check_nsclient nsclient metadata channels
╭────────┬───────────────────────────╮
│ name │ plugins │
├────────┼───────────────────────────┤
│ nsca │ NSCAClient │
│ submit │ Op5Client, GraphiteClient │
╰────────┴───────────────────────────╯
plugins is a list because more than one module can listen on the same
channel, as submit shows above; every submission is then delivered to all of
them.
A stock agent has no submission clients loaded and therefore no channels — the table is empty until you enable something like NSCAClient or GraphiteClient.
This is how you verify that a passive monitoring setup is wired up before sending anything:
$ check_nsclient --output json nsclient metadata channels | jq -r '.[].name'
nsca
submit
Note
The built-in pseudo-channels handled by the core itself —
noop(discard) andlog(write to the agent log) — are not listeners and do not appear here, but remain valid submission targets.
Events¶
The agent buffers notable occurrences — event log hits, real-time filter
matches — in an event store. check_nsclient nsclient events … reads and
drains it, which lets a poller collect what happened without keeping a
connection open.
events list¶
Shows the buffered events without removing them:
$ check_nsclient nsclient events list
╭───────┬──────────────────────┬──────────┬─────────────────────────────────────────╮
│ index │ date │ event │ data │
├───────┼──────────────────────┼──────────┼─────────────────────────────────────────┤
│ 1 │ 2026-Aug-30 15:52:03 │ eventlog │ id=7036, source=Service Control Manager │
│ 2 │ 2026-Aug-30 15:52:41 │ eventlog │ id=1074, source=User32 │
╰───────┴──────────────────────┴──────────┴─────────────────────────────────────────╯
| Column | Meaning |
|---|---|
index |
Position in the store, increasing. |
date |
When the event was recorded. |
event |
What produced it, for example eventlog. |
data |
The event payload, flattened to key=value pairs for the table. |
In json the payload keeps its structure:
$ check_nsclient --output json nsclient events list
[
{
"index": 1,
"event": "eventlog",
"date": "2026-Aug-30 15:52:03",
"data": {
"source": "Service Control Manager",
"id": "7036"
}
}
]
A stock agent produces no events — the store fills only when something feeds it, such as CheckEventLog real-time filters or real-time system monitoring. Until then the list is empty.
events clear¶
Drains the store and prints what it removed:
$ check_nsclient nsclient events clear
╭───────┬──────────────────────┬──────────┬─────────────────────────────────────────╮
│ index │ date │ event │ data │
├───────┼──────────────────────┼──────────┼─────────────────────────────────────────┤
│ 1 │ 2026-Aug-30 15:52:03 │ eventlog │ id=7036, source=Service Control Manager │
│ 2 │ 2026-Aug-30 15:52:41 │ eventlog │ id=1074, source=User32 │
╰───────┴──────────────────────┴──────────┴─────────────────────────────────────────╯
Note
clearis a drain, not a discard: the events it returns are gone from the agent. Capture the output if you need it — runningclearand ignoring what it prints loses those events permanently.
Because of that, clear is really “fetch and acknowledge”, which is how you
poll the store without processing anything twice:
$ check_nsclient --output json nsclient events clear >> /var/log/nscp-events.jsonl
A second run finds nothing:
$ check_nsclient --output json nsclient events clear
[]
Use list when you only want to look, and clear when you are
consuming.
Tags¶
Tags are small name = value facts an agent reports about the host it runs on
— which drives exist, which operating system it is, whether a particular
product was detected. They are contributed at runtime by the loaded modules and
by the core itself, and are read by the web interface and by fleet
synchronisation.
tags show¶
$ check_nsclient nsclient tags show
╭────────────┬─────────────────╮
│ drives │ c:,d: │
│ os_name │ Windows 11 24H2 │
│ os_version │ 10.0.26200 │
╰────────────┴─────────────────╯
Tags are listed in alphabetical order. Which ones exist depends entirely on
which modules are loaded — CheckDisk contributes drives, CheckSystem
contributes the operating system tags, and so on. An agent whose loaded modules
report nothing says so rather than printing an empty table:
$ check_nsclient nsclient tags show
No tags set
In json the tags are returned as an object, which stays {} when there are
none, so a script does not have to special-case the message:
$ check_nsclient --output json nsclient tags show
{
"drives": "c:,d:",
"os_name": "Windows 11 24H2",
"os_version": "10.0.26200"
}
Reading a single tag:
$ check_nsclient --output json nsclient tags show | jq -r .os_name
Windows 11 24H2
Note
Tags are read-only over the API and are not configuration — there is no
tags set, and nothing you write under/settingsshows up here. A module publishes a tag through the plugin API (NSAPISetTag), so the way to add one is to load a module that reports it.
Using tags¶
Tags are a cheap inventory when you drive several agents from one place:
$ for profile in web-01 web-02 db-01; do
> os=$(check_nsclient --output json nsclient --profile $profile tags show | jq -r '.os_name // "unknown"')
> echo "$profile runs $os"
> done
Because the values come from the agent itself they stay correct without a separate inventory step — a host that gains a drive reports it on the next poll.
Interactive client¶
check_nsclient nsclient client opens a terminal UI connected to an agent: a
live CPU and memory bar chart at the top, a log and output pane in the middle,
and a command prompt at the bottom. It is meant for exploring an agent — trying
checks, watching the log react, loading a module — without retyping a full
command line each time.
$ check_nsclient nsclient client
check_nsclient nsclient test is a legacy alias for the same thing.
Layout¶
| Area | Content |
|---|---|
| Top | Bar chart of CPU user, CPU kernel and memory usage, refreshed every 5 seconds. |
| Middle | Command output and the agent log, streamed as it arrives, coloured by level. |
| Bottom | Command prompt. |
The bars turn yellow above 50% and red above 80%.
New log records are fetched continuously, so a check that logs an error shows it immediately underneath the output.
Commands¶
Type a command and press Enter.
| Command | Description |
|---|---|
help |
List the available commands. |
ping |
Check that the agent is reachable. |
version |
Show the agent version. |
queries (or list) |
List every available check command. |
query <name> [k=v ...] |
Run a check. |
<name> [k=v ...] |
Run a check directly — the query keyword is optional. |
modules (or plugins) |
List modules with a ✓ for the loaded ones. |
modules load <module> |
Load a module (also load <module>). |
modules unload <module> |
Unload a module (also unload <module>). |
refresh |
Re-read the status and the list of available checks. |
history |
Show the command history. |
history clear |
Empty the history. |
history delete <index> |
Remove one entry. |
exit |
Leave the client (or press Esc). |
Any check command can be typed on its own, so the two lines below are equivalent:
query check_cpu warning=90
check_cpu warning=90
Arguments use the same key=value form as
queries execute. Values containing spaces can
be quoted, and \ escapes the next character:
check_drivesize "drive=C:\" warning=used>80%
Editing and history¶
| Key | Action |
|---|---|
| Up / Down | Walk through the command history. |
| Left / Right | Move the cursor (also Ctrl+B / Ctrl+F). |
| Home / End | Jump to the start or end (also Ctrl+A / Ctrl+E). |
| Backspace / Del | Delete a character (also Ctrl+H / Ctrl+D). |
| Enter | Run the command. |
| Esc | Exit. |
The prompt validates as you type: a command the agent knows is marked as valid, an unknown one as invalid, so a typo is visible before you press Enter.
Only commands that parse are recorded. A half-typed line you abandon by pressing Up is remembered while you browse and restored when you come back past the newest entry, but it never enters the history.
The history holds the last 30 commands and is stored with the rest of the client configuration, so it survives between sessions.
When to use the CLI instead¶
The interactive client is for exploration. For anything scripted — monitoring
integration, automation, structured output — use the ordinary commands, which
support --output json and set meaningful exit codes.