Passive Monitoring with NSCA-NG¶
Goal: Have NSClient++ run checks on a schedule and push results to an NSCA-NG server using TLS-PSK authentication — the modern, encrypted replacement for the legacy NSCA daemon.
NSCA vs. NSCA-NG vs. NRDP
All three solve the same problem (push results from agent → server). Pick by what your monitoring server supports:
How NSCA-NG Works¶
NSClient++ runs checks on a schedule and pushes the results to the NSCA-NG server over a TLS-PSK connection:
flowchart LR
S[Scheduler] -->|runs check| C[NSCANgClient]
C -->|TLS-PSK<br/>port 5668| N[NSCA-NG server]
N --> P[external_command_pipe]
P --> M[Nagios / Icinga core]
The agent opens a TLS connection to the server (default port 5668),
authenticates with a Pre-Shared Key (PSK), then exchanges a small text
protocol:
sequenceDiagram
participant C as Client
participant S as Server
C->>S: TLS handshake (PSK)
C->>S: MOIN 1 session-id
S-->>C: OKAY
C->>S: PUSH length
S-->>C: OKAY
C->>S: PROCESS_SERVICE_CHECK_RESULT#59;host#59;svc#59;code#59;output
S-->>C: OKAY
C->>S: QUIT
S-->>C: OKAY
Each PUSH carries one Nagios external command. The server appends it to its
configured command file (Nagios/Icinga’s external_command_pipe) and the
monitoring core picks it up like any other passive check.
Prerequisites¶
[/modules]
CheckSystem = enabled ; provides check_cpu, check_memory, etc.
CheckDisk = enabled ; provides check_drivesize
Scheduler = enabled ; runs checks on a timer
NSCANgClient = enabled ; pushes results via NSCA-NG
You also need an NSCA-NG server reachable on port 5668 (default), with a
matching PSK identity + password configured. A typical server snippet
(nsca-ng.cfg):
listen = "*:5668"
command_file = "/usr/local/nagios/var/rw/nagios.cmd"
authorize "agent01" {
password = "shared-secret-do-not-use-in-production"
hosts = [ "^agent01$" ]
services = [ "^agent01;" ]
}
The authorize block needs at least one pattern
An authorize block with only a password accepts the TLS-PSK handshake
but rejects every submission with FAIL — nsca-ng only accepts what a
hosts, services, or commands pattern explicitly allows. The
hosts patterns are matched against the host name of submitted host-check
results, and services against host;service of service-check results;
anchor them (^...$ / ^...;) so agent01 doesn’t also authorize
agent012.
Least privilege: avoid a wildcard commands pattern
The commands patterns authorize raw Nagios external commands — a
wildcard like commands = [ ".*" ] lets anyone holding that PSK submit
any command to the monitoring core (SHUTDOWN_PROGRAM,
DISABLE_NOTIFICATIONS, scheduling downtime, …), so a single compromised
agent can silence or steer your whole monitoring. Stick to hosts /
services patterns scoped to the agent’s own name, as above, and give
every agent its own identity and password so one leaked key doesn’t
authorize the whole fleet.
Treat the PSK password as a key, not a password
With the plain-PSK TLS ciphersuites there is no forward secrecy, and an
attacker who records one handshake can test password guesses offline at
leisure — a guessable password undoes the transport security entirely.
Generate a long random secret (for example openssl rand -base64 32) and
use that as the password on both ends. The PSK identity travels in
clear text during the handshake, so don’t put anything sensitive in it.
Step 1 — Verify the Connection¶
Before wiring up the scheduler, push a single test result from the agent:
nscp nsca-ng --host <server> --password "shared-secret-do-not-use-in-production" \
--identity "agent01" \
--hostname "agent01" \
--command "test_service" \
--result 0 --message "hello from NSClient++"
Expected output:
Submission successful
Keep the password out of the command line in production
Arguments are visible to every local user in the process listing (ps,
Task Manager) and may land in shell history, so passing --password on
the command line is for one-off connectivity tests only. Production
setups put the password in the target definition (Step 2), which also
keeps it out of scheduled-task definitions and scripts.
If you get a TLS handshake failure, the most common causes are (in order):
- Wrong password — the agent’s
passwordand the server’spasswordfor the matchingauthorizeblock must be byte-identical. - Wrong identity — the agent’s
--identitymust match anauthorizeblock on the server. By default the identity is the agent’s hostname. - The server only supports TLS 1.3 PSK — NSClient++ uses the legacy
SSL_CTX_set_psk_client_callbackAPI, which requires TLS 1.2. NSClient++ forces TLS 1.2 automatically whenuse psk = true; if the server is configured for TLS 1.3-only PSK, switch the server (or configure the agent for cert-based TLS instead, see below).
Step 2 — Configure a Target¶
[/settings/NSCA-NG/client/targets/default]
address = nsca-ng.example.com
port = 5668
identity = agent01
password = shared-secret-do-not-use-in-production
timeout = 30 ; per-operation timeout (connect/read/write)
retries = 2 ; total attempts = retries + 1
host check = false ; submit as service check by default
max output length = 65536 ; clamp on plugin output (bytes)
address, identity, and password are mandatory. Everything else has
sensible defaults; port defaults to 5668, timeout to 30s,
retries to 2, host check to false, max output length to 64 KiB.
Cert-based TLS instead of PSK¶
If your server uses X.509 certificates rather than PSK:
[/settings/NSCA-NG/client/targets/default]
address = nsca-ng.example.com
use psk = false
ca = ${certificate-path}/ca.pem
certificate = ${certificate-path}/agent.pem
certificate key = ${certificate-path}/agent.key
verify mode = peer-cert
When use psk = false the connection uses TLS 1.2 or 1.3 with the standard
verify chain — no PSK ciphersuite restriction.
Cert mode now fails closed without peer verification
verify mode (combined with a valid ca) must authenticate the server
when running in cert mode. If the resolved verify mode does not include
peer (for example, the setting is missing, or set to none), the agent
refuses to connect with:
Refusing to connect: TLS peer verification is disabled and PSK is not in
use. Either configure 'verify mode = peer-cert' with a 'ca = <path>',
re-enable 'use psk = true', or set 'insecure = true' to override.
The hostname in address must also match the server certificate’s CN /
SAN; if you connect to an IP literal, the cert needs that IP listed as a
SAN.
Step 3 — Configure the Scheduler¶
Same as the legacy NSCA scenario, but point the channel at NSCA-NG:
[/settings/scheduler/schedules/default]
channel = NSCA-NG
interval = 5m
report = all
[/settings/scheduler/schedules]
host_check = check_ok
cpu = check_cpu
memory = check_memory
disk_c = check_drivesize drive=C: "warn=free < 20%" "crit=free < 10%"
For cron-style schedules, real-time channels (CheckEventLog / CheckLogFile),
and per-schedule overrides see
Passive Monitoring → Step 2 — Configure the Scheduler.
The scheduler machinery is shared; only the channel differs.
Step 4 — Host Checks vs. Service Checks¶
NSClient++ submits service checks by default. Two ways to send a host check:
- Per target: set
host check = trueon the target. Every result submitted on that target becomes aPROCESS_HOST_CHECK_RESULT. - Per schedule (legacy convention): name the schedule
host_check— the result is then automatically submitted as a host check, regardless of the target’shost checksetting:[/settings/scheduler/schedules] host_check = check_ok
The host_check alias was the original way and is preserved for
backwards compatibility.
Step 5 — Restart and Verify¶
net stop nscp
net start nscp
If the server logs received commands, you should see entries like:
[1714973400] PROCESS_SERVICE_CHECK_RESULT;agent01;cpu;0;OK: CPU load is ok.|...
Set NSClient++’s log level to trace to see the full client side, including
the MOIN/PUSH/QUIT exchange:
[/settings/log]
level = trace
Common Gotchas¶
TLS handshake hangs¶
The agent applies the timeout setting to every network operation
(connect, handshake, read, write). If the handshake hangs longer than
timeout seconds the submission fails with TLS handshake timed out and
moves on to the retry, if any. Bump timeout if your network is slow; lower
it if you want faster failover to a different target.
“FAIL bad password”¶
The PSK password and identity must match an authorize block on the
server exactly. Whitespace, case, and trailing newlines all matter.
Handshake succeeds but every submission is rejected with FAIL¶
The credentials are fine — the authorize block on the server has no
hosts / services / commands pattern, or the patterns don’t match what
the agent submits. nsca-ng authorizes each command against those patterns
after authentication, and a block with only a password allows nothing.
Check that services matches the host;service pair the agent sends (the
host name is the agent’s hostname setting / --hostname, which is also
worth checking for a mismatch).
Output truncated¶
The max output length setting (default 64 KiB) clamps how many bytes of
plugin output are forwarded. Long stack traces or eventlog dumps can hit
this — bump the value, or summarise on the agent before sending.
Server-side rejection is not retried¶
Network/TLS failures retry with backoff. Server-side responses (FAIL,
BAIL) are reported back to the caller without retrying — there’s no point
hammering a server that’s actively refusing the credentials.
“Refusing to connect: TLS peer verification is disabled…”¶
You’re running in cert mode (use psk = false) without a verifying chain.
Either set verify mode = peer-cert and supply a working ca, switch back
to PSK with use psk = true, or — only if you understand the MITM risk —
set insecure = true to permit unauthenticated TLS.
Troubleshooting Checklist¶
When a submission fails silently from the monitoring server’s point of view, check these in order:
- Agent log at trace level — does it show
Submission successfulor an error? - Agent log for retry messages —
NSCA-NG attempt N/M failed: ...lines indicate transient network failures. - Server log — most NSCA-NG servers log every accepted command and every PSK rejection.
- Wireshark on port 5668 — TLS records should be visible; if not, the agent isn’t reaching the server (firewall / DNS / port).
nscp nsca-ng --host ...— bypass the scheduler and send a one-off submission to isolate scheduler config from network/auth config.
Next Steps¶
- Passive Monitoring (NSCA/NRDP) — the legacy NSCA / HTTP-based NRDP variants.
- Passive Monitoring (Icinga 2) — Icinga 2’s REST API as a third option.
- Reference: NSCANgClient — every setting in detail.