Skip to content

Active Checks over the REST API

Goal: Run NSClient++ checks from your monitoring server over HTTPS instead of NRPE, using the standalone check_nsclient command line client as the check plugin.

Tip

This is the same pull-style pattern as NRPE — the monitoring server asks, the agent answers — but over the REST API the web UI already uses. If you have no reason to move away from NRPE, there is nothing wrong with staying on it.


How it works

check_nsclient is a self-contained binary that speaks the NSClient++ REST API. Given a query name it calls /api/v2/queries/<name>/commands/execute on the agent, and queries execute-nagios renders the answer the way a Nagios plugin is expected to: one message|perfdata line on stdout, the check status as the exit code.

flowchart LR
    N[Monitoring Server<br/>Nagios / Icinga / Naemon] -->|check_nsclient<br/>HTTPS/8443| W[NSClient++<br/>WEBServer]
    W -->|runs check| R[Result]
    R --> N

Credentials are not passed on the command line. You log in once per agent, which stores an API key in the credential store of the monitoring server, and every later check refers to that stored connection by its profile name.

Why you might want this

NRPE REST API
Port 5666, in addition to the web UI 8443, the one the web UI already uses
Module NRPEServer WEBServer
Credentials Shared transport-level trust (allowed hosts, client certs) Per-user password, exchanged once for a revocable API key
Payload limits Fixed-size buffers, truncation on long output JSON, no protocol-level truncation
Argument handling Guarded by allow arguments / allow nasty characters Guarded by per-user roles
Beyond checks Checks only Also settings, logs, modules, scripts and metrics

The trade-off is that every agent needs the web server enabled and a login performed from the monitoring server — which is more setup than dropping an NRPE stanza into nsclient.ini.


Prerequisites

On each monitored host, the WEBServer module must be enabled with a password set:

nscp web install --https --password <MY SECURE PASSWORD>

The agent must be reachable on port 8443 from the monitoring server, so make sure allowed hosts includes it:

[/settings/WEB/server]
allowed hosts = 10.0.0.0/24

See Using the Web Interface for the full setup, including how to give the agent a certificate that validates.

On the monitoring server, install check_nsclient — a single binary, no runtime dependencies. Put it in the plugin directory so it sits next to your other checks:

$ VERSION=<VERSION>
$ curl -sSLo check_nsclient \
    "https://github.com/mickem/check_nsclient/releases/download/${VERSION}/check_nsclient-${VERSION}-linux-x64"
$ sudo install -m 0755 check_nsclient /usr/lib/nagios/plugins/check_nsclient

On a Windows monitoring host the NSClient++ MSI already installs the client as C:\Program Files\NSClient++\check_nsclient.exe, so there is nothing to download. See Installation for the details.


Logging in to each agent

Run the login as the user the monitoring server runs checks as — the API key lands in that user’s credential store, and a check running as somebody else will not find it:

$ sudo -u nagios /usr/lib/nagios/plugins/check_nsclient nsclient auth login web-01 \
    --url https://web-01.example.com:8443 \
    --password <MY SECURE PASSWORD> \
    --ca /etc/ssl/certs/my-ca.pem
Successfully logged in

web-01 is the profile name. Name profiles after the host so a command definition can build them from $HOSTNAME$.

Credential storage on a headless server

On Linux the credentials go into the Secret Service (libsecret), which needs a running keyring daemon — something a headless monitoring server often does not have. Confirm the login survives a fresh shell before wiring up checks:

$ sudo -u nagios /usr/lib/nagios/plugins/check_nsclient nsclient --profile web-01 ping
Successfully pinged NSClient++ version 0.18.0 2026-08-29

See Where credentials are stored for the details.

Verify what you have with profile list:

$ check_nsclient profile list
╭─────────┬──────────────────────────────────┬──────────┬──────────┬─────────┬───────────┬──────────────╮
│ id      │ url                              │ username │ insecure │ default │ has_token │ has_password │
├─────────┼──────────────────────────────────┼──────────┼──────────┼─────────┼───────────┼──────────────┤
│ web-01  │ https://web-01.example.com:8443  │ admin    │ no       │ yes     │ yes       │ yes          │
│ db-01   │ https://db-01.example.com:8443   │ admin    │ no       │ no      │ yes       │ yes          │
╰─────────┴──────────────────────────────────┴──────────┴──────────┴─────────┴───────────┴──────────────╯

Running a check by hand

Always confirm a check works from the shell before putting it in a configuration file:

$ check_nsclient nsclient --profile web-01 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

Arguments come after the query name, exactly as the check expects them:

$ check_nsclient nsclient --profile web-01 queries execute-nagios \
    check_drivesize drive=/ "warning=used>80%" "critical=used>90%"
OK: All 1 drive(s) are ok|'/ used'=13.7GB;80.5;90.6;0;100.7

