Deployment
Run kRouter on a server with npm and PM2, in Docker, with Docker Compose and the Presidio sidecar, or from source. Environment variables and HTTPS.
kRouter is a Node.js server with a SQLite database, so anything that keeps a Node 20.9+ process running can host it. It is not built for serverless or edge platforms such as Cloudflare Workers. Pick one of the paths below.
npm and PM2
The simplest setup on a VPS:
npm install -g @sifxprime/krouter pm2
# A first-login password that works remotely; note it down
export INITIAL_PASSWORD="$(openssl rand -base64 18)" && echo "Dashboard password: $INITIAL_PASSWORD"
pm2 start krouter --name krouter -- --skip-update
pm2 save && pm2 startupINITIAL_PASSWORD matters because the default 123456 is accepted only from the machine kRouter runs on. Instead of setting it, you can open the dashboard through an SSH tunnel (ssh -L 20128:localhost:20128 you@server, then http://localhost:20128/dashboard), which counts as local, and set a password under Settings → Security.
Use --port and --host here, not PORT and HOSTNAME: the krouter command ignores those variables. Add --host 127.0.0.1 after --skip-update when a reverse proxy on the same machine should be the only way in. --skip-update lets kRouter run without a terminal; see the CLI reference.
Docker
The image is on Docker Hub (sifxprime/krouter) and GitHub Container Registry (ghcr.io/sifxprime/krouter), built for linux/amd64 and linux/arm64.
KROUTER_PASSWORD="$(openssl rand -base64 18)" && echo "Dashboard password: $KROUTER_PASSWORD"
docker run -d \
--name krouter \
-p 20128:20128 \
-v "$HOME/.krouter:/app/data" \
-e INITIAL_PASSWORD="${KROUTER_PASSWORD:?run the line above first}" \
sifxprime/krouter:latestThe first line prints the dashboard password. The image already sets PORT=20128, HOSTNAME=0.0.0.0 and DATA_DIR=/app/data, and the bind mount keeps the database and OAuth tokens on the host, so restarts and upgrades keep your state. If ~/.krouter already holds a password from an npm install, that password applies instead. MITM mode does not work inside a container.
Forgot the password? With image 0.5.162 or newer: docker exec krouter node scripts/reset-password.js.
Docker Compose with PII redaction
The repository's Compose file runs kRouter next to a Presidio sidecar that can redact personal data from prompts before they reach a provider. It builds from a clone and refuses to start until KROUTER_INITIAL_PASSWORD is set:
git clone https://github.com/sifxprime/krouter.git && cd krouter
echo "KROUTER_INITIAL_PASSWORD='$(openssl rand -base64 18)'" > .env && cat .env
docker compose up -dcat .env shows the dashboard password. Redaction stays off until you turn on both Presidio Sidecar and PII Redaction on the dashboard's Presidio page. It then covers the chat endpoints only, and if the sidecar is down, those requests fail instead of going out unredacted.
From source
git clone https://github.com/sifxprime/krouter.git
cd krouter
npm install
npm run build:deploy
export INITIAL_PASSWORD="$(openssl rand -base64 18)" && echo "Dashboard password: $INITIAL_PASSWORD"
export DATA_DIR="/var/lib/krouter" # must be writable by this user
export HOSTNAME="0.0.0.0"
export AUTH_COOKIE_SECURE="true" # only when you serve it over HTTPS
npm run startnpm run start runs node custom-server.js on port 20128. For another port, run PORT=8080 node custom-server.js instead. To keep it running under PM2: pm2 start npm --name krouter -- start.
Environment variables
| Variable | Default | Purpose |
|---|---|---|
INITIAL_PASSWORD | 123456, accepted only locally | First-login password until you set one under Settings → Security. Needed for Docker, a reverse proxy or any remote first login. Example values from docs are treated like 123456. |
JWT_SECRET | generated, saved at $DATA_DIR/jwt-secret | Signs the dashboard session. Leave it unset unless several instances must share sessions; then use openssl rand -hex 32. Values under 32 characters, or copied from docs, are ignored with a warning. |
DATA_DIR | ~/.krouter (on Windows %APPDATA%\krouter) | Database, MITM certificate and runtime files |
PORT, HOSTNAME | 20128 and 0.0.0.0 in the Docker image | Port and bind address for Docker and source installs. The krouter command ignores them; use --port and --host. |
REQUIRE_API_KEY | false | Remote callers always need an API key. true also requires one from the local machine. |
AUTH_COOKIE_SECURE | false | Force the Secure flag on the session cookie. It is set anyway when the request says it arrived over HTTPS (X-Forwarded-Proto: https). |
HTTP_PROXY, HTTPS_PROXY, ALL_PROXY, NO_PROXY | unset | Outbound proxy for calls to providers |
KROUTER_SKIP_RUNTIME_HEAL | unset | Skip the npm self-repair of the SQLite and tray runtime at start, for air-gapped machines |
API_KEY_SECRET | built-in value | HMAC secret for the checksum part of generated API keys |
ENABLE_REQUEST_LOGS | false | Writes every request and response in full, headers included, to a logs/ folder. Debugging only; see Security. |
The dashboard's Environment page shows which of these are set on a running instance.
Reverse proxy (HTTPS, custom domain)
For HTTPS on your own domain, put kRouter behind Nginx, Caddy or a Cloudflare Tunnel. An Nginx example:
server {
listen 443 ssl;
server_name router.example.com;
ssl_certificate /etc/letsencrypt/live/router.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/router.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:20128;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_buffering off; # needed for streaming replies
proxy_read_timeout 600s;
}
}Behind a proxy that sends X-Forwarded-For or X-Real-IP, every request counts as remote: /v1/* needs an API key, and the first dashboard login needs INITIAL_PASSWORD. Start kRouter with --host 127.0.0.1 so the proxy is the only way in. kRouter also has a built-in tunnel (Cloudflare or Tailscale) on the dashboard's Endpoint page.
Data persistence
Everything kRouter keeps lives under $DATA_DIR:
$DATA_DIR/
├── db/
│ ├── data.sqlite # providers, accounts, combos, settings, keys, history
│ └── backups/ # copies made before upgrades, migrations and imports (newest 5 kept)
├── mitm/ # MITM root certificate, only if you used MITM mode
└── jwt-secret # generated session secret (file mode 0600)data.sqlite holds your provider tokens and keys, so back it up and store the backups like secrets. Exporting or importing the database from the dashboard asks for your password again. Delete $DATA_DIR for a clean reset.
Updating in production
# npm and PM2
npm install -g @sifxprime/krouter@latest
pm2 restart krouter
# Docker
docker pull sifxprime/krouter:latest
docker rm -f krouter
# then run the two Docker lines above again
# From source
cd krouter
git pull
npm install
npm run build:deploy
pm2 restart krouterWith Docker, a password you already set under Settings → Security stays in force; the new one printed by the first line is only used if none is stored. kRouter migrates its database on the first start of a new version and takes a backup first.
Where to go next
- Security: who can reach kRouter, what it stores, MITM certificates
- CLI reference: flags, exit codes, systemd
- Architecture: how a request moves through kRouter