Skip to content

On-Premise Configuration

This guide covers required and optional environment variables for on-prem deployments. A full template is available at infra/.env.onprem.example.

Required: Deployment Mode

Variable Description Example
DEPLOYMENT_MODE Must be single-tenant for on-prem deployments single-tenant

Required: Tenant Configuration

Variable Required Default Description
DEFAULT_TENANT_SLUG No default URL-safe identifier (lowercase, no spaces)
DEFAULT_TENANT_NAME No My Organization Display name shown in UI

The tenant is auto-created on first boot if it doesn’t exist.

Required: Admin Credentials

Variable Description Example
ADMIN_EMAIL Initial admin user email admin@company.com
ADMIN_PASSWORD Initial admin password (change after first login!) ChangeMe123!
JWT_SECRET JWT signing key (generate: openssl rand -hex 32) 64 hex chars
APP_BASE_URL Public URL (used in email links) https://kanap.company.com
CORS_ORIGINS Comma-separated allowed browser origins (required in production) https://*.company.com

Email links: Password reset/invite URLs use APP_BASE_URL (or forwarded host/proto). On-prem should set APP_BASE_URL to the externally reachable URL and configure the reverse proxy to pass Host / X-Forwarded-Proto.

CORS: Configure CORS_ORIGINS to control which browser origins can access the API. The application will fail to start in production if CORS_ORIGINS is not set.

Supported patterns: - Exact origin: https://app.company.com - Wildcard subdomain: https://*.company.com (matches any subdomain, e.g., https://tenant1.company.com) - Wildcard port: http://localhost:* (matches any port, useful for local development)

Examples:

# Single-tenant on-prem
CORS_ORIGINS=https://kanap.company.com

# Multi-tenant with subdomains
CORS_ORIGINS=https://*.company.com

# Multiple patterns
CORS_ORIGINS=https://*.company.com,https://admin.company.com

Startup validation: The application will refuse to start if JWT_SECRET, DATABASE_URL, or APP_BASE_URL are missing or empty.

Required: Database

Variable Description Example
DATABASE_URL PostgreSQL connection string postgres://user:pass@host:5432/kanap?sslmode=require

Database requirements: - PostgreSQL 16 or higher (tested minimum; older versions may work but are unsupported) - Extensions: citext, pgcrypto, uuid-ossp - User needs CREATE TABLE / ALTER TABLE permissions for migrations - Recommended: dedicated database

Database setup (example):

-- 1. Create database and user
CREATE DATABASE kanap;
CREATE USER kanap WITH PASSWORD 'secure-password';
GRANT ALL PRIVILEGES ON DATABASE kanap TO kanap;

-- 2. Connect to kanap database and enable extensions
\c kanap
CREATE EXTENSION IF NOT EXISTS citext;
CREATE EXTENSION IF NOT EXISTS pgcrypto;
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

-- 3. Grant schema permissions (for migrations)
GRANT ALL ON SCHEMA public TO kanap;

Required: Storage

Variable Description Example
S3_ENDPOINT S3-compatible endpoint https://s3.amazonaws.com
S3_BUCKET Bucket name (must exist) kanap-files
S3_REGION Region us-east-1
AWS_ACCESS_KEY_ID Access key AKIA...
AWS_SECRET_ACCESS_KEY Secret key secret
S3_FORCE_PATH_STYLE true for MinIO, false for AWS/R2 false

Bucket requirements: - Create the bucket before starting KANAP (not auto-created) - Permissions: s3:PutObject, s3:GetObject, s3:DeleteObject, s3:ListBucket

KANAP uses the AWS SDK v3 S3 client for object storage access; any provider with S3-compatible API behavior is supported.