The exit codes are the Nagios ones:

Exit code Status
0 OK
1 WARNING
2 CRITICAL
3 UNKNOWN

Not sure what a host offers? Ask it — this is the part NRPE cannot do:

$ check_nsclient nsclient --profile web-01 queries list
$ check_nsclient nsclient --profile web-01 queries show check_drivesize

Nagios server-side configuration

One command definition covers every check, because the query name is an argument:

define command {
    command_name    check_nscp_rest
    command_line    $USER1$/check_nsclient nsclient --profile $HOSTNAME$ queries execute-nagios $ARG1$
}

define command {
    command_name    check_nscp_rest_args
    command_line    $USER1$/check_nsclient nsclient --profile $HOSTNAME$ queries execute-nagios $ARG1$ $ARG2$
}

With profiles named after the host, the service definitions stay short:

define service {
    use                     generic-service
    host_name               web-01
    service_description     CPU Load
    check_command           check_nscp_rest!check_cpu
}

define service {
    use                     generic-service
    host_name               web-01
    service_description     Disk Space
    check_command           check_nscp_rest_args!check_drivesize!drive=/ "warning=used>80%"
}

Add --timeout-s if your checks are slower than the default 30 seconds, and keep it below the monitoring server’s own plugin timeout:

    command_line    $USER1$/check_nsclient nsclient --profile $HOSTNAME$ --timeout-s 20 queries execute-nagios $ARG1$

Icinga 2

The same plugin, expressed as an Icinga 2 CheckCommand:

object CheckCommand "nscp_rest" {
  command = [ PluginDir + "/check_nsclient" ]

  arguments = {
    "nsclient" = { skip_key = true; order = 0 }
    "--profile" = { value = "$nscp_rest_profile$"; order = 1 }
    "queries" = { skip_key = true; order = 2 }
    "execute-nagios" = { skip_key = true; order = 3 }
    "query" = { skip_key = true; value = "$nscp_rest_query$"; order = 4 }
  }

  vars.nscp_rest_profile = "$host.name$"
}

apply Service "cpu" {
  check_command = "nscp_rest"
  vars.nscp_rest_query = "check_cpu"
  assign where host.vars.nscp_rest
}

Rolling it out to many hosts

Logging in is a one-time step per agent, so a loop over your inventory is usually enough:

$ for host in web-01 web-02 db-01; do
>   sudo -u nagios /usr/lib/nagios/plugins/check_nsclient nsclient auth login "$host" \
>       --url "https://${host}.example.com:8443" \
>       --password "$NSCP_PASSWORD" \
>       --ca /etc/ssl/certs/my-ca.pem
> done

If a key is ever lost or leaked, revoke it on the agent and forget it locally in one step:

$ check_nsclient nsclient --profile web-01 auth logout

Limiting what the monitoring server may do

The API key inherits the permissions of the user it was issued for, so do not point your monitoring server at admin — that account can rewrite the agent’s configuration. NSClient++ ships a built-in monitoring role that grants exactly queries.execute, aliases.list, login.get and metrics.get; give the monitoring server its own user with that role:

[/settings/WEB/server/users/nagios]
password = <A DIFFERENT SECURE PASSWORD>
role = monitoring

Then log in as that user instead of admin:

$ check_nsclient nsclient auth login web-01 --url https://web-01.example.com:8443 \
    --username nagios --password <A DIFFERENT SECURE PASSWORD>

Note

The monitoring role deliberately excludes queries.list and queries.get, so queries list and queries show will fail for this user. Explore with an admin (or client) profile and run the scheduled checks with the restricted one.

See Web server roles for the built-in roles and what each one grants, and Permissions for the separate, agent-wide engine that controls which commands a caller may run at all.


Troubleshooting

Error: NSClient++ profile 'web-01' not found. — the profile does not exist for the user running the check. Re-run auth login under that user (the sudo -u nagios above), not as root.

invalid peer certificate: UnknownIssuer — the agent’s certificate is not signed by anything the monitoring server trusts. Pass --ca with your CA bundle at login time, or --insecure to skip validation (not recommended outside a lab). Adding certificates to NSClient++ covers getting a certificate that validates.

Connection refused / timeout — the WEBServer module is not loaded, the port is firewalled, or allowed hosts excludes the monitoring server. Check from the agent side with nscp test, and see what the client actually did with -d:

$ check_nsclient -d nsclient --profile web-01 ping
[debug] Debug output enabled (level 1)
[debug] GET https://web-01.example.com:8443/api/v2/info
[debug] 200 OK from api/v2/info
Successfully pinged NSClient++ version 0.18.0 2026-08-29

-dd also dumps the body of error responses, which is where NSClient++ puts its explanation.

403 / permission denied on a query — the role of the user the key was issued for does not include queries.execute. See Web server roles.


Next Steps