Environment Variables
Complete reference for every .env variable supported by KissKH Video Player
Overview
All configuration is done through environment variables, either in a .env file at the project root or via your hosting platform's environment variable UI (cPanel, Railway, Render, etc.).
Copy .env.example to .env to get started:
cp .env.example .envBelow is a complete reference for every supported variable.
Server
PORT
| Required | No |
| Default | 3000 |
The TCP port the server listens on.
PORT=3000Do not set PORT on Passenger-based hosting. Passenger manages the port automatically.
KissKH API
KISSKH_BASE_URL
| Required | No |
| Default | https://kisskh.co |
The base URL for the KissKH website and API. Only change this if KissKH moves to a new domain and you need to point the server at it.
KISSKH_BASE_URL=https://kisskh.coKISSKH_CACHE_TTL
| Required | No |
| Default | 900 (15 minutes) |
How long, in seconds, to cache episode video URL responses from the KissKH API. Increasing this reduces API calls but means video URL changes take longer to propagate.
KISSKH_CACHE_TTL=900KISSKH_SUB_CACHE_TTL
| Required | No |
| Default | 3600 (1 hour) |
How long, in seconds, to cache subtitle list responses from the KissKH API. Subtitles change less frequently than video URLs, so the default is longer.
KISSKH_SUB_CACHE_TTL=3600KISSKH_HOST_CACHE_TTL
| Required | No |
| Default | 900 (15 minutes) |
How long, in seconds, to cache the result of the internal probe that decides which proxy host to use for a given video URL.
KISSKH_HOST_CACHE_TTL=900Proxy & CDN
PROXY_URL
| Required | No |
| Default | (unset — uses the current server) |
When set, all /vid/ and /sub/ proxy URLs will point to this external server instead of the current one. Use this to offload video bandwidth to a separate Node.js instance running the same server.js code — for example, a second VPS or a cheaper bandwidth region.
PROXY_URL=https://proxy.example.comWhen unset, the current server handles all proxying itself.
Security
URL_SECRET
| Required | No (but strongly recommended in production) |
| Default | (unset) |
A random secret string used to AES-encrypt the proxy URL path segments (/vid/ and /sub/). When set, the encoded URLs are unguessable — a viewer cannot reverse-engineer the original CDN URL from the iframe source.
When unset, the server falls back to plain base64 encoding, which is easily decoded.
Set this to any long random string:
URL_SECRET=change-me-to-a-long-random-stringAlways set URL_SECRET in production. Without it, anyone who inspects the iframe's network requests can decode the CDN URLs and bypass your server entirely.
ALLOWED_ORIGIN
| Required | No |
| Default | (unset — allows the current serving domain only) |
A comma-separated list of origins allowed to make requests to the /vid/ and /sub/ proxy endpoints. By default, the proxy only accepts requests from the same domain the server is running on.
Set this only if your player page and your proxy server are on different domains:
ALLOWED_ORIGIN=https://your-site.com,https://another-site.comIFRAME_ALLOWED_ORIGIN
| Required | No |
| Default | (unset — all domains can embed the player) |
A comma-separated list of origins allowed to embed the /kisskh/{id} player page in an <iframe>. By default, any domain can embed the player.
Set this to restrict which websites can embed your player:
IFRAME_ALLOWED_ORIGIN=https://your-site.com,https://another-site.comWhen IFRAME_ALLOWED_ORIGIN is set, any attempt to embed the player from an unlisted domain will receive a 403 error page instead of the player. Direct browser access (no iframe) is always blocked regardless of this setting.
Admin Panel
ADMIN_PASSWORD
| Required | No (admin panel is disabled until this is set) |
| Default | (unset — admin panel disabled) |
The password for the admin panel at /admin. The admin panel is completely disabled until you set this. Choose a strong password.
ADMIN_PASSWORD=your-secure-passwordADMIN_USERNAME
| Required | No |
| Default | admin |
The username for the admin panel login.
ADMIN_USERNAME=adminADMIN_SECRET
| Required | No |
| Default | Falls back to URL_SECRET, then kisskh-admin |
A secret used to sign admin session cookies. You do not need to set this separately if you have already set URL_SECRET — the server uses URL_SECRET as the session signing key when ADMIN_SECRET is not explicitly provided.
ADMIN_SECRET=another-random-secretCache (Redis)
REDIS_URL
| Required | No |
| Default | (unset — in-memory cache only) |
Connection URL for an optional Redis (or Valkey) instance. When set, the server uses Redis as a shared cache in addition to the local in-memory cache. This is useful for multi-instance deployments where you want cache to be shared across servers.
Supports both plain and TLS connections:
# Plain Redis
REDIS_URL=redis://localhost:6379/0
# Redis with password
REDIS_URL=redis://:mypassword@localhost:6379/0
# Redis with TLS (e.g. Upstash)
REDIS_URL=rediss://user:password@host:6380/0When REDIS_URL is not set, the server runs with in-memory caching only, which is perfectly fine for single-instance deployments.
REDIS_TIMEOUT_MS
| Required | No |
| Default | 500 |
Timeout in milliseconds for Redis commands. If Redis is slow or unreachable, the server falls back to the in-memory cache rather than blocking.
REDIS_TIMEOUT_MS=500CACHE_MAX_ENTRIES
| Required | No |
| Default | 500 |
Maximum number of entries in the in-memory LRU cache. Older entries are evicted when the limit is reached. Increase this on servers with more RAM to reduce KissKH API calls.
CACHE_MAX_ENTRIES=500CACHE_MEMORY_TTL
| Required | No |
| Default | 60 (seconds) |
When Redis is configured, cache entries fetched from Redis are also stored in the local in-memory cache for this many seconds to avoid repeated Redis round-trips.
CACHE_MEMORY_TTL=60Minimal Production .env
Here is a minimal .env suitable for a production single-server deployment:
PORT=3000
ADMIN_PASSWORD=your-secure-password
URL_SECRET=replace-with-a-long-random-string
KISSKH_CACHE_TTL=900
KISSKH_SUB_CACHE_TTL=3600Add IFRAME_ALLOWED_ORIGIN if you want to lock down which sites can embed the player.