Self Hosting
Keygen is designed to be self-hosted through Docker. You don't have to be a Docker expert to launch your own instance of Keygen, but you should have a basic understanding of the command line and networking to successfully set up your own instance of Keygen.
Don't want to manage infrastructure? The easiest way to get started with Keygen is with our managed offering, Keygen Cloud. High availability, backups, security, and maintenance are all handled for you by our team. The section below is for self-hosting our licensing and distribution API on your own servers and managing your own infrastructure.
The source code for Keygen can be found on our GitHub.
Editions
There are two editions of Keygen. One tailored to hobbyists and DIYers, and one for businesses.
Community Edition
Keygen CE is the Community Edition of Keygen. Keygen CE is free (as in beer). This is the default edition, but can be explicitly configured with the following environment variable:
KEYGEN_EDITION="CE"
We offer best-effort support for Keygen CE users. If your business runs Keygen and needs dedicated support, consider purchasing Keygen EE or becoming a Keygen Cloud customer.
There is a community-supported Discord server and forum where you can ask for help.
Enterprise Edition
Keygen EE is the Enterprise Edition of Keygen. Keygen EE requires a valid license key to run. To purchase a license key, reach out for a 30-day no-strings-attached trial.
Keygen EE can be configured with the following environment variables:
KEYGEN_LICENSE_FILE_PATH="/etc/keygen/ee.lic"KEYGEN_LICENSE_KEY="C1B6DE-39A6E3-DE1529-8559A0-4AF593-V3"KEYGEN_EDITION="EE"
Keygen EE enables the following features:
- Request logs: keep a historical record of API requests, along with who made the request, the request body, response body, status code, IP address, and other information.
- Event logs: keep an audit trail of every single event that happens on a Keygen account.
- Environments: manage separate environments within a Keygen account, from test environments, to a sandbox, to QA, to production.
- Permissions: enterprise-grade roles and permissions.
- SSO/SAML: support for SSO/SAML coming soon.
In addition, Keygen EE customers are entitled to dedicated support.
Contact sales for a 30-day no-strings-attached trial of Keygen EE.
Modes
There are also two modes of Keygen.
Singleplayer mode
The single-tenant mode of Keygen. This is the default mode, but can be explicitly configured with the following environment variable:
KEYGEN_MODE="singleplayer"
In singleplayer mode, the account URL prefix can be ommitted. For example,
/v1/accounts/<account>/licenses
would become /v1/licenses
. This is because
in singleplayer mode, there is only 1 account, making the prefix superfluous.
Multiplayer mode
The multi-tenant mode of Keygen. This mode requires a Keygen EE license with the multiplayer entitlement. Currently, Keygen Cloud is the only multiplayer instance of Keygen.
KEYGEN_MODE="multiplayer"
If you're interested in multiplayer mode, please reach out.
Versioning
Keygen follows semantic versioning. You can find all available Keygen versions on Docker Hub.
The default latest
tag refers to the latest stable release tag.
You can also pin your version:
keygen/api:v1
pins the major version to 1 but allows minor and patch version upgrades.keygen/api:v1.3
pins the minor version to 1.3 but allows only patch upgrades.
The self-hosted versions of Keygen are somewhat of a Long-Term Support (LTS) release, getting a new release twice a year after being battle tested in Keygen Cloud. If you want features as soon as they're available, consider becoming a Keygen Cloud customer, or alteratively, build the Docker image from source (but understand the risks associated with running edge software).
After reviewing what other maintainers of popular open-source projects do, it seems like a bi-yearly schedule works well for everyone vs. more frequent updates:
- Self-hosters can upgrade their setup less frequently, which saves them time spent on maintenance and reduces their workload.
- We can cut new self-hosted releases less frequently and are able to put more effort into creating a better release DX.
No functionality or bug fixes will be backported to older versions. If you wish to get the latest bug fixes and security updates, you can upgrade to the latest version.
The Docker image and Keygen's API itself are versioned separately. For information on our API's versioning policy, please see Versioning.
You can subscribe to version updates via our RSS feed:
https://github.com/keygen-sh/keygen-api/tags.atom
Use your favorite RSS reader.
Requirements
The only thing you need to install Keygen is a server with Docker installed. The server must have a CPU with the x86_64 architecture, and support for SSE 4.2 instructions. We recommend using a minimum of 500MB of RAM, but exact requirements will depend on configuration.
If your server does not have Docker installed, you can follow their instructions.
Keygen requires Ruby >= 3.1, Postgres >= 13, and Redis >= 6.2.
Installation
Installing Keygen can be done in a few ways, depending on if you're just checking out Keygen CE or if you're looking to self-host Keygen EE for production use.
Clone the repository
The easiest way to get started with Keygen is to clone the GitHub repository:
git clone https://github.com/keygen-sh/keygen-api
After cloning, you can can build the Docker image:
docker build -t keygen/api .
Docker Hub
For most production deployments, you will pull via Docker Hub.
docker pull keygen/api
Tarball
Alternatively, you can download and extract a tarball from GitHub:
curl -L https://github.com/keygen-sh/keygen-api/archive/master.tar.gz | tar -xz
After downloading, you can build the Docker image.
Configuration
Keygen is a twelve-factor app, therefore configuring Keygen can be accomplished using environment variables. Keygen can be configured with the following variables:
Required | Default | Description | |
---|---|---|---|
KEYGEN_EDITION |
No | CE |
The edition of Keygen to run: either CE for the Community Edition, or EE for the Enterprise Edition. |
KEYGEN_MODE |
No | singleplayer |
The mode of Keygen: either singleplayer for single-tenant, or multiplayer for multi-tenant.Multiplayer mode requires a Keygen EE license with the multiplayer entitlement. |
KEYGEN_ACCOUNT_ID |
Yes* | The account ID used for setting the tenant of Keygen in singleplayer mode. Use bundle exec rails keygen:setup to generate one.* Required in singleplayer mode. |
|
KEYGEN_HOST |
Yes | The primary host that Keygen's API will be accessible at, e.g. licensing.example.com . |
|
KEYGEN_HOSTS |
No | Additional hosts that Keygen will be accessible at. | |
KEYGEN_LICENSE_FILE_PATH |
No* | The path to a Keygen EE license file, e.g. /etc/keygen/ee.lic .* Either KEYGEN_LICENSE_FILE_PATH or KEYGEN_LICENSE_FILE are required in Keygen EE. |
|
KEYGEN_LICENSE_FILE |
No* | A base64 encoded Keygen EE license file. This is useful when a file system is not available for KEYGEN_LICENSE_FILE_PATH , e.g. with Heroku.* Either KEYGEN_LICENSE_FILE_PATH or KEYGEN_LICENSE_FILE are required in Keygen EE. |
|
KEYGEN_LICENSE_KEY |
No* | The license key used to decrypt the Keygen EE license file. * Required in Keygen EE. |
|
KEYGEN_DOMAIN |
No | The primary domain Keygen's API will be accessible at. By default, this is parsed from KEYGEN_HOST , but that may result in inaccuracies under certain TLDs, e.g. co.uk . |
|
KEYGEN_SUBDOMAIN |
No | The primary subdomain Keygen's API will be accessible at. By default, parsed from KEYGEN_HOST , but that may result in inaccuracies under multiple subdomains. |
|
KEYGEN_PRUNE_EVENT_BACKLOG_DAYS |
No | 90 |
The number of days that high-volume event logs are kept before being pruned. Set to -1 to disable pruning. |
KEYGEN_PRUNE_REQUEST_BACKLOG_DAYS |
No | 30 |
The number of days that request logs are kept before being pruned. Set to -1 to disable pruning. |
KEYGEN_PRUNE_BATCH_SIZE |
No | 10000 |
The number of rows pruned per-batch during pruning. |
KEYGEN_PRUNE_BATCH_WAIT |
No | 1 |
The amount of time, in seconds, to wait in between batches during pruning. |
PORT |
No | 3000 |
The port on which the server is available. |
BIND |
No | 0.0.0.0 |
The IP address on which the server is listening. E.g. 0.0.0.0 = all interfaces, 127.0.0.1 = localhost. |
DATABASE_URL |
Yes | The Postgres database URL, e.g. postgres://postgres:postgres@localhost:5432 . |
|
DB_POOL |
No | $RAILS_MAX_THREADS |
The number of database connections Keygen will use per-worker. |
DB_TIMEOUT |
No | 5000 |
The database query timeout, in ms. |
REDIS_URL |
Yes | The Redis database URL, e.g. redis://localhost:6379 . |
|
REDIS_PROVIDER |
No | REDIS_URL |
The name of the environment variable pointing to Sidekiq's Redis. Set if you want to use an isolated Redis database for background jobs. This should be the name of an environment variable, not a Redis URL. |
REDIS_POOL_SIZE |
No | 5 |
The number of Redis connections Keygen will use per-worker. |
REDIS_POOL_TIMEOUT |
No | 5 |
The Redis pool timeout, in seconds. |
REDIS_CONNECT_TIMEOUT |
No | 5 |
The Redis connect timeout, in seconds. |
REDIS_READ_TIMEOUT |
No | 5 |
The Redis read timeout, in seconds. |
REDIS_WRITE_TIMEOUT |
No | 5 |
The Redis write timeout, in seconds. |
REDIS_RECONNECT_ATTEMPTS |
No | 5 |
The number of reconnect attempts for failed connections to Redis. |
SECRET_KEY_BASE |
Yes | An internal secret key used by Ruby on Rails. Use rails secret or openssl rand -hex 64 to generate one.We recommend a random 64-byte secret. |
|
ENCRYPTION_DETERMINISTIC_KEY |
Yes | The deterministic key used for at-work encryption. Use rails db:encryption:init or openssl rand -base64 32 to generate one.We recommend a random 32-byte secret. No less than 12-bytes. |
|
ENCRYPTION_PRIMARY_KEY |
Yes | The primary key used for at-work encryption. Use rails db:encryption:init or openssl rand -base64 32 to generate one.We recommend a random 32-byte secret. No less than 12-bytes. |
|
ENCRYPTION_KEY_DERIVATION_SALT |
Yes | The key derivation salt used for at-work encryption. Use rails db:encryption:init or openssl rand -base64 32 to generate one.We recommend a random 32-byte secret. No less than 20-bytes. |
|
CF_ACCESS_KEY_ID |
No* | The Cloudflare R2 access key ID. * Without Cloudflare R2 or AWS S3, uploading and downloading release artifacts will fail. |
|
CF_SECRET_ACCESS_KEY |
No* | The Cloudflare R2 secret access key. * Without Cloudflare R2 or AWS S3, uploading and downloading release artifacts will fail. |
|
CF_ACCOUNT_ID |
No* | The Cloudflare R2 account ID. * Without Cloudflare R2 or AWS S3, uploading and downloading release artifacts will fail. |
|
CF_BUCKET |
No* | The Cloudflare R2 bucket to upload artifacts to. * Without Cloudflare R2 or AWS S3, uploading and downloading release artifacts will fail. |
|
CF_REGION |
No* | The Cloudflare R2 region. * Without Cloudflare R2 or AWS S3, uploading and downloading release artifacts will fail. |
|
AWS_ACCESS_KEY_ID |
No* | The AWS S3 access key ID. * Without Cloudflare R2 or AWS S3, uploading and downloading release artifacts will fail. |
|
AWS_SECRET_ACCESS_KEY |
No* | The AWS S3 secret access key. * Without Cloudflare R2 or AWS S3, uploading and downloading release artifacts will fail. |
|
AWS_BUCKET |
No* | The AWS S3 bucket to upload artifacts to. * Without Cloudflare R2 or AWS S3, uploading and downloading release artifacts will fail. |
|
AWS_REGION |
No* | The AWS S3 region. * Without Cloudflare R2 or AWS S3, uploading and downloading release artifacts will fail. |
|
RAILS_ENV |
No | production |
The environment for Ruby on Rails. |
RAILS_LOG_LEVEL |
No | info |
The log level for Ruby on Rails. |
RAILS_LOG_TO_STDOUT |
No | 1 |
Set this environment variable to send all application logs to stdout. |
RAILS_KEEP_ALIVE_TIMEOUT |
No | 20 |
The timeout for idle connections to Puma, in seconds. |
RAILS_MAX_THREADS |
No | 5 |
The maximum number of threads per Puma worker. |
RAILS_MIN_THREADS |
No | $RAILS_MAX_THREADS |
The minimum number of threads per Puma worker. |
RAILS_SERVE_STATIC_FILES |
No | Set this environment varialbe to serve assets from the public/ directory. |
|
WEB_CONCURRENCY |
No | 2 |
The number of Puma workers. |
SIDEKIQ_WEB_USER |
No | The username for accessing the Sidekiq monitoring UI. | |
SIDEKIQ_WEB_PASSWORD |
No | The password for accessing the Sidekiq monitoring UI. | |
RACK_TIMEOUT_SERVICE_TIMEOUT |
No | 15 |
Documentation for rack-timeout can be found here. |
RACK_TIMEOUT_WAIT_TIMEOUT |
No | 30 |
Documentation for rack-timeout can be found here. |
RACK_TIMEOUT_WAIT_OVERTIME |
No | 60 |
Documentation for rack-timeout can be found here. |
RACK_TIMEOUT_SERVICE_PAST_WAIT |
No | 0 |
Documentation for rack-timeout can be found here. |
RACK_TIMEOUT_TERM_ON_TIMEOUT |
No | 0 |
Documentation for rack-timeout can be found here. |
RAILS_AUTOSCALE_URL |
No | The URL for Judoscale (Rails Autoscale), an autoscaler for Heroku. | |
NO_RAILS_AUTOSCALE |
No | Set this environment variable to disable Rails Autoscale. | |
CRONITOR_API_KEY |
No | The API key for Cronitor, a background job monitor. | |
NO_CRONITOR |
No | Set this environment variable to disable Cronitor. | |
SENDGRID_API_KEY |
No | The API key for SendGrid, for sending transactional email. | |
NO_SENDGRID |
No | Set this environment variable to disable SendGrid. | |
TRUSTED_PROXIES |
No | A comma-delimited list of trusted proxy IP addresses. |
Configure Postgres
Keygen's main application database is Postgres. The minimum supported version is Postgres 13. Storage and connection requirements will vary depending on volume.
You can set the Postgres database using the following environment variable:
DATABASE_URL="postgres://postgres:postgres@localhost:5432"
To start a non-production Postgres container, run:
docker run --name postgres -d -p 5432:5432 \ -v postgres:/var/lib/postgresql/data \ -e POSTGRES_PASSWORD=postgres \ postgres
Ensure Postgres is running before proceeding.
Configure Redis
Keygen's cache and background job database is Redis. The minimum supported version is Redis 6.2. Storage and connection requirements will vary.
volatile-lru
for most databases, but we recommend using noeviction
for the
Redis database used for background jobs, to prevent catastrophic job loss in
case the Redis maxmemory
value is reached.
You can set the Redis database using the following environment variable:
REDIS_URL="redis://localhost:6379"
To start a non-production Redis container, run:
docker run --name redis -d -p 6379:6379 \ -v redis:/var/lib/redis/data \ redis
Ensure Redis is running before proceeding.
Configure Keygen
The easiest way to get Keygen set up is to use the setup
command. It will walk you
through the necessary steps to set up your Keygen instance and environment.
docker run --rm -it -e SECRET_KEY_BASE="$(openssl rand -hex 64)" \ -e ENCRYPTION_DETERMINISTIC_KEY="$(openssl rand -base64 32)" \ -e ENCRYPTION_PRIMARY_KEY="$(openssl rand -base64 32)" \ -e ENCRYPTION_KEY_DERIVATION_SALT="$(openssl rand -base64 32)" \ -e REDIS_URL="redis://host.docker.internal:6379" \ -e KEYGEN_HOST="api.keygen.localhost" \ -e KEYGEN_MODE="singleplayer" \ -e KEYGEN_EDITION="EE" \ keygen/api setup
Please note that Postgres and Redis must be setup and running beforehand.
After running the setup task, set the resulting environment variables.
Running
Keygen has two processes types, server and worker.
Starting the server
Keygen uses Puma as its web server to serve the API. By default,
the server listens for HTTP(S) requests on port 3000
. The server only supports
HTTP 1.1, it does NOT support HTTP 2.
To start the server, run the following command:
docker run --name web.1 -p 127.0.0.1:3000:3000 -e SECRET_KEY_BASE="${SECRET_KEY_BASE}" \ -e ENCRYPTION_DETERMINISTIC_KEY="${ENCRYPTION_DETERMINISTIC_KEY}" \ -e ENCRYPTION_PRIMARY_KEY="${ENCRYPTION_PRIMARY_KEY}" \ -e ENCRYPTION_KEY_DERIVATION_SALT="${ENCRYPTION_KEY_DERIVATION_SALT}" \ -e REDIS_URL="redis://host.docker.internal:6379" \ -e KEYGEN_LICENSE_FILE_PATH="${KEYGEN_LICENSE_FILE_PATH}" \ -e KEYGEN_LICENSE_KEY="${KEYGEN_LICENSE_KEY}" \ -e KEYGEN_ACCOUNT_ID="${KEYGEN_ACCOUNT_ID}" \ -e KEYGEN_EDITION="${KEYGEN_EDITION}" \ -e KEYGEN_MODE="${KEYGEN_MODE}" \ -e KEYGEN_HOST="${KEYGEN_HOST}" \ -v /etc/keygen:/etc/keygen \ keygen/api web
host.docker.internal
hostnames used
for the non-production Postgres and Redis URLs. You may need to add the
--add-host host.docker.internal:host-gateway
flag.
To access Keygen on localhost over TLS, you can use a reverse proxy such as Caddy:
echo '127.0.0.1 api.keygen.localhost' | sudo tee -a /etc/hostscaddy reverse-proxy --from api.keygen.localhost --to :3000
Keygen should now be available at:
curl -I https://api.keygen.localhost/v1/ping# HTTP/2 200# ...
If you're unable to ping the server, check the logs.
For health checks, use the /v1/health
endpoint.
Starting a worker
Keygen uses Sidekiq to process background jobs, including jobs for license expirations, webhooks, machine heartbeats, and more.
To start Sidekiq, run the following command:
docker run --name worker.1 -e SECRET_KEY_BASE="${SECRET_KEY_BASE}" \ -e ENCRYPTION_DETERMINISTIC_KEY="${ENCRYPTION_DETERMINISTIC_KEY}" \ -e ENCRYPTION_PRIMARY_KEY="${ENCRYPTION_PRIMARY_KEY}" \ -e ENCRYPTION_KEY_DERIVATION_SALT="${ENCRYPTION_KEY_DERIVATION_SALT}" \ -e REDIS_URL="redis://host.docker.internal:6379" \ -e KEYGEN_LICENSE_FILE_PATH="${KEYGEN_LICENSE_FILE_PATH}" \ -e KEYGEN_LICENSE_KEY="${KEYGEN_LICENSE_KEY}" \ -e KEYGEN_ACCOUNT_ID="${KEYGEN_ACCOUNT_ID}" \ -e KEYGEN_EDITION="${KEYGEN_EDITION}" \ -e KEYGEN_MODE="${KEYGEN_MODE}" \ -e KEYGEN_HOST="${KEYGEN_HOST}" \ -v /etc/keygen:/etc/keygen \ keygen/api worker
Sidekiq should now be running.
Managing
Keygen can be managed directly via the API (see API reference), or via the console.
Looking for the UI? We don't have a self-hosted one yet. But we're working on open-sourcing a brand new Portal app soon. For now, use the API or console, or create a front-end portal app yourself backed by the Keygen API.
Opening a console
Keygen is a Ruby on Rails app, and as such, supports the rails console
command.
This allows you to programatically manage your data. You can, for example, set up
a product and generate an API token, or create a license for a new customer.
To open a console, run the following command:
docker run --rm -it -e SECRET_KEY_BASE="${SECRET_KEY_BASE}" \ -e ENCRYPTION_DETERMINISTIC_KEY="${ENCRYPTION_DETERMINISTIC_KEY}" \ -e ENCRYPTION_PRIMARY_KEY="${ENCRYPTION_PRIMARY_KEY}" \ -e ENCRYPTION_KEY_DERIVATION_SALT="${ENCRYPTION_KEY_DERIVATION_SALT}" \ -e REDIS_URL="redis://host.docker.internal:6379" \ -e KEYGEN_LICENSE_FILE_PATH="${KEYGEN_LICENSE_FILE_PATH}" \ -e KEYGEN_LICENSE_KEY="${KEYGEN_LICENSE_KEY}" \ -e KEYGEN_ACCOUNT_ID="${KEYGEN_ACCOUNT_ID}" \ -e KEYGEN_EDITION="${KEYGEN_EDITION}" \ -e KEYGEN_MODE="${KEYGEN_MODE}" \ -e KEYGEN_HOST="${KEYGEN_HOST}" \ -v /etc/keygen:/etc/keygen \ keygen/api console
The console prompt should now be available.
Upgrading
Keygen is updated regularly, but it's up to you to apply these updates on your server.
Using Docker, upgrades are safe and easy to apply.
docker pull keygen/api:latest
New versions of Keygen CE and Keygen EE are released roughly every 6 months.
Migrations
Some upgrades to Keygen may require database schema changes. Database migrations can be
run inside of the container using the following rails
command:
rails db:migrate
As part of your deployment process, we typically recommend running a single release
container
before rolling out an upgrade, which will run the above command.
To run the release command, run the following:
docker run --rm -e SECRET_KEY_BASE="${SECRET_KEY_BASE}" \ -e ENCRYPTION_DETERMINISTIC_KEY="${ENCRYPTION_DETERMINISTIC_KEY}" \ -e ENCRYPTION_PRIMARY_KEY="${ENCRYPTION_PRIMARY_KEY}" \ -e ENCRYPTION_KEY_DERIVATION_SALT="${ENCRYPTION_KEY_DERIVATION_SALT}" \ -e REDIS_URL="redis://host.docker.internal:6379" \ -e KEYGEN_LICENSE_FILE_PATH="${KEYGEN_LICENSE_FILE_PATH}" \ -e KEYGEN_LICENSE_KEY="${KEYGEN_LICENSE_KEY}" \ -e KEYGEN_ACCOUNT_ID="${KEYGEN_ACCOUNT_ID}" \ -e KEYGEN_EDITION="${KEYGEN_EDITION}" \ -e KEYGEN_MODE="${KEYGEN_MODE}" \ -e KEYGEN_HOST="${KEYGEN_HOST}" \ -v /etc/keygen:/etc/keygen \ keygen/api release
It is advised to run the above release command BEFORE shutting down old instances and routing to new instances (i.e. rolling over a release). Database migrations are typically backwards compatibile, so running the release command WILL NOT break existing instances running an older version of Keygen, unless otherwise noted in the release notes.
Some upgrades may require other migrations to be run. For example, some upgrades may require a data migration (e.g. seeding new permissions or event types). These migrations will be detailed in the documentation for the new version.
If you ever get tired of managing maintenance and upgrades for your own instances of Keygen, we'd love to have you over at Keygen Cloud. By using Keygen Cloud, you not only support the further development of Keygen, but you also get a great value. We'll handle high availability, backups, security, and maintenance for you.
Monitoring
Server
For server health checks, you can use the following endpoint:
GET https://api.keygen.localhost/v1/health
Using Docker, you can use the --health-cmd
flag to monitor the container:
docker run --name web.1 -p 127.0.0.1:3000:3000 \+ --health-cmd "wget --no-verbose --tries=1 --spider http://localhost:3000/v1/health || exit 1" \ # + --health-interval 5m \ # + --health-timeout 60s \ # keygen/api console
This health endpoint supports both HTTP and HTTPS.
Worker
To access the Sidekiq monitoring UI,
set the SIDEKIQ_WEB_USER
and SIDEKIQ_WEB_PASSWORD
environment variables
and visit the following endpoint:
https://api.keygen.localhost/-/sidekiq/
The Sidekiq monitoring UI is currently readonly.
Telemetry
Keygen takes your privacy very seriously, and we do not use any form of telemetry.
How does Keygen license Keygen EE without telemetry?
Keygen uses cryptographically signed and encrypted License Files to securely handle licensing Keygen EE without an internet connection.
tl;dr Keygen uses Keygen to license Keygen EE. It's turtles Keygens all the way down.