Run self-hosted Keyright fully air-gapped, with no outbound internet
Some networks never touch the internet, by policy and by design — a classified enclave, an isolated control system, a bank's segmented production zone, a secure facility where a security officer inspects every byte that
Some networks never touch the internet, by policy and by design — a classified enclave, an isolated control system, a bank's segmented production zone, a secure facility where a security officer inspects every byte that crosses on a USB stick. If you license software into those environments, "our licensing phones home" is a non-starter. The reassuring news is that self-hosted Keyright was built for exactly this: nothing on its runtime path needs the internet. This post is the concrete how-to — what air-gapped means for each moving part, how to install and renew the self-license as a file, how to stop the one thing that would reach out, and how metered licensing works across the gap.
Key takeaway: Self-hosted Keyright needs no outbound internet at runtime. It verifies its own self-license offline against Delta1's embedded public key (no phone-home, fails closed on tamper), your customers' apps validate offline between activations, and for metered licensing you move signed air-gapped credit blocks in and out by file. The core offline run works on Standard and Pro; air-gapped credit blocks are an Enterprise feature.
What "air-gapped" means for the three parties
There are three parts to reason about, and each is independently offline.
The Keyright instance. It is the ghcr.io/delta1-labs/keyright image — one stateless ASP.NET Core service on port 8080, with no database inside it. At startup and on every scan it checks its own license, and that check is pure local cryptography against a public key baked into the build. There is no call to a Delta1 license server, no activation handshake, no telemetry that gates the runtime. Once the image and the key are inside your network, the instance never needs to reach back out.
Your PostgreSQL. All state — licenses, activations, seats, credit balances and their ledger, the audit log, your signing keys encrypted at rest — lives in a database you run, pointed at with the KEYRIGHT_DB connection string. That is an in-network Postgres on your own infrastructure. No managed data store of ours is involved; the data never leaves your perimeter.
Your customers' apps. As covered in offline license validation explained, a signed license verifies locally against the public key you embed at build time, and an online activation hands back a short-lived signed lease the app caches and re-verifies offline. So your customers validate offline between activations — and in a fully disconnected fleet you issue signed offline files and skip the activation round trip entirely, exactly as laid out in licensing for air-gapped environments.
Put together: the instance self-licenses offline, it talks only to a database you host, and your customers' apps don't need to reach it to keep running. Nothing on that path crosses the air gap.
The instance licenses itself offline, and fails closed
Keyright licenses itself with an ordinary Keyright offline license, and your instance verifies it offline against Delta1's embedded public key — no phone-home. That same asymmetry that protects your customers protects your deployment: the public key can verify the signed self-license but can never forge one, so the check is local math, and tampering with any field breaks the signature.
It is fail-closed. With no key, an invalid key, an expired trial, or a paid license past its grace window, the instance is gated: every customer request returns 402. A handful of endpoints stay reachable so you can always diagnose the stop without the internet — /health, /health/ready, /admin/self-license, /admin/self-diagnostics, /branding, and the dashboard — but the runtime is off until a valid key is in place. In an air-gapped network that means the one thing you must get right is the key, so treat it with the same care you give the backup and recovery story for your database.
Installing and renewing the self-license as a file
Here is the part that trips people who expect a web upload: there is no "upload license" endpoint. You provide the key through configuration and (re)start. That is a feature in an air-gapped network — the key arrives the same way everything else does, as a file on your approved transfer channel.
Two ways to supply it:
-
As a file (the air-gapped default): set
KEYRIGHT_SELF_LICENSE_FILEto a path inside the container and mount the license JSON there. On Kubernetes that is a Secret via--set-file secrets.selfLicense=license.json. -
Inline: set
KEYRIGHT_SELF_LICENSEto the license JSON on one line (compact it if your copy has line breaks) — simplest for a single Compose host.
A renewal or an edition change is the same move: swap the file and restart. No redeploy, no migration, no endpoint to call. Then confirm it took:
curl -H "X-Admin-Token: $KEYRIGHT_ADMIN_TOKEN" http://localhost:8080/admin/self-license
/admin/self-license reports your edition, isTrial, phase (active / expiring / grace / gated), daysUntilExpiry and whether the runtime is blocked — and it is one of the few endpoints that answers even when the instance is gated. Wire its expiry countdown into your own monitoring, because in a disconnected network no renewal email is going to find you; the instance warns in the dashboard, but you should watch the phase yourself. The full key-state lifecycle is in the licensing reference.
Disable the one outbound call: GeoIP
The dashboard has an optional machine-location lookup that resolves activation IPs to a rough location. That is the single thing in a stock configuration that would attempt an outbound request. Turn it off for an air-gapped run by setting it empty:
KEYRIGHT_GEOIP_URL=
With that unset the dashboard simply omits the location column and attempts nothing outbound. Everything else — activation, validation, seats, credits, the portal — was already local.
Pulling the image into your private registry
The image lives on a public registry you cannot reach from inside the gap, so move it in the way you move any artifact: pull it on a connected host, export it, and load it on the other side.
# On a connected host:
docker save ghcr.io/delta1-labs/keyright:2.2.2 -o keyright-2.2.2.tar
# (also save postgres:16 if you use the bundled DB for a small install)
# Carry the tarball across your approved channel, then inside the network:
docker load -i keyright-2.2.2.tar
Retag and push into your own in-network registry if you run one, and pin the version (image.tag=2.2.2 on Helm) so deploys are reproducible. Point KEYRIGHT_DB at your in-network PostgreSQL — a database on your own infrastructure, TLS required — and the instance creates and migrates its schema on first start with no SQL to run by hand. Upgrades are the same import-and-restart, with migrations applying automatically on startup.
Metered licensing across the gap: air-gapped credit blocks
If you sell by credits or usage, connectivity is usually how you reconcile spend — and that is exactly what an air-gapped network cannot provide. Air-gapped credit blocks solve it with the same signature trust as a license. You issue a signed block of credit for a disconnected machine, it is redeemed offline there, and you reconcile the usage when the block comes back across the gap. Because each block is signed by your instance's key and verified locally, no step needs the network — credit licensing works entirely by moving files in and out.
Air-gapped credit blocks are an Enterprise feature. The rest of this post — self-license verification, offline customer validation, running with zero egress — works on Standard and Pro just as well; only the credit-block capability is gated to Enterprise.
Which edition, and where this fits
Self-hosted Keyright is priced per deployment across Standard, Pro and Enterprise. The fully offline run described here is not an edition feature — it is how the product works on every tier. Standard covers a single production node; Pro and Enterprise cover up to three (useful if your isolated network also wants high availability); and Enterprise adds SSO, white-label branding, and the air-gapped credit blocks above. See the pricing for the current numbers.
Because Keyright is one product in both deployment modes, nothing about your integration changes between a laptop evaluation and a sealed production enclave. When you are ready to stand one up behind the gap, the operations guide has the air-gapped checklist, the image-move commands, and the backup discipline that turns a running instance into one you can rely on with no way to phone out.
Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.