Licensing
Sentro self-hosted uses Ed25519-signed license keys to control which edition you're running. Without a license key, the system runs in Community mode for free. With a valid license key, paid features unlock based on the edition encoded in the key.
Editions
| Feature | Community | Team | Business | Enterprise |
|---|---|---|---|---|
| Price | Free | $2,000 one-time | $3,500 one-time | $5,000 one-time |
| Monitors | 5 | 50 | 250 | Unlimited |
| Check interval | 5 min | 1 min | 30s | 10s |
| Team members | 1 | 10 | 50 | Unlimited |
| Teams / orgs | 1 | 10 | 25 | Unlimited |
| Heartbeat monitors | 2 | 20 | 100 | Unlimited |
| Status pages | 1 | 5 | 20 | Unlimited |
| Data retention | 90 days | 365 days | 730 days | 730 days |
| Alert channels | Email, Slack, webhook | Email, Slack, webhook | Email, Slack, webhook | Email, Slack, webhook |
| REST API | No | Yes | Yes | Yes |
| Outbound webhooks | No | Yes | Yes | Yes |
| SLA reporting | No | Yes | Yes | Yes |
| OIDC SSO | No | No | Yes | Yes |
| Update renewal | Free forever | $200/yr | $600/yr | $2,000/yr |
How It Works
- License keys are Ed25519-signed tokens that encode the edition, customer info, and expiry date
- The public key is embedded in the application — signatures are verified at startup
- The app reads the
LICENSE_KEYenvironment variable and unlocks features accordingly - If the key is missing, invalid, or tampered with, the app falls back to Community mode
- An expired license does not disable the application — it only means you're no longer entitled to updates. A banner is shown in the dashboard to remind you to renew.
Detection Logic
SELF_HOSTED env | LICENSE_KEY env | Result |
|---|---|---|
true | Not set | Community edition |
true | Valid key | Edition from key (Team/Business/Enterprise) |
true | Invalid/tampered key | Community edition (with console warning) |
| Not set | Not set | SaaS mode (cloud plans) |
In Docker Compose you set SENTRO_LICENSE_KEY in .env; the stack forwards it to the containers as LICENSE_KEY and sets SELF_HOSTED=true for you. In Helm you set secrets.licenseKey, and config.selfHosted already defaults to true.
Applying a License Key
Docker Compose
Put the key in your .env file as SENTRO_LICENSE_KEY — the compose stack passes it into every service as LICENSE_KEY:
SENTRO_LICENSE_KEY=eyJ2IjoxLCJpZCI6ImFiYzEyMyIsImVkaXRpb24iOiJ0ZWFtIi4uLn0.c2lnbmF0dXJl...
Then recreate the stack:
docker compose up -d --force-recreate
docker compose restart is not enough. The plan limits stored in the database are written by the one-off migration job, which only runs when containers are recreated. Use up -d --force-recreate (or down followed by up -d) after changing the license key.
Kubernetes (Helm)
Set the license key via Helm values:
helm upgrade sentro ./helm/sentro \
--reuse-values \
--set secrets.licenseKey="eyJ2IjoxLCJpZCI6ImFiYzEyMyIsImVkaXRpb24iOiJ0ZWFtIi4uLn0.c2lnbmF0dXJl..."
Or add it to your values.yaml:
secrets:
licenseKey: 'eyJ2IjoxLCJpZCI6ImFiYzEyMyIsImVkaXRpb24iOiJ0ZWFtIi4uLn0.c2lnbmF0dXJl...'
The migration job runs as a post-upgrade hook and re-seeds the plan automatically.
Upgrading Editions
To upgrade from one edition to another (e.g. Community to Team, or Team to Business):
- Obtain the new license key for the higher edition
- Replace the key in your
.env(SENTRO_LICENSE_KEY) or Helm values (secrets.licenseKey) - Recreate the stack so the migration job re-runs
The seed step deactivates the previous plan, creates the plan matching the new edition, and moves every organisation onto it. Existing monitors and data are untouched.
Verifying the edition took effect
Open the admin panel and go to System → Licenses. On a self-hosted install that page shows your edition, expiry, limits, and current usage. The dashboard's billing page shows the same limits for end users.
Revocation Check (optional)
If you set LICENSE_CHECK_URL, each instance makes one background call on startup asking whether the license has been revoked. It is entirely optional:
- Leave it unset and the product never phones home — suitable for air-gapped installs
- If the check cannot be reached, the license stays valid (fail open)
- Startup is never blocked by the check
LICENSE_CHECK_URL=https://license.sentro.dev
Generating License Keys (Vendor)
This section is for Sentro operators (vendors) who need to generate license keys for their customers. End users receive pre-generated keys and only need to follow Applying a License Key above.
The @sentro/license package includes a CLI tool for key generation and management. All commands run from the repository root.
1. Generate a Key Pair
First, generate an Ed25519 key pair. This only needs to be done once — the private key is used to sign all future licenses, and the public key is embedded in the application code.
pnpm --filter @sentro/license keygen
This creates two files in packages/license/vendor-keys/:
private.pem— Keep this secret. Used to sign license keys.public.pem— Embedded in the application. Used to verify licenses at runtime.
Never commit private.pem to version control. It is already in .gitignore. If the private key is compromised, anyone can generate valid license keys for any edition.
After generating a new key pair, update the embedded public key in packages/license/src/verify.ts with the contents of public.pem (the base64-encoded key, without PEM headers).
2. Sign a License Key
Generate a signed license key for a customer:
pnpm --filter @sentro/license sign \
--key packages/license/vendor-keys/private.pem \
--edition team \
--customer "Acme Corp" \
--email "admin@acme.com" \
--expires 2027-06-15
Parameters:
| Flag | Required | Description |
|---|---|---|
--key | Yes | Path to the Ed25519 private key PEM file |
--edition | Yes | Edition: community, team, max, or enterprise |
--customer | Yes | Customer name (encoded in the license payload) |
--email | Yes | Customer email (encoded in the license payload) |
--expires | Yes | Expiry date in YYYY-MM-DD format (controls update entitlement) |
Output:
License key generated:
eyJ2IjoxLCJpZCI6IjAxOTVkYTc1LTg3NzAtNzk5OC1hM2I0LWE4Mjg1YzM3MDE5ZSIsImVk
aXRpb24iOiJ0ZWFtIiwiY3VzdG9tZXJOYW1lIjoiQWNtZSBDb3JwIiwiY3VzdG9tZXJFbWFp
bCI6ImFkbWluQGFjbWUuY29tIiwiaXNzdWVkQXQiOiIyMDI2LTAyLTIwVDA5OjAwOjAwLjAw
MFoiLCJleHBpcmVzQXQiOiIyMDI3LTA2LTE1VDAwOjAwOjAwLjAwMFoifQ.SIGNATURE_HERE
Edition: team
Customer: Acme Corp
Email: admin@acme.com
Expires: 2027-06-15
Send this key to the customer. Docker Compose users put it in .env as SENTRO_LICENSE_KEY; Helm users set secrets.licenseKey.
3. Verify a License Key
Inspect and verify an existing license key:
pnpm --filter @sentro/license verify <LICENSE_KEY>
Example output for a valid key:
License is valid.
ID: 0195da75-8770-7998-a3b4-a8285c370192
Edition: team
Customer: Acme Corp
Email: admin@acme.com
Issued: 2026-02-20
Expires: 2027-06-15
Updates expired: No
Example output for an expired key:
License is valid (updates expired).
ID: 0195da75-8770-7998-a3b4-a8285c370192
Edition: team
Customer: Acme Corp
Email: admin@acme.com
Issued: 2025-01-15
Expires: 2026-01-15
Updates expired: Yes
Note: The application continues to work. Only update entitlement has expired.
Renewal Workflow
When a customer's update entitlement expires:
- A yellow banner appears in their dashboard: "Your license update entitlement expired on {date}."
- The application continues to work at full capacity — no features are disabled
- To renew, generate a new license key with an extended expiry date and send it to the customer
- The customer replaces the key in their configuration and recreates the stack
License Key Format
For reference, license keys use the format:
base64url(JSON_payload).base64url(Ed25519_signature)
The JSON payload contains:
{
"v": 1,
"id": "uuid7",
"edition": "team",
"customerName": "Acme Corp",
"customerEmail": "admin@acme.com",
"issuedAt": "2026-02-20T00:00:00.000Z",
"expiresAt": "2027-06-15T00:00:00.000Z"
}
The Ed25519 signature ensures the payload cannot be tampered with. Even though the source code is public, license keys cannot be forged without the private key.
Troubleshooting
"Falling back to Community edition" in logs
This means the LICENSE_KEY is set but could not be verified. Common causes:
- Copy-paste error — Ensure the full key was copied without line breaks or extra whitespace
- Wrong key pair — The key was signed with a different private key than the one whose public key is embedded in the application
- Corrupted key — The key string was modified after generation
Run pnpm --filter @sentro/license verify <key> to check the key independently.
Limits not updating after setting LICENSE_KEY
The plan is updated during database seeding, which runs as part of the migration service on startup. Make sure:
- The migration service has run after you set the new
LICENSE_KEY - Recreate all services:
docker compose up -d --force-recreate - Check migration logs:
docker compose logs migrate
Banner says "License update entitlement expired"
This is informational only. Your application is fully functional. To remove the banner, renew the license by generating a new key with a future expiry date.