Tested providers: - AWS S3 (S3_ENDPOINT=https://s3.amazonaws.com, S3_FORCE_PATH_STYLE=false) - MinIO (S3_ENDPOINT=http://minio:9000, S3_FORCE_PATH_STYLE=true) - Cloudflare R2 (https://<account>.r2.cloudflarestorage.com) - Backblaze B2 (https://s3.<region>.backblazeb2.com) - Hetzner (https://<region>.your-objectstorage.com)

Variable Description Example
RESEND_API_KEY Resend API key re_xxxxx
RESEND_FROM_EMAIL From address KANAP <noreply@yourdomain.com>

If not configured, email features are disabled, including user invitations, password reset... See Operations for SQL password reset fallback.

Optional: Email (Phase 2 - SMTP)

In a future release KANAP will include an internal SMTP engine.

Variable Description Example
SMTP_HOST SMTP server hostname smtp.company.com
SMTP_PORT SMTP port 587
SMTP_USER SMTP username kanap
SMTP_PASSWORD SMTP password secret
SMTP_FROM From address KANAP <noreply@company.com>
SMTP_SECURE true for TLS, false for STARTTLS true

Optional: Entra SSO

See the dedicated guide: sso-entra.md.

Optional: Advanced

Variable Description Default
LOG_LEVEL Logging verbosity (debug, info, warn, error) info
JWT_ACCESS_TOKEN_TTL Access token lifetime 15m
JWT_REFRESH_TOKEN_TTL Refresh token lifetime 4h
RATE_LIMIT_ENABLED App-level rate limiting toggle true
RATE_LIMIT_TRUST_PROXY Trust proxy headers for client IP detection false
APP_URL Base URL for notification email links (tenant slug replaces app); also used as fallback origin for comment-email inline image URLs when CID embedding is not possible https://app.kanap.net
EMAIL_OVERRIDE Redirect all emails to this address (dev/QA only, never in production) unset

Full Example (.env)

# =============================================================================
# KANAP On-Premise Configuration
# =============================================================================

# DEPLOYMENT MODE (required)
DEPLOYMENT_MODE=single-tenant

# TENANT CONFIGURATION (optional - defaults shown)
DEFAULT_TENANT_SLUG=default
DEFAULT_TENANT_NAME=My Organization

# ADMIN CREDENTIALS (required)
ADMIN_EMAIL=admin@company.com
ADMIN_PASSWORD=ChangeThisPassword123!

# SECURITY (required)
JWT_SECRET=

# APPLICATION URL (required)
APP_BASE_URL=https://kanap.your-domain.com

# DATABASE (required)
DATABASE_URL=postgres://kanap:password@your-postgres:5432/kanap?sslmode=require

# STORAGE (required)
S3_ENDPOINT=https://s3.amazonaws.com
S3_BUCKET=kanap-files
S3_REGION=us-east-1
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
S3_FORCE_PATH_STYLE=false   # true for MinIO

# EMAIL (optional - Resend)
# RESEND_API_KEY=re_xxxxx
# RESEND_FROM_EMAIL=KANAP <noreply@yourdomain.com>

# EMAIL (optional - SMTP, Phase 2)
# SMTP_HOST=smtp.company.com
# SMTP_PORT=587
# SMTP_USER=
# SMTP_PASSWORD=
# SMTP_FROM=KANAP <noreply@company.com>
# SMTP_SECURE=true

# ADVANCED (optional - defaults are fine)
# LOG_LEVEL=info
# JWT_ACCESS_TOKEN_TTL=15m
# JWT_REFRESH_TOKEN_TTL=4h
# RATE_LIMIT_ENABLED=true
# RATE_LIMIT_TRUST_PROXY=false

External Connections (Firewall)

Service Endpoint Purpose Required
GitHub github.com Clone source code Once (initial setup)
npm registry registry.npmjs.org Download dependencies During build
Resend API api.resend.com Send emails If using Resend
Microsoft Entra login.microsoftonline.com SSO metadata/token If using Entra
Microsoft Graph graph.microsoft.com Profile enrichment Optional
World Bank API api.worldbank.org FX rates (annual) Optional
Exchange Rate API v6.exchangerate-api.com FX rates (spot) Optional

After initial build, KANAP can run without internet access (except for email/SSO or optional FX rates).

Background Jobs

The backend runs scheduled background jobs for email notifications: - Expiration warnings: daily at 08:00 UTC — alerts users about contracts and OPEX items expiring within 30 days. - Weekly review digest: hourly check — sends timezone-aware weekly summaries to users who have opted in.

These jobs require the API to run as a long-running process (not a serverless function). APP_URL must be set for notification email links to resolve correctly.