Skip to content

Install the sensor

There are two ways to install a sensor, and they are here as equals. The one-click command is faster. The manual path is what you use when a change board will not run a script it has not read, or when the host has no direct internet access. Both end in the same place: a verified binary, an mTLS identity, and a running scanner.

Either way, you first create the sensor in the Console, which hands you a single-use token. The token is a claim check, not a credential you keep.

In the Console, open Sensors and click Add sensor. You get a command with a bootstrap token already filled in. The token is shown once and is valid for 30 minutes - long enough to paste it onto one machine. If it expires, click again.

(For scripted onboarding, Settings → Bootstrap Tokens mints tokens directly, with an optional machine-ID pin and a TTL up to 7 days.)

Terminal window
NEXTPKI_BOOTSTRAP_TOKEN=npbst.… sh -c "$(curl -fsSL https://sensor.nextpki.com/latest/install.sh)"

This downloads the installer, which then downloads the signed checksum list, verifies its signature, downloads the binary, checks it against the now-trusted checksum, installs it, sets up a hardened service, and registers with your token.

It is one line, and it is honest about what it does - but piping a script from the internet into a shell is a decision your change process may not allow. That is what Path B is for.

Every step of Path A, done by hand. Nothing here is a lesser option; it is the same artifacts, verified by you.

1. Download the release files.

Terminal window
base=https://sensor.nextpki.com/latest
curl -fsSLO $base/install.sh
curl -fsSLO $base/SHA256SUMS
curl -fsSLO $base/SHA256SUMS.sig
curl -fsSLO $base/release-key.pub
curl -fsSLO $base/nextpki-sensor-linux-amd64 # or your platform

2. Read the installer. It is a POSIX shell script. Read it. The point of the manual path is that you do not run what you have not seen.

Terminal window
less install.sh

3. Verify the signature yourself, with ssh-keygen - present on every Linux and every Mac, and the reason we sign with it (see the signature model):

Terminal window
printf 'nextpki-sensor-release %s\n' "$(cat release-key.pub)" > allowed_signers
ssh-keygen -Y verify -f allowed_signers -I nextpki-sensor-release \
-n file -s SHA256SUMS.sig < SHA256SUMS

A Good "file" signature line means the checksum list genuinely came from the NextPKI release process. The release key’s fingerprint is SHA256:+6znvJRuTIkoE47Bdt2fgWqp/DRfwAgjlyZrYDSJtvs; it is also printed on sensor.nextpki.com.

4. Check the binary against the verified list.

Terminal window
sha256sum -c SHA256SUMS --ignore-missing # 'shasum -a 256 -c' on macOS

5. Install and register. Move the binary somewhere on PATH, then register. The token goes in the environment, never on the command line (see why the token is in the environment):

Terminal window
install -m 755 nextpki-sensor-linux-amd64 /usr/local/bin/nextpki-sensor
NEXTPKI_BOOTSTRAP_TOKEN=npbst.… nextpki-sensor bootstrap --machine-id "$(hostname)"

Air-gapped hosts: do steps 1-4 on a machine with egress, carry the verified binary in, and register from a host that can reach api.nextpki.com on 443. The registration call is a single HTTPS request; only that one host needs the route.

What each layer actually protects, stated plainly so you can weigh it:

  • HTTPS proves the bytes came from sensor.nextpki.com and were not altered in transit. It does not prove they came from our build - anyone who took over the distribution host could serve their own bytes over perfectly valid HTTPS.
  • The ed25519 signature over SHA256SUMS closes that gap. The private key lives neither on the distribution host nor in the source tree, so a compromised host cannot produce a valid signature. This is the layer that matters.
  • What the signature does not cover: install.sh itself. It cannot - when you fetch the installer you have no key yet to check it against, and a key fetched next to it would come from the same attacker. So the installer’s integrity rests on HTTPS alone, and that is exactly why Path B has you read it before running it. Everything the installer downloads afterwards, it verifies against the embedded key.

We sign with ssh-keygen rather than openssl for a concrete reason: the openssl shipped on macOS (LibreSSL) cannot verify ed25519 at all. An installer that silently skipped verification because the tool was missing would be worse than no signature. OpenSSH is on every target and does the job.

The bootstrap token is passed as an environment variable, never as a command-line argument. A command line is visible in ps to every user on the host and lands in shell history; a URL query string lands in the access log of every proxy on the way. The environment keeps the token out of all three. It is single-use and consumed the moment it is redeemed, but there is no reason to leak even a spent one.

The sensor generates an ECDSA key pair locally, sends a certificate signing request, and receives a client certificate. Nothing secret travels upward - the private key is created on the host and never leaves it. Afterwards the data directory holds:

File Mode Contents
identity.json 0644 Sensor ID, tenant, machine ID, ingest endpoint
cert.pem 0644 mTLS client certificate
key.pem 0600 Private key - never transmitted
ca.pem 0644 CA bundle used to verify NextPKI

