Platform: Licensing

Nexus GSLB enforces per-tier requests-per-second (RPS) limits and feature gates via cryptographically signed license tokens. The DNS server consults the licensing manager on every query — if the token bucket is exhausted the query is rejected with SERVFAIL.


License Token Format

A license token is a two-part, dot-separated structure:

base64url(JSON_payload).base64url(Ed25519_signature)

The signature covers the raw JSON bytes. Both parts use base64.RawURLEncoding (no padding).

JSON payload fields:

Field

Type

Description

tier

string

free, paid, pro, enterprise, or custom

maxRps

int

Per-license RPS override (0 = use tier default)

iat

int64

Unix timestamp — issue time

exp

int64

Unix timestamp — expiry (0 = never expires)

id

string

32-char hex UUID — unique per license

cid

string

Customer ID bound to this token

iid

string

(optional) Installation ID — node-locks the token


License Tiers

Tier

Default RPS

Notes

unlicensed

20 (configurable)

No valid token present

free

20 (configurable)

Signed free token required

trial

500

Auto-issued 30-day evaluation; enterprise-level feature access

paid

500

Entry-level commercial tier

pro

2,000

Mid-market tier

enterprise

1,000,000 (effectively unlimited)

Full-featured top tier

custom

1,000,000

Custom contract terms

expired

20 (configurable)

expiredFallbackRPS → defaultUnlicensedRPS → 20

Effective RPS is determined by:

  1. If maxRps > 0 in the token → use that value (overrides tier default)

  2. If maxRps == 0 → use tier default above

Per-tier feature and limit matrix:

Feature / Limit

Free / Unlicensed

Paid

Pro

Enterprise / Custom

Pool members per pool

3

10

50

Unlimited

Tenants

1

1

1

Unlimited

Cluster nodes

1

1

3

Unlimited

Remote probe agents

0

0

10

Unlimited

DNSSEC online signing

✗

✅

✅

✅

Filter chains

✗

✅

✅

✅

HTTP redirects

✗

✅

✅

✅

ACME certificate management

✗

✅

✅

✅

Alerting — email/webhook

✗

✅

✅

✅

Service discovery — Consul

✗

✅

✅

✅

Dual-run zone push (zonesync)

✗

✅

✅

✅

SLA uptime % / incident history

✗

✅

✅

✅

BGP route health injection

✗

✗

✅

✅

NATS clustering

✗

✗

✅

✅

Geo rules

✗

✗

✅

✅

DNS response rate limiting

✗

✗

✅

✅

Alerting — PagerDuty/Opsgenie

✗

✗

✅

✅

Service discovery — etcd

✗

✗

✅

✅

RUM (real-user measurement) routing

✗

✗

✅

✅

Progressive delivery rollouts

✗

✗

✅

✅

Remote probe agents (external vantage)

✗

✗

✅

✅

Signal-weight routing (carbon/cost)

✗

✗

✅

✅

DNS query anomaly detection (insights)

✗

✗

✅

✅

RPZ (DNS firewall)

✗

✗

✅

✅

Traffic shadowing (dark-testing)

✗

✗

✅

✅

Traffic globe (query-origin map)

✗

✅

✅

✅

Deployment gates (soak + auto-rollback)

✗

✗

✅

✅

Scriptable filter-chain steps

✗

✗

✗

✅

OIDC / SSO

✗

✗

✗

✅

Custom RBAC roles

✗

✗

✗

✅

Multi-tenancy

✗

✗

✗

✅

Audit logging

✗

✗

✗

✅

Trial licenses receive enterprise-level feature access for the duration of the trial period.

Trial Online Activation

