Skip to content

Licensing

The free core needs no licence key at all: it is AGPL-3.0 software that is fully functional on its own, and nothing about it asks a server for permission.

Pro modules are different. They are gated by an online check against the Nyxtrace licence server, and this page says exactly what that means for an appliance in your basement.

The key is an identifier, not a permission

Section titled “The key is an identifier, not a permission”

A licence key carries no rights. It is a short identifier that says which subscription this installation belongs to; the entitlements — which modules, which limits, until when — live on the server and are looked up there.

A self-contained key that grants rights by itself was the other option, and it was rejected for three concrete reasons: it cannot be revoked, it cannot be moved between installations without handing the old one a permanent copy, and it cannot carry the part of Pro that is only worth paying for because a server keeps it current.

The appliance exchanges its key for a short-lived entitlement token:

Property Value
Signature Ed25519, by the licence server
Time to live 6 hours
Renewal Every 1–2 hours, in the background
Bound to The installation identity (install_id) — the seat
Transport HTTPS to the licence server, with certificate pinning

The token is what the Pro modules actually check, and the public signing key is compiled into the Pro binaries. A renewal that succeeds simply replaces the token; nothing in the interface moves.

Revocation takes effect at the next renewal. Cancel a subscription, move a seat, or reset an installation in the portal, and the affected appliance stops being entitled within one renewal interval — an hour or two, not a month, and without anyone having to reinstall anything.

Seats are bound per installation. The identity is the random installation identifier described under instance registration — a value the appliance writes once for itself. Restore the installation from a backup and the seat comes with it, because the identifier is part of the backup.

No hardware fingerprinting. No MAC address, no disk serial, no CPU ID, no machine ID is read to lock a licence to a machine. There is nothing to break when you move the appliance to a bigger box.

The governing rule: never break what already works.

State Behaviour
Entitled Pro modules active
Server unreachable, within 72 hours Everything still active, with a visible warning and the remaining time
Server unreachable, past 72 hours Pro modules go read-only: existing data, incidents and reports stay visible and exportable. New Pro evaluations and response execution rest.
Revoked or expired subscription The same read-only state, at the next renewal
No key configured Pro modules do not start and report the exact reason. The free core runs unchanged.

Seventy-two hours is an operator decision rather than a law of nature: it is long enough to cover a weekend outage on our side and a router replacement on yours, and it is documented so nobody has to guess.

Never, under any circumstances: data deletion, an ingest stop, incident loss, a crash, a start-up failure, or a silent behaviour change. The core keeps running throughout — ingest, storage, detection, incidents, search and export do not depend on the licence check at all. A licence problem must never blind your network.

And one specific guarantee: a lapsed entitlement may not leave an existing block hanging. The expiry mechanism in the response module is independent of the licence, so a containment that is supposed to lapse lapses.

What the internet connection is actually for

Section titled “What the internet connection is actually for”

Pro is not a switch that unlocks code you already downloaded. A good part of what it sells only exists on the server side and only makes sense for an activated installation:

  • Threat-intelligence feeds, kept current centrally.
  • Model packs, published and versioned by us.
  • The AI analyst quota, which costs real money per request.
  • Signed release manifests for the Pro modules, so an appliance can tell a genuine module build from something else.

That is why the check is online: the thing being paid for is partly a service, not only a binary.

The licence check and instance registration share one identity and one channel. The full field list, what is never sent, and the switch are documented under instance registration and telemetry. On the pro plan registration is required, because it is the seat binding: there is no state “Pro active, but not registered”.

Each Pro module asks once, at startup, and registers itself in the core’s capability registry only on success. There are no if licensed checks scattered through the code; a renewal that fails withdraws the capability at the boundary instead of leaving half-working features behind.

The consequence you can see: the interface presents an unregistered module as not provisioned — exactly the way it already presents a source that is not configured. Not an upsell banner in the middle of a workflow, and not a button that fails when you press it.

GET /api/v1/license

Returns the tier, features, limits, status, the time the current entitlement expires and the reason for the current state. The status is valid, grace, expired, missing or invalid. The subject name is not disclosed to non-administrators.

An extension is a separate process speaking a versioned JSON protocol over standard input and output — not a shared library and not a compiled plugin. Each one ships a manifest that the same strict YAML loader validates:

extension:
id: example-source
version: 1.2.0
api_version: 1 # protocol version, not product version
kind: source # source | model | action | sink
requires_feature: connectors.example # empty means a free extension
exec: /opt/nyxtrace/ext/example-source
emits: [example.client, example.device]
config_schema: {} # generates the operator form
secrets: [username, password]
health_interval: 60s
rate_limit: { requests_per_minute: 30, burst: 5 }

Four verbs, one bounded line of JSON each way:

Verb Purpose
describe Confirm the manifest, report capabilities and protocol version
test The test-connection button. Must not write.
collect One bounded batch from a cursor
act Exactly one approved action, with a readback. Action kind only.

The trust boundary is narrow on purpose. An extension receives only its own configuration and its own secrets, through environment variables — never a tenant key, never a database connection, never database credentials. Its output is untrusted data: the core assigns tenant, sensor identity and trust class from the registry. An extension cannot grant an approval, change a threshold or invoke the executor.

It is also sandboxable by ordinary means, as a service unit with no new privileges, a strict system protection profile, its own user and its own network permissions.

Detection models stay declarative: a “model extension” is a package of YAML models plus a description, not a process. No foreign code executes in the detection path.

The bundle ships third-party components — the database, the packet source, the transport, the flow collector, Grafana, the dashboard’s design system — each under its own licence, with a third-party licence inventory in the release. Attribution requirements, including the CC-BY attribution for DB-IP Lite, are yours to keep visible where you publish results.