DurinDoor
Operations

Startup

Start, stop, health-check, and restart DurinDoor on CLI, source, or Docker.

Pick one runtime. Production listens on port 20128 unless PORT is set. Source npm run dev listens on 20127.

ModeCommandPortBind default
Global CLIdurindoor201280.0.0.0
npxnpx durindoor201280.0.0.0
Source devnpm run dev20127127.0.0.1 if HOSTNAME unset
Source prodnpm run build && npm start20128127.0.0.1 if HOSTNAME unset
Dockerdocker run or compose201280.0.0.0 in the image

custom-server.js pins HOSTNAME to 127.0.0.1 when the variable is empty, so a source production start stays on loopback. The CLI default bind is all interfaces. Docker compose sets HOSTNAME: "0.0.0.0". Do not publish 0.0.0.0 on a public network without the checks in Security.

Prepare the first start

Install or clone. Set DATA_DIR to a directory that survives restarts.

Set a unique JWT_SECRET, a stable API_KEY_SECRET, and a password of your own in a private environment file. Keep the values for later restarts. Fresh installs fail closed without JWT_SECRET or a legacy secret file. Set INITIAL_PASSWORD before remote login.

Start the process. Open http://localhost:20128/dashboard and sign in.

Change the dashboard password. Add a provider connection. Create a DurinDoor API key. Send one chat request.

Commands

durindoor
durindoor --port 8080
durindoor --host 127.0.0.1
durindoor --no-browser
durindoor --skip-update
durindoor --help

--port / -p and --host / -H override listen address. --tray runs in the system tray. --no-browser is parsed and listed in help.

Verify inference

curl http://localhost:20128/api/health

First check the listener. GET /api/health returns { "ok": true }. No API key. A 200 means the HTTP server answered, not that a provider works.

curl http://localhost:20128/v1/models \
  -H "Authorization: Bearer YOUR_DURINDOOR_API_KEY"
curl http://localhost:20128/v1/chat/completions \
  -H "Authorization: Bearer YOUR_DURINDOOR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "MODEL_ID_OR_COMBO",
    "messages": [{"role": "user", "content": "Reply OK."}],
    "max_tokens": 16
  }'

A successful inference response and a new Usage row confirm the model request completed. Replace MODEL_ID_OR_COMBO with an ID returned by /v1/models, or a combo you created. A 401 indicates rejected gateway credentials; a provider error needs a check of that connection, model entitlement, and quota.

Stop and restart

CLI and source: Ctrl+C. Docker: docker stop durindoor. Stop before a backup or upgrade. See Data management.

Restart after changing PORT, HOSTNAME, DATA_DIR, JWT_SECRET, API_KEY_SECRET, proxy env, or OAuth URL overrides. Dashboard rows stored in SQLite usually apply without a restart. A Postgres cutover flips the live adapter from Settings → Database.

Logs

docker logs -f durindoor

MITM dumps, when enabled, go under DATA_DIR/logs/mitm. ENABLE_REQUEST_LOGS=true writes metadata files under logs/ in the process working directory, not under DATA_DIR. Dashboard Console log is an in-memory ring and empties on restart.

Common failures

SymptomCauseFix
Port in useAnother process owns 20128Stop it, or pass --port / PORT
Login loopsCookie or JWT_SECRET mismatchKeep JWT_SECRET stable. Set AUTH_COOKIE_SECURE=true behind HTTPS
Data gone after restartMissing volumeMount a volume and set DATA_DIR=/app/data
OAuth callback failsPublic URL does not matchSet BASE_URL and NEXT_PUBLIC_BASE_URL
API keys invalid after redeployAPI_KEY_SECRET changedKeep the same secret across deploys
Health check failsNothing listeningConfirm port, firewall, and published container port

On this page

Edit on GitHub