Quick start
Start Keygate with Docker Compose, issue your first license key and activate it from the command line. It takes about five minutes.
This page gets Keygate running on your own machine and walks one license key through its life: issued, activated, verified and freed again. Nothing here needs Stripe or an email server. You can add both later.
What you need
- Docker with Compose 2.24 or later.
curlandopenssl, which most systems already have.
Start the server
Make a folder and download the compose file and the example settings into it:
mkdir keygate && cd keygate
curl -O https://raw.githubusercontent.com/tabloy/keygate/main/docker-compose.yml
curl -o .env https://raw.githubusercontent.com/tabloy/keygate/main/.env.exampleKeygate refuses to start without two secrets. Generate a random value for each and paste them into .env as JWT_SECRET and LICENSE_SIGNING_KEY:
openssl rand -hex 32
openssl rand -hex 32Then start it:
docker compose up -dCompose starts PostgreSQL and Keygate together and Keygate creates its tables on first start. When the health check answers, it is ready:
curl http://localhost:9000/health
{"checks":{"database":"ok"},"status":"ok","version":"x.y.z"}Set up your account
Open http://localhost:9000. A fresh install shows a setup page that asks for your name and email, a name for the site and your first product. Use your own email address, and keep the product type on Desktop for this page, because the activation calls below need a product with devices. Keygate creates your owner account, the product and a subscription plan called Pro, then takes you to the login page.
Keygate has no passwords. Enter the same email and Keygate sends a one time code. Since no email server is set up yet, the code goes to the server log instead:
docker compose logs keygate | grep "OTP code"The log line carries the code in its code field. Enter it and you are in the admin dashboard.
curl -X POST http://localhost:9000/api/v1/setup/initialize \
-H "Content-Type: application/json" \
-d '{"admin_email":"[email protected]","admin_name":"Your Name",
"site_name":"My Licenses","product_name":"My App",
"product_slug":"my-app","product_type":"desktop"}'Issue a license
Go to Licenses and choose Issue License. Pick the product and the Pro plan from setup, enter any email address and save. Keygate shows the new key:
KG-ABCD2345-EFGH6789-JKLM2345-NPQR6789In a real setup this step happens on its own when a customer pays. The Stripe guide shows how.
Activate it
Your app would make the next calls. Here they are with curl, so you can see exactly what goes over the wire. The identifier names the device; any stable string works for now.
curl -X POST http://localhost:9000/api/v1/license/activate \
-H "Content-Type: application/json" \
-d '{"license_key":"KG-ABCD2345-EFGH6789-JKLM2345-NPQR6789",
"identifier":"my-laptop","label":"My laptop"}'The answer says the device is activated and includes a signed token. Your app keeps that token so it can check the license later without asking the server every time.
{
"success": true,
"data": {
"status": "activated",
"license_id": "4f0c6c1e-2a7b-4d4e-9a55-0d3b7e1f2c11",
"token": "eyJsaWQiOiI0ZjBj...J9.5jW2kC0..."
}
}When the app starts it verifies the license. This also returns the plan, its features and a fresh token:
curl -X POST http://localhost:9000/api/v1/license/verify \
-H "Content-Type: application/json" \
-d '{"license_key":"KG-ABCD2345-EFGH6789-JKLM2345-NPQR6789","identifier":"my-laptop"}'And when the user moves to a new computer, the old one gives its seat back:
curl -X POST http://localhost:9000/api/v1/license/deactivate \
-H "Content-Type: application/json" \
-d '{"license_key":"KG-ABCD2345-EFGH6789-JKLM2345-NPQR6789","identifier":"my-laptop"}'Next steps
- Install Keygate on a server with a real domain and HTTPS.
- Choose your licensing model and set up your plans.
- Add the license check to your app, including offline use.
- Connect Stripe so licenses are created when people pay.
Last updated October 4, 2026