# Licensing Overview (/licensing)



Every KubeMQ server needs a license to start, in every deployment mode — standalone
binary, Docker, Kubernetes with the operator, and Kubernetes without it. There is no
unlicensed or "community" mode. This page explains the model; the pages that follow
show how to obtain and supply a license for each situation.

<Cards>
  <Card title="Start a 30-day trial" href="/licensing/trial" description="Get a free trial key from kubemq.io/trial — one installation, 30 days, no sales call." />

  <Card title="Use a license key" href="/licensing/license-key" description="KUBEMQ_LICENSE_KEY for Docker, Compose, Helm and raw manifests; activation, caching, regeneration." />

  <Card title="Air-gapped installations" href="/licensing/air-gap" description="A signed license file verified locally — no network access, ever." />

  <Card title="Kubernetes" href="/licensing/kubernetes" description="CRD fields, the operator's role, the lease cache Secret, and the RBAC the server needs." />

  <Card title="Troubleshooting" href="/licensing/troubleshooting" description="Every licensing log line, its cause, and its fix." />

  <Card title="Usage reporting" href="/licensing/usage-reporting" description="Exactly what an online server sends, how often, and what is never sent." />
</Cards>

## Key or file [#key-or-file]

There are two ways to license a server. They differ only in whether the server talks to
the licensing service.

|                  | License key (online)                                                                       | License file (offline)                                                                   |
| ---------------- | ------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------- |
| What you receive | A 43-character key, shown once when it is issued                                           | An armored text file (`-----BEGIN KUBEMQ LICENSE-----`)                                  |
| How you pass it  | `KUBEMQ_LICENSE_KEY`                                                                       | `KUBEMQ_LICENSE_FILE` (a path) or `KUBEMQ_LICENSE_DATA` (the contents)                   |
| Network          | Activates once per installation, then refreshes hourly against `https://license.kubemq.io` | None. The file is verified locally with the public key embedded in the server binary     |
| Who it is for    | Trials, and any installation that can reach the internet                                   | Air-gapped networks, and networks whose egress rules cannot allow the licensing endpoint |
| Usage reporting  | Yes — see [Usage reporting](/licensing/usage-reporting)                                    | No — an offline server makes zero outbound connections                                   |
| Revocation       | Possible, by a signed and confirmed revocation (below)                                     | Impossible for a file already issued; files expire and are reissued                      |

If both a key and a file are set, the **file wins** and the server logs a warning. If
neither is set, the server refuses to start with exit code 3.

<Callout type="info">
  The **license key** and the **license id** are different things. The id is a public
  handle that appears in logs, the dashboard and usage reports. The key is a secret used
  only to activate; it is stored by KubeMQ only as a hash. A key can be regenerated
  without affecting running servers — they hold a lease, not the key.
</Callout>

## The lease [#the-lease]

An online server never runs on the key itself. On first boot it **activates**: it sends
the key plus its installation fingerprint to the licensing service and receives a
**lease** — a signed token valid for **7 days** (24 hours for trials). The lease is
cached on disk under the server's store directory (`<store>/license/`) and is what the
server verifies from then on.

While the server runs it **refreshes** the lease every &#x2A;*60 minutes (±10% jitter)**.
Each refresh returns a freshly signed lease, so the 7-day window keeps sliding forward
for as long as the server can reach the endpoint. If a refresh fails the server keeps
running on the cached lease and retries with backoff (1, 2, 5, 15, then 30 minutes).

The file used by air-gapped installations is the same kind of token with a longer
validity — up to one year — and no refresh.

## What is checked, and when [#what-is-checked-and-when]

* **At boot.** The server resolves its input (file, data, then key), verifies the
  signature, the signing key id, the algorithm and the expiry, and checks that the token
  was issued to this installation's fingerprint. An online server with no cached lease
  activates first. Any failure here refuses to start.
