Skip to content

News

Host security posture, JSON-aware HTTP checks, and a clearer licence

This release adds a brand-new CheckSecurity module for monitoring a host's security posture — certificates, firewall, antivirus, BitLocker, Secure Boot, NLA and logged-on users — and teaches check_http to assert on values inside a JSON response body. It also fixes boolean check arguments over REST, tidies up process aggregation and module activation, relicenses the project under a clear dual licence, and reworks the documentation to handle Windows and Linux side by side.

Highlights

  • New CheckSecurity module. Seven new checks for host security posture: check_certificate, check_firewall, check_antivirus, check_bitlocker, check_secureboot, check_nla and check_users. check_certificate and check_users run everywhere; the rest are Windows-only. (#1339)
  • check_http can assert on JSON responses. New json-path=alias:path options extract values from a JSON body into filter keywords you can threshold on and emit as perfdata. (#1341)
  • CheckNet queries now emit performance data by default, so check_http, check_tcp and friends graph out of the box without an explicit perf syntax. (#1341)
  • Boolean check arguments accept values, not just flags. check_ping host=www.google.com total=true now works alongside the bare-flag form — the form REST already used. (#1338)
  • Activate several modules in one command: nscp settings --active-module CheckSystem CheckNet. (#1329-follow-up)
  • Clear dual licence. NSClient++ is now Apache-2.0 OR GPL-2.0-only, with machine-readable REUSE metadata and third-party notices. (#1343)
  • Reworked, multi-OS documentation that presents Windows and Linux options and features together instead of assuming one platform. (#1342)

Detailed changes

CheckSecurity — new host security-posture module

A new module, CheckSecurity (alias security), checks whether a host is in the security state you expect. Each check is a normal modern_filter check, so you can override the default warn/crit expressions, filter, and detail-syntax/top-syntax as usual.

Command Platforms What it checks
check_certificate All X.509 certificate expiry / validity / hygiene from files or the Windows store
check_users Windows + Linux Count and detail of logged-on / RDP sessions
check_firewall Windows only Firewall profile (Domain/Private/Public) enabled and active state
check_antivirus Windows only Registered antivirus products' enabled / up-to-date state (Security Center)
check_bitlocker Windows only BitLocker drive-encryption protection status per volume
check_secureboot Windows only Whether UEFI Secure Boot is enabled (distinguishes "disabled" from "legacy")
check_nla Windows only Network Location Awareness category (public/private/domain) per network

check_certificate defaults to warning when a certificate expires within 30 days and critical within 10 (matching common practice), emits expires_in (whole days until expiry) as perfdata, and can scan a whole directory:

check_certificate file=/etc/ssl/certs/mysite.pem
check_certificate file=/etc/ssl/certs recursive=true "detail-syntax=${subject}: ${expires_in}d"
check_certificate file=/etc/pki/tls/certs critical=expired=1

The Windows checks expose the raw state fields so you can tighten or relax the default posture. check_firewall adds an active flag (which profile is currently in effect) alongside enabled, so you can warn when a machine silently falls back to the Public profile after a network change:

check_firewall "warn=active = 1 and profile = 'Public'" "detail-syntax=${profile} profile is active"
check_secureboot "warn=supported = 0" "crit=supported = 1 and enabled = 0"
check_nla "crit=connected = 1 and category != 'domain'" "detail-syntax=${network}=${category}"

On a platform where a Windows-only check does not apply, the check returns UNKNOWN with a clear message rather than failing.

CheckNet — check_http JSON path extraction

check_http can now pull values out of a JSON response body and treat them as filter keywords. Each json-path=alias:path option extracts the value at a dotted path (numeric segments index into arrays; single-quote a segment that itself contains a dot) and makes it available for warning=/critical= expressions and perfdata:

check_http url=https://api.example.com/health "json-path=qlen:data.queue.length" "crit=qlen > 100"
check_http url=https://api.example.com/health "json-path=st:status" "crit=st != 'ok'"
check_http url=https://api.example.com/health "json-path=err:metrics.error_rate" "warn=err > 0.01" "crit=err > 0.05"
check_http url=https://api.example.com/health "json-path=first:items.0.name" "json-path=cfg:'a.b'.c"

Numeric values keep full precision, strings compare and render as strings, and booleans read as 1/0. A missing path — or a body that is not valid JSON — leaves the alias empty rather than failing the check, and multiple json-path options can be combined freely.

CheckNet — default performance data

CheckNet queries now attach sensible performance data by default, so check_http, check_tcp and the other network checks produce graphable perfdata without a hand-written perf syntax. check_ntp_offset threshold handling was also tidied up in the same change.

Check arguments — boolean options accept values

Boolean check options now accept an explicit value in addition to the bare-flag form:

check_ping host=www.google.com total=true

Previously the value form was rejected from the CLI even though REST always passes flags as key=true tokens, so a boolean option that worked over REST could look broken from the command line. Both forms now behave identically.

CheckSystem — process total aggregation

check_process process-total aggregation now correctly reports the started and hung states (on both Windows and Linux), so totals of these statuses match what the per-process detail shows.

Settings — activate multiple modules at once

nscp settings --active-module now accepts several module names in one invocation:

nscp settings --active-module CheckSystem CheckNet

Licensing — dual-licensed Apache-2.0 OR GPL-2.0-only

NSClient++ is now explicitly dual-licensed under Apache-2.0 OR GPL-2.0-only. Source headers were updated to SPDX identifiers, the project carries machine-readable REUSE metadata (REUSE.toml, LICENSES/), and a THIRD-PARTY-NOTICES.md / NOTICE collect the third-party licences. The installer, packaging and docs licence text were updated to match.

Build — Python library discovery

CMake now derives the default Python library name instead of hardcoding a version, and defaults it to the soname so the module loads without the Python development packages installed. This makes Linux builds far less sensitive to the exact Python version on the build and target hosts. (#1334)

Documentation

  • Multi-OS reference docs. The reference documentation was reworked to present Windows and Linux options and features together, handling checks whose options diverge by platform instead of documenting a single OS. Windows docs were regenerated. (#1342)
  • New docs/samples/ usage examples and descriptions for every new CheckSecurity command and the check_http JSON feature.
  • check_process docs cross-reference filter_perf for top-N processes. (#1330)
  • README restructured and dead files removed. (#1340)

Quality and CI

  • Spelling. A codespell GitHub workflow was added and spelling errors in log messages and settings descriptions were fixed. (#1314, #1344)
  • Live integration tests. A new opt-in test suite runs checks against a real VM in Azure, alongside the existing REST-driven integration tests. New integration tests cover CheckSecurity, the check_http JSON feature, and --active-module. (#1335)
  • Assorted build fixes for older Windows toolchains, Linux, and sanitizer runs.

Upgrade notes

  • Licence change: NSClient++ is now distributed as Apache-2.0 OR GPL-2.0-only. This is a clarification/relicensing — review it if your organisation tracks the exact licence of bundled software. No code or runtime behaviour changes as a result.
  • CheckNet perfdata is now on by default. Network checks emit performance data without an explicit perf syntax. If you were adding perfdata manually, double-check you are not now emitting it twice; graphs that previously showed nothing will start populating.
  • Boolean check arguments: option=true / option=false now work from the CLI as well as over REST. Existing bare-flag usage is unchanged.
  • CheckSecurity is not loaded by default. Enable it before using the new checks, e.g. nscp settings --active-module CheckSecurity. Windows-only checks return UNKNOWN on other platforms rather than erroring.

Download

You can download the new version from GitHub

// Michael Medin

0.14.0 Linux parity

This release brings Linux up to near-parity with Windows and completes the Linux story that began in 0.13.0. On the checks side it adds a full suite of Linux-native system checks (CheckSystemUnix) sourced directly from /proc and /sys, event-driven real-time monitoring on Linux, Linux disk / file / mount support in CheckDisk, and a round of cross-platform CheckNet improvements — TLS for check_tcp, a fuller check_http, multi-record-type DNS, and two new network checks. Around the daemon it delivers , a secure-by-default web server, one-command installs via winget / Chocolatey / Scoop and nscp web install-ui, and a broad set of security and reliability fixes. It also hardens plugin shutdown so a misbehaving module can no longer crash the service on exit.

🌟 Highlights

  • Linux system checks (CheckSystemUnix). New native checks — check_load, check_cpu_utilization, check_kernel_stats, check_swap_io, check_cpu_frequency, check_temperature, check_battery, check_network — plus overhauled check_process (with process history / delta CPU) and a systemd-aware check_service. All read /proc and /sys directly, with thresholds and syntax that match their Windows counterparts.
  • Real-time monitoring on Linux. CheckSystemUnix gains an event-driven real-time thread, so CPU, memory and process alerts can fire the moment a threshold is crossed rather than only on poll — the same real-time model previously available only on Windows.
  • Disk, file and mount checks on Linux (CheckDisk). CheckDisk is no longer Windows-only: free-space (check_drivesize), file (check_files) and disk-I/O checks now run on Linux, with per-device I/O sampling from /proc/diskstats, LVM / device-mapper mapping, inode statistics, file-integrity checksums, and a new check_mount.
  • TLS-aware network checks (CheckNet). check_tcp now speaks TLS (ssl=true) with new SPOP / SIMAP / SSMTP presets; check_http gains redirect policy, certificate-expiry reporting, Basic auth, SNI and non-GET methods; check_dns queries any record type against a custom resolver; and two new checks arrive — check_ssh and check_nsclient_web_online.
  • First-class Linux packaging. The build follows the FHS / CMAKE_INSTALL_PREFIX, with official .deb/.rpm targeting /usr, and a Boost.Beast web backend by default.
  • One-command installs everywhere. Windows via winget / Chocolatey / Scoop; the Linux web UI via nscp web install-ui.
  • Secure by default. The web server refuses to serve cleartext HTTP without an explicit opt-in, plus check_nt command allow-listing and stricter external-script argument checks.
  • Run Lua scripts straight from the CLI with nscp lua execute, backed by Lua thread-safety hardening.
  • Safer plugin shutdown. The plugin manager isolates broken plugins and tears modules down cleanly, so a module that fails to unload can no longer take the service down on shutdown.

📖 Detailed changes

🐧 CheckSystemUnix — native Linux system checks

A new family of checks reads Linux kernel state directly. Thresholds and detail-syntax keywords mirror the Windows checks so alerts port across platforms.

Command Source What it reports
check_load /proc/loadavg 1/5/15-minute run-queue averages; load shortcut; percpu=true scaling
check_cpu_utilization /proc/stat (~1s sample) Per-mode breakdown — user, system, iowait, steal, idle, total
check_kernel_stats /proc/stat, /proc/loadavg Context-switch rate, fork/process-creation rate, live thread count
check_swap_io /proc/vmstat Swap paging rates (swap_in/swap_out pages/s and bytes/s)
check_cpu_frequency /sys cpufreq Current / max / min CPU frequency
check_temperature thermal zones + hwmon Thermal-zone and hwmon sensor temperatures
check_battery /sys power_supply Charge level, power source, health
check_network /proc/net/dev + sysfs Per-interface link status and throughput
check_load "warn=load5 > 4" "crit=load5 > 8"
check_cpu_utilization "warn=iowait > 20" "crit=iowait > 50"
check_swap_io "warn=swap_out > 100" "crit=swap_out > 1000"
check_kernel_stats "warn=current > 8000" "crit=current > 10000"

⚙️ CheckSystemUnix — check_process history and check_service on systemd

  • check_process now tracks process history and computes delta CPU between samples (rather than lifetime CPU), and exposes memory keywords (rss, vms), matching the Windows process semantics.
  • check_service now inspects systemd units. The raw systemd state is mapped to a normalised state keyword so thresholds read the same as on Windows, while the raw fields (active, sub_state, preset) are exposed too. The default critical expression is ( state not in ('running', 'oneshot', 'static') or active = 'failed' ) and preset != 'disabled' — so a stopped-but-disabled unit stays OK while an enabled unit that failed is CRITICAL. Per-unit process metrics (rss, vms, cpu, tasks, age) are parsed from /proc for the unit's main process.
check_service service=cron "detail-syntax=${name}=${state} active=${active} preset=${preset}"
check_service service=mysql "warn=rss > 1G" "crit=rss > 2G"
  • check_os_version now parses /etc/os-release and reports the distribution and kernel details.

⚡ CheckSystemUnix — real-time monitoring

CheckSystemUnix gains a real-time collection thread and real-time data model, bringing event-driven checks to Linux. CPU, memory and process real-time filters evaluate continuously and emit the moment a threshold is crossed, matching the Windows real-time behaviour. See the Real-Time System Monitoring scenario, now cross-platform.

💾 CheckDisk — now on Linux: disk metrics, inodes, checksums, and check_mount

CheckDisk is no longer Windows-only. Linux builds gain the core free-space and file checks (check_drivesize, check_files) plus disk-I/O sampling, and this release adds:

  • Linux disk I/O. check_disk_io and check_disk_health now sample per-device I/O from /proc/diskstats once per second on Linux (mirroring the Windows PDH path). LVM / device-mapper and RAID volumes are mapped back to their backing devices via sysfs, so space and I/O join correctly for /dev/mapper/… filesystems. The first query after startup can return UNKNOWN while the collector takes its first sample.
  • Inode statistics. check_drivesize exposes inodes_total, inodes_free, inodes_used, inodes_free_pct and inodes_used_pct, so you can catch inode exhaustion (free bytes but no free inodes).
  • File-integrity checksums. check_files exposes md5_checksum, sha1_checksum, sha256_checksum, sha384_checksum and sha512_checksum, computed lazily only when referenced.
  • check_mount (new). Verifies a filesystem is mounted — and optionally that it is mounted with the expected type and options — reading the live mount table (/proc/self/mounts). A path that is not mounted is CRITICAL; a fstype or missing-options mismatch is WARNING.
check_drivesize drive=/ "warn=used>80%" "crit=used>90%"
check_drivesize drive=/ "warn=inodes_used_pct > 85" "crit=inodes_used_pct > 95"
check_files path=/var/log pattern=*.log "crit=size>100M"
check_mount mount=/data fstype=ext4

(Some Windows-only legacy CheckDisk commands are not registered on Linux.)

🔐 CheckNet — TLS for check_tcp

check_tcp can now establish a TLS session over the connected socket (ssl=true), with tls-version (default tlsv1.2+), verify (default none) and ca options, and a response regex to match the server's greeting. Three new TLS service presets ship alongside the existing plaintext ones:

Preset Port TLS Expected greeting
SPOP 995 yes ^\+OK
SIMAP 993 yes ^\* OK
SSMTP 465 yes ^220
check_tcp host=pop.example.com ssl=true "response=^\+OK"
check_tcp host=imap.example.com SIMAP

Peers that close the TLS session without a close_notify (reported by OpenSSL as stream_truncated) are now treated as a clean end-of-data rather than a read failure.

🌐 CheckNet — check_http features

check_http gains the features needed for real service checks:

  • Redirect policyonredirect=ok|follow (default ok) with max-redirs (default 15); follows 301/302/303/307/308.
  • Certificate expiry — reports ssl_expiry_days (days until the served certificate expires) for HTTPS targets.
  • Authenticationusername / password send an HTTP Basic Authorization header.
  • Methods and bodiesmethod= (HEAD/POST/…), post-data, content-type; supplying post-data with a GET promotes the request to POST.
  • SNIsni= overrides the TLS server name / verification host.
check_http url=https://example.com method=HEAD
check_http url=https://example.com username=user password=secret
check_http url=http://example.com/old onredirect=follow
check_http url=https://example.com "warn=ssl_expiry_days < 30" "crit=ssl_expiry_days < 7"

🔎 CheckNet — check_dns record types and custom server

check_dns now queries any record type (type=A|AAAA|MX|TXT|NS|CNAME|SOA|PTR|SRV) and can direct the query at a specific resolver (server=), rather than only resolving an A record against the system resolver.

check_dns host=example.com type=MX server=8.8.8.8

🔑 CheckNet — check_ssh (new)

Connects to an SSH port and validates the protocol banner (implemented on top of the check_tcp service-preset machinery). Flags a server that fails to present a valid SSH-2.0 / SSH-1.x identification string.

check_ssh host=server.example.com
check_ssh host=server.example.com port=2222

📡 CheckNet — check_nsclient_web_online (new)

Verifies that a remote NSClient++ agent's REST/WEB endpoint is reachable and that credentials authenticate — a lightweight liveness probe for the agent's management interface. Reports the base URL and distinguishes "unreachable" from "authentication failed (HTTP 401/403)".

check_nsclient_web_online url=https://agent:8443 password=... verify=none

This command is deliberately named _online because it only checks reachability. A future check_nsclient_web will run actual remote checks through the endpoint.

🌙 Lua — run scripts straight from the command line

nscp lua execute runs a Lua script directly from the CLI — useful for developing and debugging check scripts without wiring them into the configuration first:

nscp lua execute --script myscript.lua

Lua also got thread-safety hardening (a proper GIL), new helpers for targeted and forwarded queries, clearer errors when a script fails to load, and log lines that report the actual script line number.

🔏 TLS — outbound SNI and Op5 client options

  • SNI is now sent on outbound TLS connections (Graphite and the generic TLS client), so a TLS proxy hosting several certificates returns the right one.
  • The Op5 client gained explicit TLS settings:
[/settings/op5/client/targets/default]
tls version = 1.2+
verify mode = peer
ca = ${ca-path}

🔒 Security — secure-by-default web server and hardening

  • The web server refuses to run unencrypted by default. To stop NSClient++ from silently serving the REST API / web UI over plain HTTP, the WEB server now refuses to start without a certificate unless you explicitly opt in with allow insecure = true (see Upgrade notes).
  • check_nt can now be restricted to specific commands. The legacy check_nt protocol is password-only (and source-IP filtering is spoofable), so you can now limit which of its ten request codes are answered. The default is any (unchanged behaviour):
[/settings/NSClient/server]
# Answer only harmless system metrics; deny arbitrary counter/file reads
# and service/process enumeration:
allow = metrics, info

A request outside the list is rejected with ERROR: Command not allowed. - Stricter shell-metacharacter checks in external scripts. User-supplied argument values containing more shell metacharacters are now rejected. - Graphite metric paths are sanitized before being written to the line protocol, preventing injection of extra metrics. - Python sys.path handling hardened to prevent code-injection via path manipulation.

🪟 Windows — winget / Chocolatey / Scoop packages

NSClient++ is now published to the common Windows package managers:

winget install Mickem.NSClient
choco install nsclient   # Still pending approval
scoop install nsclient   # still pending approval

📦 Linux packaging — FHS layout and install prefix

The Linux build honours CMAKE_INSTALL_PREFIX like a normal CMake project, and the official .deb/.rpm are built for /usr. The file layout is now:

What Location
Daemon /usr/sbin/nscp
Modules /usr/lib/nsclient/modules
Private libs /usr/lib/nsclient
Config /etc/nsclient
State / logs /var/lib/nsclient · /var/log/nsclient

If you previously patched hardcoded paths to build for a custom location, that is no longer needed — pass -DCMAKE_INSTALL_PREFIX=/opt/nsclient (or the standard CMAKE_INSTALL_*DIR knobs) instead. To point an already-installed daemon at a boot.ini in a non-standard place there is a new override:

nscp service --run --path-override boot-conf=/etc/nsclient/boot.ini

🖥️ Linux — web UI is a separate download (.deb / .rpm)

The Linux packages no longer bundle the React/Vite web frontend (Debian/Fedora policy forbids npm install during package builds). The daemon, REST API, NRPE/NSCA listeners and every check module are still in the package — only the browser UI ships separately. After installing the package, fetch the matching UI bundle as root:

sudo nscp web install-ui      # downloads + verifies NSCP-Web-<version>.zip
sudo nscp web ui-status       # show installed version / source
sudo nscp web uninstall-ui    # remove only what install-ui put down

Until you do, the web port shows a small built-in placeholder page; the REST API and all listeners work normally without it. The Windows MSI still bundles the UI inline.

🧩 Core — filter summary-variable rendering

All check filters now prefer summary variables during summary rendering. Previously a keyword that exists both per-item and as a summary aggregate (notably status) could render the last item's value in the summary line, making the overall status read incorrectly. Summary context now resolves to the summary value, so top-syntax reports the aggregate correctly.

🛡️ Service — safer plugin shutdown

The plugin manager now handles broken plugins defensively and prevents a module that misbehaves during teardown from crashing the service on shutdown. Modules get a clean teardown path so listeners and background threads stop before unload.

📈 collectd client — encoding and protocol fixes

Correct (little-endian) gauge encoding, working IPv6 multicast, a configurable send interval (default 10s), and previously dropped metric types (counter / derive / absolute) are now mapped instead of discarded.

🐛 Bug fixes

  • Fixed a Windows build break introduced during the Linux work.
  • Fixed regressions where some metrics and real-time checks stopped reporting.
  • Corrected check_ntp_offset threshold handling and improved default accuracy.
  • Improved check_connections performance-data accuracy for total connections.
  • Yet another possible fix for installer deleting config on upgrade.
  • Fix unreliable per-process CPU% from check_process delta=true. The delta calculation for per-process CPU usage produced inconsistent readings; it now returns stable, accurate values.
  • Fix perf-config=none reporting "Failed to parse syntax". Setting perf-config=none to suppress performance-data formatting no longer fails parsing.
  • Fixed http(s) headers should be case-insensitive.
  • IPv6: listeners set IPV6_V6ONLY on Linux to avoid port conflicts with IPv4, and IPv6 address resolution was improved.
  • Thread-safety: logger subscriber management, the scheduler, and timer callbacks were made properly thread-safe; CommandClient now shuts down gracefully on POSIX signals.
  • check_mk server: fixed a memory leak.

🚚 Packaging & distribution notes

  • The bundled check_nsclient Nagios plugin moved to its own repository (mickem/check_nsclient) and is pulled in at build time. This only matters if you build from source.
  • Package/file names were normalised — double-check the exact asset name on the releases page if you script downloads.
  • Reduced Linux build dependencies: the build now uses libzip (instead of vendored Miniz), can use the system Google Test, and degrades cleanly when an optional dependency is missing. Linux uses the Boost.Beast web backend by default.

📚 Documentation and tests

  • New Linux Server Health scenario, plus updated cross-platform Network Checks, Disk Space Alerting, Service & Process Monitoring and Real-Time System Monitoring scenarios.
  • New docs/samples/ usage examples and clarifying descriptions for every new command.
  • Extensive new unit tests (CheckSystemUnix, CheckDisk unix, CheckNet) and REST-driven integration tests under tests/ covering the new system, disk and network checks.

⚠️ Upgrade notes

A few defaults were tightened for security and the Linux packaging layout changed. None of these affect a normal Windows MSI upgrade, but Linux users and anyone running the web server in cleartext should read this section.

  • The web server refuses to run unencrypted by default. If you intentionally run the web server in cleartext (e.g. behind a TLS-terminating proxy, or on an isolated network), set allow insecure = true:
[/settings/WEB/server]
allow insecure = true

Otherwise, provide a certificate (certificate = …). If you do nothing and the server has no certificate, it logs an error and does not start the listener. - The web UI is a separate download on Linux (.deb / .rpm). After installing the package, run sudo nscp web install-ui to fetch the matching UI bundle. Until then the web port serves a built-in placeholder; the REST API and all listeners work normally without it. The Windows MSI still bundles the UI inline. - Linux install layout now follows the FHS / install prefix. The official .deb/.rpm install to /usr (daemon /usr/sbin/nscp, config /etc/nsclient, state/logs under /var). If you patched hardcoded paths to build for a custom location, pass -DCMAKE_INSTALL_PREFIX (and the standard CMAKE_INSTALL_*DIR knobs) instead. - Linux check_service now targets systemd. If you previously scripted around the old behaviour, note the normalised state keyword and the default expression that keeps disabled units OK. Match units by unit name (e.g. service=ssh), and use state, active, sub_state and preset in thresholds. - Linux check_process reports delta CPU. CPU is now the usage between samples rather than lifetime CPU. Review any CPU thresholds that assumed the old semantics. - Linux disk I/O needs one collector sample. The first check_disk_io / check_disk_health query immediately after startup may return UNKNOWN ("collector still initializing"); this is invisible with a running service and normal in one-shot testing. - check_tcp / check_http boolean ssl. Enable TLS with ssl=true. When verifying certificates, set verify=peer and provide a ca= bundle; the default remains verify=none.

Download

You can download the new version from GitHub

// Michael Medin

0.12.6 New permission system

The release has three big stories — a new core permission system with optional client-cert principals on NRPE, a PDH overhaul that fixes long-standing counter-collection crashes and adds counter functions, and a WEB hardening option that lets monitoring-only deployments expose the WEB UI without seeding a privileged admin account. Everything else is bug fixes, small features, and follow-ups around those three threads.


Highlights

  • Core permission system — opt-in policy layer that gates which caller can run which command. Configured under /settings/permissions. Disabled by default; existing installs keep working. See https://nsclient.org/docs/concepts/permissions/ for the model, identity table, and rollout recipe.
  • NRPE client identity from cert CN — when client identity source = cn is set on NRPEServer and the listener verifies the client cert, the CN is stamped as the policy principal so rules can be written per-cert ( NRPEServer:icinga-master = ...). Hard guardrail at module start refuses to load the module if the TLS verify mode would let the CN be attacker-supplied.
  • Global allow exec toggle — exec is now gated by a single on/off switch under /settings/permissions. The per-command rule table applies to queries only. Default true so enabling the policy system does not break exec callers.
  • PDH (performance counter) overhaul — fixes for service crashes when PDH misbehaves (#592, #547), counter retry when temporarily unavailable (#634), reliable English counter lookup (#652, #906), a resource leak in the counter-lookup path, and a refactor to smart-buffer-based PDH enumeration. Most users running CheckSystem on Windows should see meaningfully better reliability.
  • check_pdh counter scaling and functions (#281) — details-syntax and related rendering paths can now apply scaling and other functions, e.g. '${counter}'=${value:scale(/1024)}MB.
  • check_network — human-readable strings, scaling, speed, and percentages (#329); team-network statistics (#625). See https://nsclient.org/docs/reference/check/CheckNet.
  • Nagios range syntax in performance data (#748) — 1:10, ~:5, @10:20 etc. work in perfdata thresholds, matching the Nagios plugin spec.
  • disable admin user on WEBServer — monitoring-only deployments can expose the WEB UI without ever seeding the built-in admin (and previously seeded admin entries are ignored). Pairs naturally with the new permission system to lock down reconfiguration surfaces.
  • Path overrides moved to boot.ini + new --path-override CLI flag — path tokens (module-path, certificate-path, etc.) are now declared early in boot.ini so they take effect before the main config is loaded. Per-invocation overrides via --path-override KEY=VALUE. See https://nsclient.org/docs/concepts/settings.
  • NRPE startup is no longer fatal on listener failure — bad bind address / port already in use logs a clear error and leaves the module loaded so settings and commands stay usable for diagnostics.
  • Dual-stack listening fixed (#312) — v4 and v6 acceptors no longer trample each other's pending connection slot.
  • disable admin user, client identity source, allow exec, and the policy table are all documented in https://nsclient.org/docs/concepts/permissions/ and https://nsclient.org/docs/setup/securing. Treat those two as the starting point for any new install.

Detailed changes

Security and permissions

Core permission system A policy layer in the core decides whether a given caller may run a given command. Disabled by default; when enabled, rules form a strict allow-list.

[/settings/permissions]
enabled = true
log denials = true
log allows = false      ; noisy, only flip on while rolling out
allow exec = true       ; queries-only rule table; exec is a global toggle

[/settings/permissions/policies]
NRPEServer = CheckHelpers.*, CheckSystem.check_cpu
WEBServer:admin   = *
WEBServer:viewer  = CheckSystem.check_cpu, CheckSystem.check_drivesize
Scheduler = CheckHelpers.*, CheckSystem.*

Subject is module[:principal]; object is module.command. Wildcards (*, ?) supported. Rules combine additively. See https://nsclient.org/docs/concepts/permissions/ for the full identity model, the CheckHelpers identity-forwarding behaviour, and a step-by-step rollout recipe.

NRPE client cert CN as principal When two-way TLS is configured and verifying client certs against your CA, the Common Name is stamped as the policy principal:

[/settings/NRPE/server]
client identity source = cn        ; default: none
verify mode = peer-cert
ca = /etc/nsclient/ca.pem
[/settings/permissions/policies]
NRPEServer:icinga-master   = CheckHelpers.*, CheckSystem.*
NRPEServer:metrics-shipper = CheckSystem.check_cpu, CheckSystem.check_drivesize

Guardrails: the module refuses to start if client identity source = cn is configured without SSL, without verify_mode containing peer and fail-if-no-peer-cert (or the peer-cert alias), or without a non-empty ca path. The CN is logged at debug level on every accepted handshake for diagnostics. CN-only (not full DN) because INI key syntax uses = as the key/value separator and would corrupt DN-shaped policy keys; see the "Why CN-only" section of the permissions doc. See https://nsclient.org/docs/reference/client/NRPEServer.

Global allow exec toggle Per-command rules apply to queries only. The exec surface (WEB scripts UI, lua/python core:simple_exec(...), CLI exec) is gated by a single boolean:

[/settings/permissions]
allow exec = false   ; hard lockdown; default is true

When false and enabled = true, every exec call returns Permission denied: exec is globally disabled (/settings/permissions/allow exec = false). See "Why exec is a single toggle" in https://nsclient.org/docs/concepts/permissions/.

disable admin user on WEBServer For installations that expose the WEB UI for status/visualisation only and never want a remote-reconfiguration surface:

[/settings/WEB/server]
disable admin user = true

With this set, the built-in admin is not seeded on first boot, and any existing admin entry in the user settings is ignored at load time.

Security guide updates https://nsclient.org/docs/setup/securing was rewritten with concrete configurations for NRPE (with and without mTLS) and the WEB server. Read it before exposing either to a network you don't fully control.


Performance counters / PDH

The PDH subsystem (the Windows performance-counter collection backbone behind CheckSystem, check_cpu, check_pdh, check_network, etc.) got a substantial reliability pass. Most users running NSClient++ as a long-running service on Windows should see fewer crashes and more consistent results.

  • Service crashes when PDH misbehaves on a particular machine (#592, #547) — root-caused and fixed. Misbehaving counter registrations no longer take the service down.
  • Counter not retried if unavailable (#634) — counters that fail to bind at first sight now get retried on subsequent collection cycles, instead of being permanently unhealthy for the lifetime of the process.
  • English counter lookup improved (#652, #906) — addresses reading of localised counters by their canonical English names on non- English Windows installs.
  • Resource leak in PDH counter lookup fixed.
  • PDH enumeration refactored to smart buffers — clearer memory ownership across the enumeration path, fewer footguns for future changes.
  • check_pdh counter scaling and functions (#281) — all the details-syntax / rendering paths can now apply functions. Examples:
    check_pdh "counter=\Processor(_Total)\% Processor Time" \
              "details-syntax=${counter} = ${value:round(2)}%"
    
    See https://nsclient.org/docs/reference/check/CheckSystem for the function reference.

check_network

  • Human-readable strings, scaling, speed, and percentages (#329) — perfdata and message output now render numbers in a way operators actually want to read:
    check_network 'filter=interface=Ethernet' \
                  'top-syntax=${list}' \
                  'detail-syntax=${interface}: ${total_rx_human}/s in, ${total_tx_human}/s out'
    
  • Team network statistics (#625) — aggregate stats across Windows NIC teams.

See https://nsclient.org/docs/check/CheckNet.


Performance data formatting

  • Nagios range syntax in performance data (#748) — the perfdata threshold fields now accept the standard Nagios range syntax: 5:10, ~:5, @10:20, etc. Brings NSClient++ into line with what Nagios consumers already expect.

Settings, paths, and CLI

  • Path overrides moved to boot.ini — path tokens (module-path, certificate-path, data-path, log-path, …) now live under [paths] in boot.ini (next to nscp.exe), not in nsclient.ini. Overrides take effect before the main config is loaded — including the bootstrap step that decides where the main config itself lives.
    ; boot.ini
    [paths]
    module-path = D:\monitoring\modules
    certificate-path = D:\monitoring\certs
    
  • --path-override CLI flag — per-invocation override, repeatable. (Renamed from --path to avoid colliding with the nscp settings --path subcommand option.)
    nscp client --path-override module-path=/build/modules --path-override log-path=. ...
    
  • See https://nsclient.org/docs/concepts/settings for the precedence rules and the migration note for installs that had a [/paths] section in nsclient.ini.

Aliases and command registration

  • CheckHelpers alias — aliases can now be defined under [/settings/check helpers/alias] and are registered by CheckHelpers directly, without requiring CheckExternalScripts to be loaded. This is the preferred place going forward; the legacy [/settings/external scripts/alias] is still honoured for backward compatibility.
  • API to list registered query aliases (#506) — programmatic introspection of the alias table, useful for tooling.
  • simple_command / simple_command_map — internal refactor that streamlines how modules register aliases. No user-visible behaviour change, but module authors may want to look at the new pattern.
  • Icinga client alias (7c49a3d3) — minor module-specific addition.

NRPEServer

  • Listener failure no longer kills the module — a bad bind to address that the resolver can't look up, or a port already in use, used to make the whole module fail to load. Now the failure is logged clearly, the listener stays down, and the module's settings and commands remain accessible for diagnostics and reconfiguration. Fix the config and reload — no service restart needed.
  • Dual-stack fixed (#312) — the v4 and v6 acceptors used to share a single pending-connection slot, which caused intermittent Already open errors on v6 once v4 accepted a client. Each family now owns its own slot.
  • Insecure mode produces an error-level log line — flipping insecure = true (for legacy check_nrpe interop) now surfaces as an ERROR so it shows up in monitoring dashboards, instead of silently disabling cert-based peer auth.

Plugin lifecycle

  • prepare_shutdown hook — modules can opt in to a first-phase shutdown pass before any plugin is unloaded. Used by the Scheduler and similar long-running submitters to finish in-flight work cleanly. Operators see fewer "submission failed during shutdown" lines during service stop.

Settings store

  • simpleini buffer NUL-termination fix — fixes a buffer allocation issue in the INI parser that could affect non-UTF-8 data paths.
  • cache allowed host is now a real boolean — previously parsed as a string with surprising truthiness; matches what the docs always claimed.

Modules and clean-ups

  • WMI module refactor — target handling and settings management cleaned up.
  • IcingaClient cleanup — removed unused command-handling code paths.
  • CheckLogFile config and descriptions — fixed misleading defaults and improved the help text.
  • Web UI improvements — more settings elements exposed under modules, simpler module configuration. Web dependencies refreshed.
  • Installer: UninstallString is now correct (#495) — removal via Windows "Apps & Features" works again.
  • Rust dependencies bumped.

Upgrade notes

Most installs can upgrade in place — defaults are preserved. Read the specific items below if any of them apply.

Permission system

The new policy layer is disabled by default. Existing installs continue to behave exactly as before until an operator opts in via /settings/permissions/enabled = true.

If you do opt in:

  • Per-command rules under /settings/permissions/policies apply to queries only. Any rules you might have written for exec command patterns will be silently ignored for the exec dispatch path — exec is gated by the single global allow exec boolean.
  • The default for allow exec is true, so enabling the policy will not silently break the WEB scripts UI, lua/python core:simple_exec(...), or CLI exec. Flip to false only if you want a hard exec lockdown.
  • Roll out with log allows = true first so you can inventory what your actual traffic looks like before tightening to a real allow-list. See the step-by-step recipe in https://nsclient.org/docs/concepts/permissions/.

NRPEServer

  • The new client identity source setting defaults to none, which matches the previous behaviour (subject is bare NRPEServer). Set to cn only when you want per-cert principals — and only after you've configured verify_mode = peer-cert and a ca path. The module will refuse to start with a clear error if you set cn without those.
  • Pin the ca path to your private monitoring CA. The system trust store (Windows root store / Linux distro bundle) accepts certs from every public CA on the planet and would let an attacker with a public cert choose their own CN. See "Pin to a private CA" in the permissions doc.

Path overrides

  • If you had a [/paths] section in nsclient.ini from an older NSClient++ install, those overrides moved to [paths] in boot.ini (note: same section name, different file). There is no automatic migration. Copy each key = value to a [paths] section in boot.ini (next to nscp.exe) and delete the old section from nsclient.ini.

WEB server

  • The new disable admin user = true setting is opt-in. Existing installs keep their admin and continue to work unchanged. Use this when you want to expose the WEB UI for status-only viewing and have no need to reconfigure the agent through the web.

NRPEServer startup robustness

  • A failed listener (bad bind address, port in use) used to make the whole NRPEServer module fail to load. It now logs an ERROR and leaves the module loaded with no active listener — so you can reconfigure via nscp settings --path /settings/NRPE/server --key ... --set ... and reload, without restarting the service. If you had monitoring on "module load failed" specifically, you may want to add "NRPE listener failed" as a separate signal.

insecure = true on NRPEServer

  • This option (for legacy check_nrpe interop) now logs at ERROR rather than DEBUG/INFO. Behaviour is unchanged; the message is louder so it shows up in dashboards. If your monitoring filters by severity, you may want to whitelist this specific message on agents that intentionally run in insecure mode.

cache allowed host

  • Previously parsed as a string with surprising truthiness; now a real boolean. If you had cache allowed host = yes or = on, switch to true. Numeric 1 / 0 still work.

Nagios range syntax in performance data

  • This is additive — existing perfdata that doesn't use range syntax continues to work. Plain numbers still parse as before. Only consumers that previously had to special-case NSClient++'s output may need adjusting, but most Nagios-ecosystem tools handle both forms.

Download

You can download the new version from GitHub

// Michael Medin

0.12.3 Fixed almost all bugs :)

0.12.4 Fixes a few important regression issues, so please use that version.

What's Changed

This release rolls up everything since the last stable: five pre-releases (0.11.31, 0.11.32, 0.11.33, 0.12.1, 0.12.2) plus the latest in-development changes.

The headline themes are:

  1. New monitoring scenarios — first-class Checkmk and Icinga 2 integration, plus a real check_net family.
  2. A modern Web UI and REST API — events, metadata, settings DELETE, filterable lists, dedicated widgets for PDH counters and real-time filters.
  3. Hardened by default0.12.2 is a security release that closes listener defaults that used to be silently permissive (empty allowed hosts, plaintext check_nt, query-string tokens, etc.).
  4. Many long-standing check fixescheck_service, check_process, check_files, check_drivesize, check_uptime, CheckLogFile, and the shared filter/threshold engine all behave correctly now.

Read the Breaking changes section before upgrading — several long-standing-but-incorrect behaviours have been corrected and a number of listener defaults are now fail-closed. If you have an existing configuration, plan to review it.


TL;DR for end users

  • New scenario: Checkmk agent integration. Point a Checkmk site at port 6556 and you get a native-looking agent dump. See scenarios/check-mk.md.
  • New scenario: Icinga 2 passive submission. A new IcingaClient module submits passive results to Icinga 2's REST API as an alternative to NSCA / NRDP.
  • New scenario: NSCA-ng. A new hardened NSCAngClient with PSK and AEAD-first cipher selection.
  • Native cross-platform network checks: check_tcp, check_dns, check_http, check_ntp_offset, check_connections.
  • Native Windows registry checks: check_registry_key, check_registry_value.
  • HTTP proxy support for every HTTP-based client (NRDP, Elastic, Op5, Icinga, the configuration loader, ...).
  • Windows ROOT trust store auto-export — HTTPS-bound checks validate certificates against the system trust store automatically.
  • A modern Web UI with filterable lists, settings diff, dashboard, and dedicated CheckSystem widgets.
  • New REST endpoints: GET/DELETE /api/v2/events, GET /api/v2/metadata, DELETE /api/v2/settings/.... Covered in api/rest/.
  • Linux real-time metrics — the same background CPU/memory/disk/ network/load sampling that Windows has had for years.
  • Many bug fixes in check_service, check_process, check_files, CheckLogFile, the filter/threshold engine and the HTTP stack.

Major new features

Checkmk agent integration

NSClient++ can now serve a Checkmk-compatible agent dump on TCP port 6556. A real Checkmk site can register the host with tag_agent = cmk-agent, discover services, and run checks — no proxy, no NSCA gateway.

Enable it:

[/modules]
CheckMKServer = enabled
LUAScript = enabled
CheckSystem = enabled
CheckDisk = enabled
CheckHelpers = enabled

[/settings/check_mk/server]
port = 6556
allowed hosts = 127.0.0.1, <checkmk-site-ip>
submission ttl = 60          ; seconds, default 60
mrpe channel = check_mk-mrpe
local channel = check_mk-local

Out-of-the-box sections (no extra config):

Section Contents
<<<check_mk>>> Version, OS, hostname
<<<systemtime>>> Unix epoch (Windows clock-skew check)
<<<uptime>>> Seconds since boot (read from internal metrics store)
<<<mem>>> MemTotal:/MemFree:/SwapTotal:/SwapFree: (from metrics store)
<<<df>>> Per-volume size/used/free/mountpoint (Windows)
<<<services>>> name state/start_type display_name per Windows service
<<<ps>>> (user,vsz_kb,rss_kb,cputime,pid) cmdline per process

Expose any nscp check as a Checkmk service under <<<local>>>:

[/settings/check_mk/server/local]
CPU Load = command=check_cpu warn=load>80 crit=load>95
Disk C = command=check_drivesize drive=C: "warn=free<20%" "crit=free<10%"

MRPE relay under <<<mrpe>>>:

[/settings/check_mk/server/mrpe]
Uptime = command=check_uptime warn=uptime<2d
Memory = command=check_memory type=committed warn=used>80% crit=used>90%

Documentation: https://nsclient.org/docs/scenarios/check-mk.md`.

IcingaClient — Icinga 2 REST API submission

A new client module submits passive check results directly to an Icinga 2 master/satellite via the /v1/actions/process-check-result REST endpoint, as an alternative to NSCA or NRDP.

[/modules]
IcingaClient = enabled

[/settings/IcingaClient/targets/default]
address = https://icinga2.example.com:5665
username = nscp
password = secret
hostname = ${hostname}
nscp client --module IcingaClient \
            --command submit_icinga \
            --address https://icinga2.example.com:5665 \
            --username nscp --password secret \
            --command heartbeat \
            --result 0 \
            --message "Hello from NSClient++" \
            --ensure-objects

NSCA-ng client

A new NSCAngClient module ships a hardened NSCA-ng submission client with PSK support, AEAD-first cipher selection, and connection retry logic.

Native support for Windows CA-store

On startup NSClient++ now exports the machine's ROOT certificate store as a single PEM bundle, so any check that does TLS (check_http, IcingaClient, NRDP, ...) can validate certificates against the trust store the rest of Windows already uses.

check_http url=https://www.ibm.com
OK: https://www.ibm.com -> 303 ok (0B in 33ms)

check_http url=https://self-signed.badssl.com/
CRITICAL: https://self-signed.badssl.com/ -> 0 error: Failed to connect ... certificate verify failed

CheckNet — five new (cross-platform) checks

CheckNet graduated from a placeholder into a full network-check module. All five commands work over NRPE as well as locally:

  • check_tcp — open a TCP socket to one or more host/port pairs, optionally send a payload and require an expected substring.
  • check_dns — resolve a hostname and optionally assert which addresses come back.
  • check_http — fetch one or more URLs, check status code, response time and body content; supports custom headers and user-agent.
  • check_ntp_offset — query one or more NTP servers and alert on offset / stratum.
  • check_connections — Windows TCP/UDP connection table inspection (counts per protocol/family/state).
check_tcp host=smtp.gmail.com port=25 send="EHLO nsclient.org" expect="250"
check_dns host=google.com expected-address=172.217.20.174
check_http url=https://nsclient.org/ expected-body="NSClient" \
    "warn=time > 500 or code >= 400" \
    "crit=time > 2000 or code >= 500 or result != 'ok'"
check_ntp_offset "servers=0.pool.ntp.org,1.pool.ntp.org" timeout=2000
check_connections "filter=protocol = 'tcp' and state = 'TIME_WAIT'" \
    "warn=count > 200" "crit=count > 1000"

CheckSystem (Windows) — registry checks

Two new commands let you monitor the Windows registry directly from NSClient++ instead of relying on external scripts. They support recursion, exclude lists, 32/64-bit (WoW64) views, custom filters and the usual warn=/crit= expression syntax.

  • check_registry_key — verify that a key exists, count sub-keys/values, watch its last-write time.
  • check_registry_value — read a single value assert its type, size or content.
check_registry_key "key=HKLM\Software\NSClient" \
    "warn=age > 7d" "crit=age > 30d or not exists"

check_registry_key "key=HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall" \
    recursive max-depth=1 exclude=KB5005463 exclude=KB5005539

check_registry_value "key=HKLM\System\CurrentControlSet\Services\W32Time\Config" \
    value=MaxPollInterval "warn=int_value > 14" "crit=int_value > 17"

CheckSystem — check_os_updates (Windows)

A new check using the Windows Update Agent (WUA) reports pending OS updates. By default any pending update returns warning; thresholds let you alert only on security/critical:

check_os_updates "warning=important > 0" "critical=security > 0 or critical > 0"

CheckSystem (Linux) — real-time metrics

The Linux build of CheckSystem now ships with the same real-time metric collection that has been available on Windows for a long time: CPU, memory, disk, network and load are sampled in the background and exposed both to dashboards/metrics and to real-time filters (filter=... rules that fire when a threshold is crossed). Existing real-time filter configuration just works on Linux now.

Real-time filter metrics

CheckSystem's real-time filters now publish per-filter match and error counts under system.realtime.<filter_name>.fired / system.realtime.<filter_name>.errors. Visible via:

  • The metrics REST endpoint (/api/v2/metrics + filter)
  • Prometheus scrape
  • The new Metrics() Lua API in default_check_mk.lua

Useful for spotting filters that never fire (typo in the where-clause) or filters that always error (broken expression).

CheckDisk — check_single_file

A focused variant of check_files for inspecting a single, known path. Compared to using check_files for the same job:

  • Only one required argument (file=<path>).
  • A clear error when the input is empty.
  • UNKNOWN: File not found: <path> when the file is missing — instead of the empty-set / "No files found" workflow.
  • A useful default detail-syntax so a no-threshold run is informative on its own.
check_single_file file=C:/windows/WindowsUpdate.log "warn=age > 5m" "crit=age > 1h"
CRITICAL: WindowsUpdate.log (size=276, age=917)

CheckDisk — filesystem filtering for check_drivesize

check_drivesize can now filter drives by filesystem type — useful for excluding tmpfs, nfs, etc.

check_drivesize drive=* "filter=fs = 'NTFS'"

check_nscp_update

A new check command queries the GitHub releases API (with caching) and reports whether the running NSClient++ is up to date.

HTTP proxy support across every HTTP client

NSClient++ can now route HTTP and HTTPS traffic through a corporate proxy. The same surface is used by every component built on the internal http::simple_client (NRDPClient, ElasticClient, Op5Client, IcingaClient, the remote boot.ini loader, ...).

For HTTPS targets the client opens a CONNECT tunnel to the proxy, validates the proxy's response, and only then performs the TLS handshake — so a single setting covers both http:// and https:// URLs.

Two new options on every HTTP client command and target:

Option Purpose
proxy Proxy URL — scheme://[user:pass@]host[:port]/. Empty value disables the proxy.
no-proxy Comma-separated list of hosts that bypass the proxy. A leading . is a suffix match.
[/settings/NRDP/client/targets/nagios]
address = https://nagios.example.com/nrdp/
token = mytoken
proxy = http://proxy.corp.example:3128/
no proxy = localhost,127.0.0.1,.internal

Configuration loader (boot.ini):

[proxy]
url = http://proxy.corp.example:3128/
no_proxy = localhost,127.0.0.1,.internal

Notes / limits:

  • Only the http:// proxy scheme is supported. socks5:// / https:// proxies are not.
  • No automatic detection of system proxy settings (HTTP_PROXY env vars, WinINET / WPAD). The proxy must be configured explicitly.
  • On 407 Proxy Authentication Required the proxy's response body is captured in the error message.

Web UI / REST API expansion

New web routes:

Route Method Purpose
/api/v2/events GET List buffered real-time events
/api/v2/events DELETE Drain (returns + clears) the event buffer in one call
/api/v2/metadata GET Module/setting metadata index
/api/v2/metadata/counters GET List of available PDH counters
/api/v2/metadata/channels GET List of registered submission channels
/api/v2/settings/<path> DELETE Remove a settings key or path (staged delete; survives restart)

The settings store gained staged deletion: a DELETE is recorded so that subsequent reads of the deleted key/path return "not present" until the change is saved. Stops a deleted-but-not-yet-saved key from being re-resurrected by a concurrent read.

Web UI refresh

The bundled web interface has been heavily reworked:

  • Modern theme with active-navigation highlighting and a redesigned login page.
  • Filterable lists for Modules, Queries and Settings.
  • Settings diff dialog — the "settings changed" widget can now show exactly which keys changed.
  • CheckSystem settings UI got dedicated widgets for PDH counters and real-time filters: a counter picker that hits /api/v2/metadata/counters, "Add filter" / "Add counter" dialogs, and a live preview of metric values pulled from the metrics endpoint.

If you've been editing real-time filters in nsclient.ini by hand, the web UI is now a much faster way to do it.

SMTPClient rewrite

The SMTPClient module has been substantially rewritten with proper SMTP handling, integration tests, and a Python-based test harness.

Smaller features

  • nscp settings --sort — produce stable, sorted output, useful for diffing exported settings between hosts.
  • Performance threshold min/max bounds — perfdata threshold expressions can declare minimum and maximum bounds, propagated into emitted perfdata:
    check_pdh "counter=\\Processor(_Total)\\% Processor Time" \
              "perf-config=*(minimum:0;maximum:100)"
    
  • Timezone-aware check_uptime and Schduler — applies a timezone cache on both Windows and Unix, so absolute boot-time output and cron expressions agree with the host's local time.
  • WEBServer cookie attribute supportSecure, HttpOnly, SameSite, Path, Domain, Expires, Max-Age.
  • WEBServer password hashing with constant-time verification — removes the timing oracle on the previous plaintext equality check.
  • WEBServer authentication rate limiter — per-source throttling of failed authentication attempts:
    [/settings/WEB/server]
    auth rate limit max failures   = 10   ; 0 disables the limiter
    auth rate limit block seconds  = 60
    

Filter engine — stable summary thresholds

These changes touch the shared filter / threshold engine and therefore affect every modular check (check_files, check_service, check_process, check_eventlog, ...).

Stable count / total / *_count in warn= / crit=

warn= / crit= were evaluated during iteration. Summary variables such as count therefore exposed their running value instead of the final post-iteration value, so a mixed expression like

crit = state = 'hung' OR count < 5

mis-fired on the very first row (count == 1 < 5) regardless of how many rows ultimately matched. Per-row evaluation is now deferred: matched rows are recorded during iteration, and the warn/crit/ok engines run once the summary state is final.

Mixed warn= / crit= evaluated when no rows match

If a filter excluded every row, mixed expressions like crit = state = 'stopped' OR count = 0 were skipped entirely — leaving the check OK in the empty case. They are now evaluated with object-bound variables defaulting to false and summary variables at their final values, so the check correctly returns CRITICAL when the service is missing.

Quieter, more predictable expression evaluation

  • Operators audited so is_unsure propagates consistently; invalid-type comparisons resolve to unsure-false instead of erroring.
  • String variables on no-object cases now return an empty string with is_unsure=true and produce a warning in the log instead of an error per row — log volume on complex queries drops dramatically.
  • Removed the misleading "most likely mutating" warnings.
  • Substantial new test coverage.

check_service and check_process fixes (Windows)

  • "Failed to enumerate service: 6f7" on busy hosts — enumeration is now properly looped until the SCM signals end-of-data.
  • perf-syntax=none actually suppresses perfdatacheck_service used to emit empty perfdata aliases ( ''=4;0;1 ''=4;0;1 ...), blowing past NRPE size limits.
  • No more TODO leaking into ${desc}check_service service=Spooler used to render as OK: Spooler: TODO. Now: OK: Spooler: Print Spooler.
  • delayed only reported for SERVICE_AUTO_START — manual / boot / system / disabled services no longer randomly show up as delayed.
  • check_process sees protected / cross-user processes as NETWORK SERVICE — a PROCESS_QUERY_LIMITED_INFORMATION fallback is now attempted, so winlogon.exe, csrss.exe etc. no longer report CRITICAL: <name>=stopped when the agent runs unprivileged.
  • Realtime check_process is now case-insensitive, matching the active path and Windows itself.

check_files fixes

  • #730max-depth=0 now scans the top directory only (was: bail out before scanning anything, returning "no files found").
  • #598 — Non-ASCII paths (accented letters, CJK, ...) are no longer silently mangled by mismatched codepage conversions.
  • #613 — Top-level paths that cannot be opened now produce UNKNOWN: Path was not found: <path> instead of being hidden behind the configured empty-state.
  • #605 — NTFS junctions / symlinks / mount points are now skipped during recursion, preventing double-counts on self-referential trees.
  • #717 — The legacy CheckFiles shim now sets empty-state=ok when translating, restoring 0.4-era behaviour for legacy calls that find zero files.

Other check / module fixes

  • CheckDisk resilience — an error on a single unavailable volume no longer aborts the entire check_drivesize run.
  • #581CheckLogFile honours the line-split argument (previously hard-coded to \n); multi-character delimiters such as \r\n are handled correctly. Real-time seek behaviour fixed; CRLF handling harmonised.
  • #589 — Time/duration arguments such as time=3000foobar or time=3000mfoobar are no longer silently accepted; malformed inputs are rejected with a clear error.
  • #669 — The literal U (Nagios "undefined") in performance data is preserved end-to-end instead of being coerced to 0. Only an exact U, u, U% or u% token matches.
  • NSCA wire timestamps are now correctly built in UTC. Both server (IV packet) and client (data packet) used to derive seconds-since-epoch from second_clock::local_time(), which drifted by the host's TZ offset. A timezone setting on both ends allows legacy interop with agents that emit local-clock-as-Unix-time stamps.
  • Metrics collection regression fixed (some metrics were silently dropped).
  • Op5Client / ElasticClient unified on the new HTTP client; 401 path fixed; reponse → response typos corrected.
  • Gracefully handle non-numeric NSClient command codes.
  • TLS support fixes; better randomness for encryption; race condition fixes; boundary checks for various network payloads and reading certificates.
  • NRDP integration tests added; new nrdp client alias.

HTTP refactor

  • HTTP request and response are now distinct types instead of one shared bag.
  • Chunked transfer-encoding is decoded properly. check_http against servers using Transfer-Encoding: chunked ( most modern reverse proxies, Icinga 2, Kubernetes ingress, ...) now returns the full body instead of a truncated/garbled one. The IcingaClient module relies on this.
  • Header storage is normalised — case-insensitive lookup, no more duplicate-header surprises.

Security hardening

The 0.12.2 release is a security-focused pass. These do not change documented behaviour for well-formed traffic but close down attacker-controlled edge cases.

DoS / resource-exhaustion limits

  • Authorization header capped at 8 KiB to mitigate amplification.
  • Per-connection parser buffer cap to prevent memory pinning from oversized or never-completed requests.
  • Session token cap with eviction to prevent unbounded memory growth.
  • Payload lengths below the protocol minimum are rejected before allocation.
  • Path expansion now detects cycles and refuses to recurse, preventing stack overflow on pathological configurations.

NSCA hardening

  • Packet version is checked.
  • Timestamp validation tightened to mitigate replay attacks.

Log/output injection prevention

Control characters are stripped from values before they are written to external sinks, removing log/protocol-injection vectors:

  • Log file entries (file names and messages)
  • syslog messages (CR/LF/NUL stripped)
  • Graphite metric paths and values
  • HTTP response headers (header keys and values)
  • log_status is now JSON-serialised so attacker-controlled fields cannot inject extra structured fields.

Filesystem / process safety

  • PID file creation hardened against symlink attacks; exclusive access enforced.
  • Archive extraction has a zip-slip guard that validates entry paths and refuses traversal sequences.
  • Module and script names are validated to prevent path traversal at load time.
  • Argument substitution in external scripts is isolated to prevent command injection through user-controlled tokens.

Cryptography / TLS

  • HTTPS now logs explicitly when no certificate is present and warns on HTTP fallback in production.
  • SSL connections enable hostname verification by default.
  • Auto-generated passwords use OpenSSL RAND_bytes (cryptographically secure) instead of the previous predictable generator.
  • Sensitive values are no longer logged at debug level.
  • check_nt password compare is constant-time.

Breaking changes

Read this section carefully. Some changes are listener defaults that are now fail-closed; some are corrections to long-standing buggy behaviour; some are internal API changes for out-of-tree modules.

Listeners default to safer behaviour

  1. Empty allowed hosts now rejects all connections. Previously treated as "allow any source". To genuinely expose the agent to any source, set it explicitly:
    allowed hosts = 0.0.0.0/0,::/0
    
  2. check_nt (NSClientServer) defaults to ssl = true. The legacy check_nt protocol carries the password in every request. The listener will not refuse to start if TLS is off, but it will log a warning. To keep the old plaintext behaviour for legacy clients, set ssl = false explicitly in [/settings/NSClient/server].
  3. check_nt: the literal password None no longer authenticates. Empty server passwords now reject all requests. Errors are also genericised (ERROR: Bad request.) to remove the online password-guessing oracle.
  4. WEBServer: /auth/token and /auth/logout are removed (HTTP 410). They accepted the password and session token as URL query parameters, leaking credentials into browser history and proxy logs. Migrate to:
    • POST /api/v2/login with Authorization: Basic to obtain a token
    • DELETE /api/v2/login with Authorization: Bearer to log out
  5. WEBServer: ?TOKEN= / ?__TOKEN= query-string token auth removed. Send the token in a header instead: Authorization: Bearer <token>, TOKEN: <token>, or X-Auth-Token: <token>.
  6. WEBServer: anonymous access is now opt-in. A role named anonymous registered in settings is silently ignored unless the new allow_anonymous flag is enabled.
  7. WEBServer: existing admin user is no longer overwritten on restart. Deployments that relied on the password being reset to the default at boot must adapt.

Scheduler — cron expressions evaluate in local time by default (#570)

The Scheduler module previously used UTC, so 40 15 * * * fired at 15:40 UTC regardless of host TZ. The default has changed to local time, matching standard cron semantics. Hour and minute fields will shift accordingly on non-UTC hosts.

A new timezone setting under [/settings/scheduler] controls the reference clock:

[/settings/scheduler]
timezone = local                          ; default — standard cron semantics
; timezone = utc                          ; restore the pre-0.12 behaviour
; timezone = EST-05EDT,M3.2.0,M11.1.0     ; any POSIX TZ string is honoured

IANA names such as Europe/Stockholm are not supported — use the POSIX form. Unparseable values fall back to UTC and surface as UTC? in any timezone label.

Filter / threshold engine

  1. warn= / crit= no longer fire mid-iteration on running counts. Configurations "tuned" against the buggy early-fire will produce different results.
    crit = state = 'hung' OR count < 5
    # Old: CRITICAL on the very first row (count == 1).
    # New: CRITICAL only if any row is 'hung' OR final count < 5.
    
  2. Mixed warn= / crit= now evaluate when no rows match.
    crit = state = 'stopped' OR count = 0
    # Old: OK when nothing matched (count = 0).
    # New: CRITICAL when nothing matched (count = 0).
    
    If your old config implicitly treated "empty" as OK, add a count > 0 AND ... guard or move the empty-case logic into a dedicated check.

Check-specific corrections

  1. check_service: delayed is no longer reported for non-auto services. Filters that matched start_type = 'delayed' on Manual / Boot / System / Disabled services will stop matching. To alert on "any non-running service that isn't disabled":
    filter = start_type IN ('auto','delayed','boot','system') AND state != 'running'
    
  2. Realtime check_process is now case-insensitive. A rule that intentionally matched only an exact casing will now match all variants (almost certainly the desired behaviour).
  3. check_service: ${desc} no longer returns the literal TODO. Use the real display name.
  4. check_service: perf-syntax=none actually suppresses perfdata. Backends that consumed the empty-aliased entries (highly unlikely) will see them disappear.

check_files — corner cases changed

  1. max-depth=0 now scans the top directory instead of returning empty (#730).
  2. Missing paths now return UNKNOWN instead of OK / empty (#613).
  3. NTFS junction loops are no longer double-counted (#605).
  4. Legacy CheckFiles calls that previously returned UNKNOWN on empty results will now return OK (#717).

Configuration / startup

  1. CheckExternalScripts: malformed alias commands are refused at startup. The fallback "split-on-space" parser has been removed. Aliases whose command line does not parse cleanly are refused with an error in the log instead of being silently registered with surprising tokenisation. Review your logs after upgrading.

Internal API (out-of-tree module authors)

  1. HTTP request/response API changed. Internal C++ types http::request / http::response are now distinct, headers are case-insensitive, and chunked decoding happens transparently. Out-of-tree modules linked against the old shared bag type need a small adjustment:
    // before
    http::packet pkt = client.send(...);
    auto body = pkt.body;
    
    // after
    http::response resp = client.send(http::request{...});
    auto body = resp.body();   // chunked decoding already applied
    

Documentation reorganisation

  1. The documentation tree was restructured (concepts/, checks-in-depth/, scenarios/, tutorial/, reference/ are now clearly separated). Bookmarks and external links may need updating.

Upgrade checklist

  1. Audit allowed hosts on every node — empty values now reject everything.
  2. check_nt (NSClientServer) now defaults to ssl = true. If your clients don't speak TLS, set ssl = false explicitly. Either way the listener will log a warning at startup if TLS is off or a password is configured, recommending a switch to REST or NRPE.
  3. Replace any client that calls /auth/token or /auth/logout with the /api/v2/login flow.
  4. Replace any client that passes ?TOKEN= / ?__TOKEN= in the query string with a header-based token.
  5. Scheduler cron expressions on non-UTC hosts will shift to local time. Either update them or set [/settings/scheduler] timezone = utc to restore the previous behaviour.
  6. Review check_service / check_process / check_files filters that may have relied on the corrected behaviours listed above.
  7. Restart the service and review the log for new "refused alias" or "rejected connection" warnings — these flag configurations that were previously silently accepted.

No configuration migration is required for the new HTTP proxy keys, the Checkmk server, the Icinga client, the NSCA-ng client, or the new checks — they are all opt-in.

Download

You can download the new version from GitHub

// Michael Medin

0.11.29 New checks and web ui enhancements

check_battery

Monitor battery status on Windows laptops and mobile devices. This command provides comprehensive battery health and status information using both the Windows Power API and WMI.

  • Charge Level Monitoring: Track battery charge percentage with warning/critical thresholds
  • Power Source Detection: Determine if system is running on AC or battery power
  • Battery Health: Calculate battery health as a percentage of design capacity
  • Status Tracking: Monitor charging, discharging, critical, low, and high states
  • Time Remaining: Estimate remaining battery life when on battery power
  • Detailed Metrics: Access charge/discharge rates and capacity information via WMI

Basic battery check with default thresholds (warn < 20%, crit < 10%):

check_battery
OK: system: 85% (ac, charging)

Check if battery charge is above 50%:

check_battery "warn=charge < 50" "crit=charge < 25"
OK: system: 85% (ac, charging)

Alert if running on battery power:

check_battery "warn=power_source = 'battery'"
WARNING: system: 72% (battery, discharging)

Show detailed battery information:

check_battery "detail-syntax=${name}: ${charge}% (${power_source}, ${status}, health: ${health}%, time: ${time_remaining}s)"
OK: system: 85% (ac, charging, health: 95%, time: -1s)

check_process_history

Track all processes that have been seen running since NSClient++ started. This command maintains a history of process executions, allowing you to verify that certain processes have (or haven't) run.

  • Process Tracking: Records every unique process seen since service start
  • Execution Counting: Tracks how many times each process has started
  • Timestamp Recording: Records first and last seen timestamps
  • Current State: Shows whether each process is currently running
  • Selective Filtering: Check specific processes by name

Use Cases - Compliance Monitoring: Verify that backup software, antivirus scanners, or other required applications have run - Security Auditing: Detect if unauthorized applications have been executed - SLA Verification: Confirm that scheduled maintenance tasks have executed

As checking processes is expensive it is disabled by default. You need to enable it by setting:

[/settings/system/windows] 
process history=true

List all processes in history: Check if a specific backup application has run:

check_process_history --process backup.exe "warn=times_seen = 0" "crit=times_seen = 0"
CRITICAL: backup.exe (false) - never seen running

Check if a process is currently running:

check_process_history --process important-service.exe "crit=running = 'false'"
CRITICAL: important-service.exe (false) - not currently running

Alert if a forbidden application has ever run:

check_process_history --process forbidden-game.exe "warn=times_seen > 0"
WARNING: forbidden-game.exe (seen 3 times, not running)

Show detailed history for a process:

check_process_history --process notepad.exe "detail-syntax=${exe}: first=${first_seen}, last=${last_seen}, count=${times_seen}, running=${running}"
OK: notepad.exe: first=2026-04-06 08:15:32, last=2026-04-06 14:22:45, count=5, running=false

check_process_history_new

Detect processes that have been started recently within a configurable time window. This is useful for security monitoring to detect unexpected process launches.

  • Time-Based Detection: Find processes first seen within a configurable window
  • Flexible Time Windows: Support for seconds (s), minutes (m), hours (h)
  • Security Focused: Ideal for detecting new/unexpected process launches

Use Cases - Security Monitoring: Detect newly launched processes that might indicate compromise - Change Detection: Monitor for new software installations or unauthorized programs - Incident Response: Identify what processes started around the time of an incident

As checking processes is expensive it is disabled by default. You need to enable it by setting:

[/settings/system/windows] 
process history=true

Check for any new processes in the last 5 minutes (default):

check_process_history_new
OK: No new processes found.

Check for new processes in the last hour:

check_process_history_new --time 1h
WARNING: suspicious.exe (first seen: 2026-04-06 14:15:32)

Check for new processes with detailed output:

check_process_history_new --time 30m "detail-syntax=${exe} started at ${first_seen} (running: ${running})"
OK: updater.exe started at 2026-04-06 14:10:00 (running: false)

Beware that depending on if you are looking for wanted or unwanted processes you likely want to change empty-state to ok, or critical.

check_service overhaul

Fixed a reported bug as well as overhauled the check with some new features and modernized the checks.

This is technically a breaking change, in that it will classify some services as "ok" which was not before. But I doubt that anyone relied on the default checking of all services

  • state_is_perfect() now treats auto-start services with triggers as OK when stopped (trigger-start services legitimately remain stopped until their trigger fires)
  • state_is_ok() now treats auto-start services with triggers as OK when stopped (same as delayed services were already treated)
  • state_is_ok() now treats auto-start services that stopped with exit code 0 as OK (services like WslInstaller that start, complete their task, and stop cleanly no longer trigger CRITICAL)
  • Added new filter keyword 'exit_code' exposing the Win32 exit code of a service. Allows users to write custom filters like 'exit_code != 0' to detect failed services
  • Improved error logging in trigger detection. fetch_triggers() previously swallowed all errors silently; now logs unexpected failures
  • check_service: Updated service classification list for Windows 11 24H2 / Server 2025
  • Added modern services: WslInstaller, WaaSMedicSvc, UsoSvc, DoSvc, CoreMessagingRegistrar, SecurityHealthService, SystemEventsBroker, vmcompute, HNS, sshd, LxssManager, and others
  • Removed obsolete services no longer present in modern Windows: Browser, NtFrs, IISADMIN, TlntSvr, napagent, IEEtwCollectorService, UI0Detect, SMTPSVC, aspnet_state, and others
  • Reclassified: COMSysApp (essential → ignored), SystemEventsBroker (supporting → system), WerSvc/wercplsupport (role → ignored)
  • Fixed casing: Eventsystem → EventSystem, systemEventsBroker → SystemEventsBroker
  • Changed default detail-syntax to include exit_code. From ${name}=${state} (${start_type})into ${name}=${state}, exit=%(exit_code), type=%(start_type)
  • Removed warning messages for excluded services. If a service is excluded we will not try to enumerate it.

Improvements to web-ui

web-disk-widgets

This version adds some new dashboard widgets that showcases system statistics as well as a network graph and disk stats. I also fixes and issue relating to calculating network measurements.

test-client test-client

It also changes the tools bar slightly to make them a bit less intense:

test-client

Other changes:

  • three new metrics which contains the refresh times of metrics, system metrics and network metrics so you can see this in the web UI.
  • Removes unnecessary scientific notations for number in the metrics api so now you will get 1 instead of 1E1. Both are valid json so this should not impact anyone as long as your not using grep or some such to parse the json.

Download

You can download the new version from GitHub

// Michael Medin

0.11.25 New Linux support and installer fixes

This release includes significant, but experimental, Linux support. While it has always been possible to use and build NSClient on Linux we now build official packages which are ready to be installed. In addition to this there are a lot of fixes and enhancements to make running on Linux much more viable.

🐧 Experimental Linux Support

The Linux version is now complete and mirrors the Windows experience more closely than ever before.

  • Unified Commands: CheckSystemUnix has been renamed to CheckSystem. Linux users can now use the same configuration as Windows users.
  • Distribution-Specific Binaries: We now provide optimized builds for Debian, and Rocky Linux (redhat).
  • Scripting Parity: Full support for Python and Lua scripts is now available on Linux, including proper script-folder routing.
  • Permission Improvements: Default logging on Linux is now directed to the console, allowing the agent to run without sudo when testing. Also now certificates are generated when you run nscp web install to prevent sudo requirements when running as a service.

🛠️ Installer & Core Stability

After a series of regression tests in the 0.11.x branch, the installer has been hardened.

  • Fixed Upgrade Logic: Resolved a critical issue where a DLL name change caused the WiX installer to fail or leave files missing during upgrades in some instances.
  • Configuration Protection: Added safeguards to prevent the installer from overwriting or wiping existing .ini configurations during an upgrade.
  • Silent Install Flags: Reintroduced and documented ALLOW_CONFIGURATION=0 for msiexec, allowing admins to deploy the MSI without touching existing config files.

🏗️ Architectural Refactoring

  • Modular Codebase: Significant internal refactoring of nscapi and protobuf functions to improve long-term maintainability.
  • Windows Core Cleanup: Reorganized Windows-specific code into a dedicated internal directory structure to separate it from cross-platform logic.
  • Enhanced Testing: Many unit tests as well as a new Azure-based automated integration test.

⚠️ Upgrade Note for ALLOW_CONFIGURATION=0

If you use ALLOW_CONFIGURATION when upgrading from an old version the configuration might be deleted. This is an issue which is in the old installer and thus not possible to fix. This has however been fixed in future upgrades.

Download

You can download the new version from GitHub

// Michael Medin

0.11.6 New interactive client

New check_nsclient client

This new release adds a new check_nsclient client tool. This is a stand-alone application you can use to connect to and interact with NSClient. This new client can:

  • Run queries/checks
  • Change configuration
  • Show logs
  • Load/unload modules

It also have an interactive client you can use which is aimed as a replacement for "test mode".

To connect to NSClient you need to have the web server enabled and then you can login with the same username and password as you use in the web-ui:

$ check_nsclient nsclient auth login --password PASSWORD --ca %LOCALAPPDATA%\mkcert\rootCA.pem
Successfully logged in

Credentials are securely stored in store in credential manager.

The reason there is a nsclient command line option is that soon this will also support NRPE and other protocols as well becoming a universal monitoring tool.

After this you can show logs:

$ check_nsclient nsclient logs list
╭────────┬───────────────────────┬──────────────────────────────────────────────────────────────────╮
│ level │ date                 │ message                                                         │
├────────┼───────────────────────┼──────────────────────────────────────────────────────────────────┤
│ debug │ 2026-Jan-11 12:36:26 │ NSClient++ 0.4.0 2026-01-11 x64 booting...                      │
│ debug │ 2026-Jan-11 12:36:26 │ Booted settings subsystem...                                    │
│ debug │ 2026-Jan-11 12:36:26 │ Archiving crash dumps in: C:\src\build\nscp/crash-dumps         │
│ debug │ 2026-Jan-11 12:36:26 │ Found: CheckExternalScripts                                     │
│ debug │ 2026-Jan-11 12:36:26 │ Found: CheckSystem                                              │
│ debug │ 2026-Jan-11 12:36:26 │ Found: Checkhelpers                                             │
│ debug │ 2026-Jan-11 12:36:26 │ Found: LuaScript                                                │
│ debug │ 2026-Jan-11 12:36:26 │ Found: NRPEServer                                               │
│ debug │ 2026-Jan-11 12:36:26 │ Found: WEBServer                                                │
╰────────┴───────────────────────┴──────────────────────────────────────────────────────────────────╯

Or to load and enable a module you can:

$ check_nsclient nsclient modules use CheckHelpers
Successfully loaded and enable module CheckHelpers

Or you can execute queries:

$ check_nsclient nsclient queries execute-nagios check_cpu
OK: CPU load is ok.|'total 5m'=10%;80;90 'total 1m'=10%;80;90 'total 5s'=7%;80;90

As well as launch the new interactive client:

check_nsclient nsclient client

image

The client is included in the installer or it can be downloaded separately below as check_nsclient

One benefit of this client is that it can output everything as text, json, yaml or csv making it easy too integrate in any system:

$ check_nsclient --output json nsclient queries execute check_cpu
{
  "command": "check_cpu",
  "lines": [
    {
      "message": "OK: CPU load is ok.",
      "perf": {
        "total 1m": {
          "value": 12.0,
          "unit": "%",
          "warning": 80.0,
          "critical": 90.0,
        },
        "total 5s": {
          "value": 21.0,
          "unit": "%",
          "warning": 80.0,
          "critical": 90.0,
        },
        "total 5m": {
          "value": 11.0,
          "unit": "%",
          "warning": 80.0,
          "critical": 90.0,
        }
      }
    }
  ],
  "result": 0
}

You cal also have multiple profiles (foo) and connect to remote systems (--url):

check_nsclient nsclient auth login foo --url https://127.0.0.1:8443 --password PASSWORD --insecure
# ...
check_nsclient --output json nsclient --profile foo queries execute check_cpu

Once your are done you can log out (and remove credentials from credential store);

check_nsclient nsclient auth logout

Download

You can download the new version from GitHub

// Michael Medin

0.9.14 New release

REST API updates

Removed some old (deprecated) rest API endpoints so hence forth use the versioned apis under /api. The main goal here was to remove the outdated json library and the protobuf to json conversion.

The old check endpoints have NOT been removed to retain compatibility with Icinga and similar tools.

In addition to this I have also added numerous integration test to help to keep the APIs stable.

Installer improvments

The installer has been updated a lot to behave more predictably and in general work better. I have also added numerous tests to the installer to ensure less accidental breaking changes in the future.

Should not impact anything but instead of a dedicated Json library we now use boost to reduce number of dependencies. Removed sample config from installer (as you can easily generate the config i removed it from the installer).

Web UI improvements

The web interface has gotten a medium overhaul improving settings and queries.

  • You can now change setting under modules.
  • Settings now have widgets for boolean settings
  • Settings view now show all settings not just changed ones.
  • You can now use " in queries when executing from the Web UI so "filter=1 > 2" is now possible,

Modern TLS Support for remote settings

Remote settings via https (TLS) has been improved to now support TLS 1.3 as well as certificate validation. This is configure in boot.ini (NOT nsclient.ini as that's the file loaded remotely).

Sensitive keys

Added the ability to mark keys as sensitive which can then be configured to be stored in Windows credential manager. Meaning you now have a way to keep secrets and passwords out of the config file.

Restored Linux builds

While Linux support is a work in progress it is now possible to build on windows and piplines for building on windows. "Soon(TM)" I will add some packages and config files and such to make it more usable.

Bug-fixes

Numerous bug fixes and minor enhancments.

Download

You can download the new version from GitHub

// Michael Medin

0.7.0 Improved support for modern Windows

Changes since 0.6.9 (last official release).

Modern Windows detection for check_os_version

We now use the build number to detect OS versions above Windows 10. This means if you want to actually check that a version is above Windows 10 you need to include build number in your check.

check_os_version warn="version lt 10 or build lt 26100"
L        cli OK: OK: Windows 11 24H2 (10.0.26100)

Enhancements and experimental support for Pdh based check_cpu.

This version has some PDH (Performance data Helpers) fixes and improved error handling and introduces an experimental new option to switch check_cpu to use PDH instead of APIs. This is experimental and intended to solve the issue with incorrect, negative or zero values on some machines with more than 12 cores. The main issue is that PDH is messy. It is localized and has historically been prone to strange issues and errors such as counter index getting corrupted and similar issues so lets ee how this works before making it the default.

To switch change the following configuration:

[/settings/system/windows]
use pdh for cpu=true

Check CPU load values now uses more standard keywords: * idle * user * system

Old keywords are still retained for compatibility, so this is a non-breaking change.

We also added a short-hand option cores for expanding all cores:

check_cpu cores
L        cli OK: OK: CPU load is ok.
L        cli  Performance data: '0 5m'=58%;80;90 '1 5m'=47%;80;90 '10 5m'=56%;80;90 '11 5m'=42%;80;90 '2 5m'=59%;80;90 '3 5m'=49%;80;90 '4 5m'=56%;80;90 '5 5m'=45%;80;90 '6 5m'=57%;80;90 '7 5m'=43%;80;90 '8 5m'=57%;80;90 '9 5m'=39%;80;90 'total 5m'=51%;80;90 '0 1m'=65%;80;90 '1 1m'=52%;80;90 '10 1m'=65%;80;90 '11 1m'=48%;80;90 '2 1m'=64%;80;90 '3 1m'=52%;80;90 '4 1m'=62%;80;90 '5 1m'=65%;80;90 '6 1m'=70%;80;90 '7 1m'=51%;80;90 '8 1m'=61%;80;90 '9 1m'=46%;80;90 'total 1m'=58%;80;90 '0 5s'=65%;80;90 '1 5s'=46%;80;90 '10 5s'=56%;80;90 '11 5s'=42%;80;90 '2 5s'=70%;80;90 '3 5s'=57%;80;90 '4 5s'=52%;80;90 '5 5s'=45%;80;90 '6 5s'=70%;80;90 '7 5s'=40%;80;90 '8 5s'=48%;80;90 '9 5s'=41%;80;90 'total 5s'=53%;80;90

Lua

The biggest new change here is the re-added Lua support. The Lua support has been changed a bit so it might not be 100% compatible with old scripts. As there is not much documentation for Lua scripting, I plan to add that soon. And doing that I will highlight the main differences.

One thing still missing in Lua is protocol buffer support This means you can only create "simple function" is returning code, string and performance data. But given the nature of Lua I think this is acceptable for the time being.

But in general "optional parameters" to functions are no longer optional. So for instance:

local reg = Registry()
reg:simple_function('lua_test', test_func_query)

local settings = Settings()
str = settings:get_string('/settings/lua/scripts', 'testar')

local core = Core()
code, msg, perf = core:simple_query('lua_test')

Will now require to be written as:

local reg = Registry()
reg:simple_function('lua_test', test_func_query, '')

local settings = Settings()
str = settings:get_string('/settings/lua/scripts', 'testar', '')

local core = Core()
code, msg, perf = core:simple_query('lua_test', {})

The other change is that construction object is now generally done with new where before it was done with various functions like Core() here however I have retained backwards compatibility so both should be possible.

But in general the quality of error handling and such is much better and I will as I said expand the documentation and add some more examples and such.

check_mk

As a side note experimental check_mk support was also added back. This is experimental in so far as I have only verified it with NSClient++ not actual check_mk so will need to look into that next. Also note that check_mk is experimental currently it only provides the version and agent name. If there is genuin interest, this could easily be extended so please do let me know...

The way check_mk works is that the module only provides the communication layer and the data provided is provided by a Lua script (hence requiring Lua support). So the current script looks like so:

function server_process(packet)
    s = section.new()
    s:set_title("check_mk")
    s:add_line("Version: 0.0.1")
    s:add_line("Agent: nsclient++")
    s:add_line("AgentOS: Windows")
    packet:add_section(s)
end

reg = mk.new()
reg:server_callback(server_process)

So here we need to extend the packet to include more data and other sections for proper check_mk support.

Installer:

  • Removed padded version numbers from installer (this caused issues with upgrade)
  • Installer is now built with openssl presumably fixing remote config via https (have not verified this yet)
  • Enabled WebUI by default in installer (open can still be used to disable)
  • Added option to disable installing the service in installer

Security:

  • Added option to configure ciphers in the web server (default is TLS 1.2 but now you can set 1.3 if you prefer)
  • Default TLS (NRPE et al.) is now 1.2+ instead of only 1.2
  • Improved some options and added docs for using NRPE with certificates and Nagios…
  • Installer now installs the NRPE 2048 bit DH key

Other changes

  • Fixed check_nscp_verison parsing new semantic version
  • Added error messages for login failure via web browser
  • Updated build instructions
  • Fixed integer overflow in check_files.vbs script
  • Fixed status in summary text not matching actual summary when no results were found in filters (see UNKNOWN: OK in this example)
    check_drivesize "filter=drive='foobar'"
    L        cli UNKNOWN: OK: No drives found
    L        cli  Performance data:
    
  • Fixed numerous spelling and grammar issue in the documentation.
  • Removed breakpad (replaced by restart watchdog and log files, but wont create and submit crash dumps (instead windows creates dumps which can be used))
  • Bumped dependencies

Dependencies

Library Version
Boost 1.82.0
Cryptopp 8.9.0
Lua 5.4.7
OpenSSL 1.1.1w
Protobuf 21.12
TinyXml2 10.1.0

Download

You can download the new version from GitHub

// Michael Medin

0.6.9 Fix installer bug

New versions out

As you probably notice, I do not always update the news section when new versions are released. If you want to know about new versions, you can always check the GitHub releases page Instead here I post when there are new and important updates.

And the latest release fixes an important installer issue where upgrading from 0.4.x or 0.5.x would wipe the existing configuration. So be sure you do not upgrade to any of the older versions unless you want to reconfigure. Other changes include some more installer issues and WEB server issues as well as new signature for the MSI files.

Changes

  • Fixes config is overwritten by installer when upgrading from 0.4.x or 0.5.x
  • Makes TLS default for web server (so enabled web server will now be exposed on https://localhost:8443)
  • Fixed broken TLS support in the WEBServer
  • Added signatures to MSI (currently using a "personal signature" as I haven't managed to get Microsoft to cooperate)
  • Metrics added to the WebUI and new welcome screen
Dependency Version Date
Boost 1.82.0 2023-04-15
OpenSSL 1.1.1w 2023-09-11
Python 3.11.0 2022-10-24
Crypto++ 8.8.0 2023-05-25
Protocol Buffers 21.12 2022-12-22

There are some other dependencies as well that will be isolated and versioned soon.

There is a forum thread for this release here

Download

You can download the new version from GitHub

Next version

There is also a pre-release of the next version available on the GitHub releases page. This includes: * Some security improvements * Some installer improvements * documentation about using certificate-based authentication with NRPE and Nagios * Along with the usual minor bug fixes and improvements.

// Michael Medin