llms.txt
Search Documentation
Search through all documentation pages
Setup Guide

Deployment

Deploy Kener with Docker or Node.js and verify service health with the healthcheck endpoint

Use this guide when moving from local testing to production. It includes .env examples for PostgreSQL, MySQL, subpath deployments, and both SMTP/Resend email providers.

Quick start with Docker Compose

For most teams, Docker Compose is the fastest path to production.

  1. Clone the repo.
  2. Create a .env file.
  3. Start services with Docker Compose.

Minimum required values:

  • KENER_SECRET_KEY
  • ORIGIN
  • REDIS_URL

Required and common variables

Variable Required Notes
KENER_SECRET_KEY Yes Use a strong random secret
ORIGIN Yes Public URL, no trailing slash
REDIS_URL Yes redis:// or rediss://
DATABASE_URL No Defaults to SQLite if omitted
PORT No Defaults to 3000
KENER_BASE_PATH No Example: /status

For full variable reference, see Environment Variables.

.env examples

PostgreSQL + external Redis

KENER_SECRET_KEY=replace_with_a_long_random_secret
ORIGIN=https://status.example.com
DATABASE_URL=postgresql://kener:strongpassword@postgres.example.com:5432/kener
REDIS_URL=redis://redis.example.com:6379
PORT=3000

MySQL + external Redis

KENER_SECRET_KEY=replace_with_a_long_random_secret
ORIGIN=https://status.example.com
DATABASE_URL=mysql://kener:strongpassword@mysql.example.com:3306/kener
REDIS_URL=redis://redis.example.com:6379
PORT=3000

Subpath deployment (`/status`) + PostgreSQL

KENER_SECRET_KEY=replace_with_a_long_random_secret
ORIGIN=https://example.com
KENER_BASE_PATH=/status
DATABASE_URL=postgresql://kener:strongpassword@postgres.example.com:5432/kener
REDIS_URL=redis://redis.example.com:6379
PORT=3000

Important

For subpath deployments, ORIGIN remains the domain root (for example https://example.com), and KENER_BASE_PATH carries the subpath (for example /status).

Email examples in .env

Add one of these blocks to any .env example above.

SMTP enabled

SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=mailer-user
SMTP_PASS=mailer-password
SMTP_FROM_EMAIL=status@example.com
SMTP_SECURE=0

Resend enabled

RESEND_API_KEY=re_xxxxxxxxxxxxx
RESEND_SENDER_EMAIL=status@example.com

Note

If SMTP and Resend are both configured, SMTP is used first. See Email Setup.

Using the current Docker Compose with your own DB/Redis

If your team already runs managed PostgreSQL/MySQL/Redis, keep docker-compose.yml and set connection URLs in .env.

Example: current Compose + managed PostgreSQL/Redis

KENER_SECRET_KEY=replace_with_a_long_random_secret
ORIGIN=https://status.example.com
DATABASE_URL=postgresql://kener:strongpassword@pg-managed.example.com:5432/kener
REDIS_URL=rediss://redis-managed.example.com:6380
PORT=3000

Example: current Compose + managed MySQL/Redis

KENER_SECRET_KEY=replace_with_a_long_random_secret
ORIGIN=https://status.example.com
DATABASE_URL=mysql://kener:strongpassword@mysql-managed.example.com:3306/kener
REDIS_URL=redis://redis-managed.example.com:6379
PORT=3000

Docker Compose override examples (self-host DB/Redis)

If you want PostgreSQL/MySQL/Redis containers in the same Docker Compose stack, add an override file and keep app variables in .env.

Option A: `docker-compose.pg.yml`

services:
    postgres:
        image: postgres:16
        environment:
            POSTGRES_DB: kener
            POSTGRES_USER: kener
            POSTGRES_PASSWORD: kener_password
        volumes:
            - pg_data:/var/lib/postgresql/data

    redis:
        image: redis:7-alpine
        command: ["redis-server", "--appendonly", "yes"]
        volumes:
            - redis_data:/data

volumes:
    pg_data:
    redis_data:

Use with this .env:

KENER_SECRET_KEY=replace_with_a_long_random_secret
ORIGIN=https://status.example.com
DATABASE_URL=postgresql://kener:kener_password@postgres:5432/kener
REDIS_URL=redis://redis:6379
PORT=3000

Option B: `docker-compose.mysql.yml`

services:
    mysql:
        image: mysql:8
        environment:
            MYSQL_DATABASE: kener
            MYSQL_USER: kener
            MYSQL_PASSWORD: kener_password
            MYSQL_ROOT_PASSWORD: root_password
        command: ["--default-authentication-plugin=mysql_native_password"]
        volumes:
            - mysql_data:/var/lib/mysql

    redis:
        image: redis:7-alpine
        command: ["redis-server", "--appendonly", "yes"]
        volumes:
            - redis_data:/data

volumes:
    mysql_data:
    redis_data:

Use with this .env:

KENER_SECRET_KEY=replace_with_a_long_random_secret
ORIGIN=https://status.example.com
DATABASE_URL=mysql://kener:kener_password@mysql:3306/kener
REDIS_URL=redis://redis:6379
PORT=3000

Tip

Keep secrets in .env and avoid hardcoding credentials in Compose files.

Pre-built image deployment

You can run official images from either registry:

  • Docker Hub: docker.io/rajnandan1/kener:latest
  • GHCR: ghcr.io/rajnandan1/kener:latest

Example using .env:

mkdir -p database

# .env should contain at least KENER_SECRET_KEY, ORIGIN, REDIS_URL
docker run -d \
  --name kener \
  -p 3000:3000 \
  -v "$(pwd)/database:/app/database" \
  --env-file .env \
  docker.io/rajnandan1/kener:latest

Node.js deployment (without Docker)

Use this when you prefer managing runtime directly on a VM/server.

Requirements:

  • Node.js >= 20
  • Redis
git clone https://github.com/rajnandan1/kener.git
cd kener
mv .env-min.example .env
npm install
npm run build
npm run start

Minimum .env:

KENER_SECRET_KEY=replace_with_a_random_string
ORIGIN=https://status.example.com
REDIS_URL=redis://localhost:6379
PORT=3000
# Optional (defaults to SQLite):
# DATABASE_URL=sqlite://./database/kener.sqlite.db

Healthcheck URL

Kener exposes a healthcheck endpoint from the server entrypoint.

  • Default path: https://your-domain/healthcheck
  • With base path (KENER_BASE_PATH=/status): https://your-domain/status/healthcheck

Quick verification:

curl -fsS https://your-domain/healthcheck

Expected response body:

ok

Next steps