* **Every minute.** The server checks the token it verified at boot, locally and with
  no network call: expiry (plus grace, see below), its own clock against the persisted
  high-water mark, and the warning conditions (over cap, silent, clock skew, revocation
  seen). It does not re-verify the signature or the fingerprint every minute — those
  were settled at boot, and a cache file edited while the server runs is caught at the
  next boot. This is what catches an expired file, an exhausted grace window, or a clock
  rolled backwards.
* **Every hour (online only).** The refresh described above. A changed entitlement —
  for example a trial converted to a paid plan, or an extended expiry — arrives with the
  next refresh, within an hour.
* **Every 15 minutes (online only).** The usage report. See
  [Usage reporting](/licensing/usage-reporting).

## Hard stop, and the fail-open window [#hard-stop-and-the-fail-open-window]

The rule is simple: &#x2A;*no valid license, no running server.** A server with no license
input, an invalid signature, a wrong fingerprint or an expired file does not start. A
running server whose license is revoked, or whose lease and grace are exhausted, drains
and exits.

The one thing that never stops a running server is **a network problem**. If the
licensing service is unreachable — DNS failure, outage, firewall change — the server
keeps running on its cached lease. When the lease's 7 days pass, it enters a **grace
period** (`grace_days`, default 7, set per license between 0 and 30; trials have 2
days). During grace it runs normally and logs a warning every minute with the days
left. Only when lease **and** grace are both exhausted does it drain and exit.

**The maximum an online server runs without ever reaching the licensing service is
lease + grace: 7 days + `grace_days`.** For a trial that is 24 hours + 2 days, which is
why a trial server must reach the endpoint at least every 3 days.

## Revocation: signed, confirmed, drained [#revocation-signed-confirmed-drained]

A revocation is the only way a running server is stopped before its lease and grace run
out, and it is deliberately hard to trigger:

1. **Signed.** A revocation is a token signed by the licensing service with the same key
   that signs leases. An HTTP error — a 403, a 401, a 404, a 5xx — never stops a server
   on its own. The server keys on the presence of a valid signed revocation, not on a
   status code.
2. **Confirmed.** The server counts a revocation only after seeing **three** fresh
   assertions **at least 10 minutes apart** — both the assertion's issue time and the
   moment the server received it must be 10 minutes after the previously counted one,
   so a burst of freshly minted assertions is one confirmation, not three. After the
   first one it re-polls every 10 minutes and reports `revocation.seen_count` in
   `GET /api/v1/license`. A replayed assertion (wrong nonce) is not counted. Counted
   assertions are persisted (`<store>/license/revocation.json`): a restart with one or
   two on record resumes the 10-minute polling with the count intact.
3. **Drained.** After the third confirmation the server stops accepting new connections
   and subscriptions, waits for the drain window (`KUBEMQ_LICENSE_DRAIN_SECONDS`, default
   300\) plus, in a cluster, a per-node stagger (a hash of the node's host name modulo
   600 seconds, so nodes leave one at a time), sends a final usage report with
   `activity: "stop"`, and then stops with exit code 3.

Revocations are issued only by an explicit, typed administrative action. Nothing
automatic — silence, exceeding an installation cap, rate limiting, an ingest error —
produces one. A disabled license simply stops receiving new leases and runs out at lease

* grace.

## Commercial expiry versus lease expiry [#commercial-expiry-versus-lease-expiry]

Every token carries two dates:

| Claim                                 | Meaning                                                                                   | When it passes                                                                                                                      |
| ------------------------------------- | ----------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `exp` — lease expiry                  | How long this particular token is valid: 7 days online (24 h trial), up to 1 year offline | Online: grace starts, and refresh keeps trying. Offline: the server drains and exits (with a 5-minute leeway)                       |
| `kmq.license_exp` — commercial expiry | The end of your contract or trial                                                         | The licensing service stops issuing new leases. The running server keeps going until its current lease + grace runs out, then stops |

Both are shown in `GET /api/v1/license` (`lease_expires_at`, `license_expires_at`) and
by `kmq license`, together with `run_until` — the exact moment the server will drain if
nothing changes.

## Exit code 3 [#exit-code-3]