For a service install the data directory is /var/lib/nextpki-sensor (Linux) or /var/db/nextpki-sensor (macOS), owned by the service user. For a plain user run it is the platform data directory: ~/.local/share/nextpki-sensor on Linux (or $XDG_DATA_HOME/nextpki-sensor where that is set) and ~/Library/Application Support/nextpki-sensor on macOS. Override with --data-dir.

The token is consumed at this point; redeeming it a second time fails with token_already_used.

The one-click installer sets up a service by default: a dedicated non-root user (nextpki-sensor), the binary in /opt/nextpki-sensor/bin owned by that user, and a hardened unit - systemd on Linux, a LaunchDaemon on macOS. The hardening follows the same pattern as the NextPKI server units: ProtectSystem=strict, NoNewPrivileges, an empty capability set, restricted address families.

To install the binary only, without a service, pass NEXTPKI_NO_SERVICE=1.

There is no one-click installer for Windows yet - Path A is a POSIX shell script. Download the binary, register it, then register it as a service. Everything below runs in an elevated PowerShell; registering a service needs administrator rights.

Terminal window
$env:NEXTPKI_BOOTSTRAP_TOKEN = "npbst.…"
.\nextpki-sensor.exe bootstrap --machine-id $env:COMPUTERNAME
.\nextpki-sensor.exe service install -- --targets 10.0.0.0/24
Start-Service NextPKISensor

The data directory defaults to %ProgramData%\NextPKI\sensor, not %APPDATA%: the service runs as LocalSystem, whose roaming profile is buried under C:\Windows\System32\config\systemprofile. %ProgramData% is where a machine-wide agent belongs, and it is the same directory whether you bootstrap as yourself or as the service.

Everything after -- becomes the service’s own command line. This is not a stylistic choice: a Windows service is started by the Service Control Manager, not by a shell, so it inherits neither your environment variables nor the flags you used at install time. Scan targets, a proxy, a different health port - if the service should have it, it goes after --. sc qc NextPKISensor shows exactly what was stored.

That registry entry is readable by every account on the machine, so a proxy URL with an embedded password is readable too. The sensor warns when it stores one. Prefer a proxy that lets the NextPKI endpoints through without authentication - see network requirements.

Where the logs go. A Windows service has no console, so the sensor writes to the event log rather than to standard output. Look under Windows Logs → Application, source NextPKISensor, or:

Terminal window
Get-WinEvent -FilterHashtable @{LogName="Application"; ProviderName="NextPKISensor"} -MaxEvents 20

Errors and warnings arrive as their own event types, so the usual filters work. Elsewhere this job belongs to the supervisor - systemd puts it in the journal, launchd in its own log - which is why the destination is only spelled out here.

The service also restarts itself on failure (after 5s, then 30s, then 300s). A machine whose sensor died at 03:00 would otherwise simply stop being scanned, without saying so.

Removing the service leaves the identity alone, the same as install.sh --uninstall does elsewhere:

Terminal window
.\nextpki-sensor.exe service uninstall

Two things Windows does not have yet: an MSI, and a signed installer. Both are planned. Until then the verification steps from Path B apply unchanged - the SHA256SUMS signature covers the Windows binary exactly as it covers the others, and ssh-keygen ships with Windows 10 1809 and newer.

Remove everything later with install.sh --uninstall. It stops and removes the service and the binary, and names the identity directory rather than deleting it - throwing away a certificate and its private key is a decision for the operator, not a script. If the machine is gone for good, delete the directory it prints.

The sensor updates itself. On a schedule it fetches the signed release manifest, verifies it against the same embedded key, and - only if the offered version is newer than the running one - downloads, verifies and swaps its own binary, then re-executes. It never downgrades, and it never installs anything the signature does not cover.

Banks and other shops that distribute software through their own tooling turn this off with NEXTPKI_NO_SELF_UPDATE=1; the installer writes that into the service’s environment file when you set it. You then ship new versions the same way you ship everything else - the manual path above, re-run.

The sensor appears in the Console under Sensors, moving from pending to active once its first report lands. Configure what it scans on its detail page; see configuration. A sensor that stays pending did not reach the ingest endpoint - check network requirements.

A local health endpoint is available for your own monitoring, on 127.0.0.1:18080/healthz by default.

Building it yourself is explicitly permitted - see licensing. You need a Rust toolchain (1.80 or newer), and nothing else:

Terminal window
cargo build --release -p nextpki-sensor

(Earlier versions needed buf to generate protobuf bindings first. The sensor reports over REST now, so that step is gone.)

The release build is reproducible: the same commit produces byte-identical binaries, which is what lets you check a downloaded binary against one you built yourself. The build uses --remap-path-prefix so the build machine’s paths do not end up in the binary; deploy/sensor-release.sh in the repository is the exact recipe.