On first startup with no license, gslbd auto-issues a trial. When license.serverURL is set (the default, https://www.gslb.nexus), it first registers the machine fingerprint with POST {serverURL}/api/v1/trial/register (500 ms timeout) before issuing the local trial token:

  • First registration (HTTP 201) — a full 30-day trial is issued.

  • Prior trial detected (HTTP 409) — a 7-day grace trial is issued, with a warning to contact licensing@gslb.nexus to purchase.

  • Server unreachable / timeout — activation fails open: a full 30-day trial is issued offline (logged at INFO).

Activation reuses license.serverURL, so setting it to "" (air-gap deployments) skips online activation entirely and always issues a full 30-day trial. The fingerprint is sha256(machine-id + install-id) truncated to 16 bytes — the same value used for node-locking — so it carries no PII.


Node Identity and Installation ID

Every gslbd installation generates a random install ID (install_id) on first startup and stores it in the rqlite datastore. In a cluster, the install ID is shared automatically because the datastore is Raft-replicated, so nodes which have not yet generated their own ID adopt the cluster's value.

The install ID is used to node-lock licenses. If a license token contains an iid field, the daemon rejects it unless iid matches the local install ID.

Floating vs. Node-Locked Licenses

Type

iid field

Accepted by

Use case

Floating

Absent

Any installation

Multi-node clusters, simple deployments

Node-locked

Present

One specific installation

Single-node, strong anti-reuse

Floating licenses are the recommended choice for clusters. Node-locked licenses are suited to single-node deployments where you want to prevent a token being reused elsewhere.

Viewing the Install ID

WebUI: Admin → License → Installation ID section

CLI:

gslbctl license status --server https://your-node:8880

API:

GET /api/v1/license

Response includes "installId" in the JSON body.


gslbd Configuration

License credentials are loaded in priority order:

  1. Environment variables (highest priority)

  2. settings table in the SQLite database (applied via API/WebUI/TUI)

  3. config.yaml

Environment variables:

Variable

Description

GSLB_LICENSE_PUBLIC_KEY

Ed25519 public key (base64url, 32 bytes)

GSLB_LICENSE_KEY

License token

GSLB_LICENSE_SERVER_URL

Override the revocation-check server URL (see below)

config.yaml:

license: publicKey: "" # Ed25519 public key (base64url) licenseKey: "" # License token defaultFreeRPS: 50 # RPS for free-tier licenses (default: 50) defaultUnlicensedRPS: 5 # RPS when no valid license is present (default: 5) expiredFallbackRPS: 20 # RPS when license has expired (default: 20) serverURL: "https://www.gslb.nexus" # revocation-check endpoint; "" disables polling entirely refreshInterval: 1h # how often to poll serverURL (default: 1h)

The publicKey must match the public key of the operator keypair used to sign tokens. It is safe to distribute; only the licensectl operator database contains the private key.


Applying a License

Licenses can be applied without restarting the daemon on all admin surfaces.

WebUI

Admin → License → paste token into the Apply License Token field → Apply Token.

The token is validated, hot-loaded into the running daemon, and persisted to the database for restart survivability.

gslbctl CLI

gslbctl license status --server https://your-node:8880gslbctl license apply --server https://your-node:8880 --token <token># or positionally:gslbctl license apply --server https://your-node:8880 <token>

REST API

# View current license statusGET /api/v1/license# Apply a new tokenPOST /api/v1/licenseContent-Type: application/json{"token": "eyJ0aWVy..."}

Both endpoints require license:read / license:write permission. The system API key (GSLB_API_KEY) always has access.

Environment Variable (Traditional)

Set in /etc/gslb/env and restart the service:

GSLB_LICENSE_PUBLIC_KEY=<base64url-ed25519-public-key>
GSLB_LICENSE_KEY=<token>

When GSLB_LICENSE_KEY is set, it takes precedence over any token stored via the API.


Revocation Checking

gslbd polls GET {serverURL}/api/v1/verify/{token} on refreshInterval (default 1h) to catch licenses revoked after the daemon already loaded them — without this, a revoked license stays valid until the next restart. On {"valid": false, "error": "revoked"} the daemon immediately drops to the unlicensed RPS limit (defaultUnlicensedRPS) without restarting. The check fails open: any network error, timeout, or non-200 response just logs a warning and keeps the current license state — a license server outage never takes down a paying customer's DNS.

This is intentionally configurable (serverURL, including setting it to "" to disable polling entirely) rather than hardcoded, for two reasons:

  1. Air-gap support is a shipped, marketed feature (see docs/ops/AirGap.md) — a customer running fully offline cannot have a mandatory phone-home baked in, full stop.

  2. It wouldn't meaningfully raise the bar anyway. Because the check fails open, a customer who actually wants to dodge revocation doesn't need to touch serverURL — blocking the default host at the firewall has the identical effect. Hardcoding the URL would only inconvenience legitimate air-gapped/restricted-network customers, not stop anyone determined to bypass it.

If stronger enforcement is ever wanted, the lever is the fail-open behavior itself (e.g. fail closed after N consecutive missed checks), not the URL's configurability — and that's a real product tradeoff (a license-server outage would then degrade paying customers), not a one-line change.


Token Bucket Rate Limiter

The licensing manager implements a token bucket:

  • Bucket capacity = effective RPS

  • Refill rate = effective RPS tokens per second

  • Each DNS query consumes one token

  • Empty bucket → SERVFAIL

  • Bucket starts full at daemon startup and after Reload


License Lifecycle Behaviour

State

Effective RPS

Notes

No license

defaultUnlicensedRPS (default 5)

Valid floating license

Tier or maxRps

Valid node-locked license (iid matches)

Tier or maxRps

Node-locked license (iid mismatch)

defaultUnlicensedRPS

Wrong installation

Expired license

expiredFallbackRPS → defaultUnlicensedRPS → 20

Invalid signature

defaultUnlicensedRPS

Tampered or wrong public key

Missing id field

Rejected

Prevents predictable tokens


Generating Licenses

Licenses are issued via the Nexus website. Log in, create a license for the relevant customer and tier, and copy the generated token.

The website signs tokens using an Ed25519 keypair it manages internally. You will need the corresponding public key to configure your nodes — this is available in the website's operator settings.


Cluster LicensingNew Installations

For a new cluster, start all nodes before any snapshot is exchanged and the install IDs will be generated independently on each node. To ensure the entire cluster shares one install ID (required for a single node-locked license to cover all nodes):

  1. Start the primary node first — it generates the install ID

  2. Start remaining nodes before they process any snapshots, or wipe their databases so they receive the primary node's snapshot before EnsureInstallID runs

In practice, floating licenses are the recommended approach for clusters. They require no install ID coordination and one token covers all nodes.

Existing Cluster: Upgrading to This Version

When upgrading an existing cluster to a version that includes install ID support:

  • Each node generates its own install ID independently on first startup with the new binary

  • No existing functionality is affected — licenses without an iid field (floating) continue to validate on all nodes

  • Cluster sync, DNSSEC, and all other features are unaffected

To check each node's install ID after upgrading:

# From any machine with gslbctl access:gslbctl license status --server https://lon-01:8880gslbctl license status --server https://eu-01:8880gslbctl license status --server https://lab-01:8880

If you later want a single node-locked token covering the whole cluster, the install IDs must all match. The simplest path is to issue one floating license — no install ID binding, works across all nodes with no additional configuration.


API ReferenceGET /api/v1/license

Returns the current license state for this node.

Permissions: license:read (all built-in roles)

Response:

{ "valid": true, "tier": "enterprise", "maxRps": 50000, "expiresAt": 2094742275, "licenseId": "c5f8cc4ea66715cb45379dfb4b6656ad", "customerId": "star-storm-development", "installId": "786a318b5f8ffa3daa36552f4d0b81a7"}

POST /api/v1/license

Applies a new license token. Validates, hot-reloads, and persists to the database.

Permissions: license:write (tenant_admin role only)

Request:

{"token": "eyJ0aWVy..."}

Response: Same as GET /api/v1/license reflecting the new state.


Security Notes

  • The Ed25519 private key never leaves the license issuer. Distributing the public key to nodes does not enable token forgery.

  • Tokens are cryptographically bound to a specific payload — they cannot be modified without invalidating the signature.

  • Rotating the issuer keypair requires updating GSLB_LICENSE_PUBLIC_KEY (or the API-stored value) on all nodes and re-issuing all active licenses signed with the new key.

  • Tokens applied via the API are stored in the settings table of the local SQLite database. Access to the database file grants read access to the token — protect database file permissions accordingly.


Was this article helpful?