A licensing refusal at boot, and a licensing-driven stop at runtime, always exit with
**code 3**. Exit 1 remains a durability fault and exit 0 a clean shutdown, so a
restart policy or a probe can tell them apart. Every licensing log line that refuses or
stops ends with a link into [Troubleshooting](/licensing/troubleshooting) naming the
exact cause.

## Enforcement by deployment mode [#enforcement-by-deployment-mode]

The server itself enforces the license in every mode. Kubernetes detection changes only
how the installation fingerprint is derived and how `source.type` is reported in usage;
it never changes whether licensing applies.

### Standalone binary [#standalone-binary]

|             |                                                                                           |
| ----------- | ----------------------------------------------------------------------------------------- |
| Input       | `KUBEMQ_LICENSE_KEY`, or `KUBEMQ_LICENSE_FILE` / `KUBEMQ_LICENSE_DATA` in the environment |
| Fingerprint | A random id generated on first boot, persisted at `<store>/license/instance.id`           |
| Cache       | `<store>/license/` — must survive restarts, so keep the store on a persistent path        |
| Enforced by | The server                                                                                |

### Docker [#docker]

|             |                                                                                                                                        |
| ----------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| Input       | `-e KUBEMQ_LICENSE_KEY=…`, or a mounted file with `-e KUBEMQ_LICENSE_FILE=/path`                                                       |
| Fingerprint | Persisted at `<store>/license/instance.id` inside the store volume                                                                     |
| Cache       | `<store>/license/` — **mount a volume** at `/kubemq/store`; without one every container restart is a first boot and a new installation |
| Enforced by | The server                                                                                                                             |

### Kubernetes with the operator [#kubernetes-with-the-operator]

|             |                                                                                                                                                                                                                                                                                                                                                        |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Input       | `spec.licenseKey` / `spec.licenseFile` on the `KubemqCluster`, or `spec.licenseKeySecretRef` / `spec.licenseFileSecretRef` pointing at a Secret; the operator injects `KUBEMQ_LICENSE_KEY` or `KUBEMQ_LICENSE_DATA` into the pods                                                                                                                      |
| Fingerprint | The UID of the `kube-system` namespace, read by the server through a ClusterRole the chart installs                                                                                                                                                                                                                                                    |
| Cache       | `<store>/license/` on the PersistentVolumeClaim; the operator additionally copies the last good lease into a Secret named `<cluster>-license-cache` so a pod rescheduled onto a fresh volume does not start from a first boot                                                                                                                          |
| Enforced by | The server. The operator only refuses to create or update a cluster whose **offline file** fails signature or revocation checks (a key is never verified by the operator), clamps the replica count to the installation cap on first create when it knows the cap, and blocks growing a live cluster past the cap (condition `ReplicasOverLicenseCap`) |

### Kubernetes without the operator [#kubernetes-without-the-operator]

|             |                                                                                                                                                                                     |
| ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Input       | `KUBEMQ_LICENSE_KEY` or `KUBEMQ_LICENSE_DATA` from a Secret via `envFrom` / `secretKeyRef`                                                                                          |
| Fingerprint | The UID of the `kube-system` namespace — needs a ServiceAccount with `get` on `namespaces` for `kube-system`; without it the server falls back to a persisted id and logs a warning |
| Cache       | `<store>/license/` on a PersistentVolumeClaim (required)                                                                                                                            |
| Enforced by | The server                                                                                                                                                                          |

Details for both Kubernetes modes are in [Kubernetes](/licensing/kubernetes).

## What licensing cannot do [#what-licensing-cannot-do]

* A self-built or patched server binary can bypass any check. The supported artifact
  is the signed official image; the server reports its image digest in usage reports
  when the deployment injects it as `KUBEMQ_IMAGE_DIGEST` (see
  [Usage reporting](/licensing/usage-reporting)).
* An offline file can be copied to another machine that has the same fingerprint list.
  Its use is bounded by the file's expiry (at most one year) and by your contract, not by
  cryptography.
* The signing key is rotated by a server release. A compromised key stays trusted until
  the release that retires it is adopted.
