DurinDoor
Reference

Environment variables

Environment variables, defaults, accepted values, and runtime limits.

The starter template is .env.example. Empty environment values are removed at process start. Docker -e FOO= therefore uses the unset default. Values below are runtime defaults; the template can supply a different starter value.

JWT_SECRET is required on a fresh data dir. DurinDoor does not mint DATA_DIR/jwt-secret. An existing file from an older install is reused with a warning. Generate a value with openssl rand -hex 32.

Tables list each variable's default and effect. For example, FIRECRAWL_TIMEOUT_MS defaults to 15000, while .env.example supplies 30000.

Production secrets

VariableDefaultPurpose
JWT_SECRETnoneSigns dashboard session tokens. Env wins. Legacy DATA_DIR/jwt-secret is accepted with a warning. Missing both throws. Documented example values such as replace-me are ignored and count as unset.
INITIAL_PASSWORD123456Dashboard password when none is stored. Remote login with the built-in default, or with a documented example such as change-me or replace-me, is refused.
API_KEY_SECRETminted at DATA_DIR/api-key-secret when DATA_DIR is setSecret that signs API key checksums. Set it when minted keys must survive recreate.
MACHINE_ID_SALTendpoint-proxy-saltSalt for the machine id embedded in generated API keys.
AUTH_COOKIE_SECUREfalsetrue forces secure dashboard cookies. Otherwise https on BASE_URL / NEXT_PUBLIC_BASE_URL or the request URL decides.

Native default DATA_DIR remains ~/.9router on macOS/Linux and %APPDATA%\9router on Windows.

Listen address and URLs

VariableDefaultPurpose
PORT20128Listen port for the gateway and dashboard.
HOSTNAME127.0.0.1 from custom-server.js when unsetBind address. CLI default bind is 0.0.0.0. Docker Compose sets 0.0.0.0 inside the container.
HOST127.0.0.1Host used when deriving the provider-plugin manifest URL.
DASHBOARD_PORTfalls back to PORT then 20128Alternate port for the manifest URL.
API_PORTfalls back to PORT then 20128Alternate port for the manifest URL.
NODE_ENVunset (treated as not production / not development unless set)production for production starts. Gates shutdown, intercept-path overrides, and similar.
NINEROUTER_MAX_OLD_SPACE_SIZE6144 MBCLI child heap cap. Positive integer MB, or 0 to leave sizing to Node. An existing --max-old-space-size in NODE_OPTIONS suppresses the default.
BASE_URLunsetServer-side origin for callbacks, secure-cookie inference, and the sidecar manifest URL.
NEXT_PUBLIC_BASE_URLunsetBrowser-visible origin. Same fallback chain as BASE_URL for cookies and the manifest. Also the OAuth redirect_uri for a non-loopback install, so the consent flow lands on the public origin instead of window.location.origin behind a proxy that rewrites Host.
CLOUD_URLunsetOptional server-side origin for a separately configured remote endpoint. No hosted default.
NEXT_PUBLIC_CLOUD_URLunsetBrowser-visible remote endpoint used by selected CLI-tool helpers.
TRUST_PROXYunset (false)true plus the custom-server peer token lets login rate limiting read X-Forwarded-For.
SHUTDOWN_SECRETunsetBearer secret for /api/shutdown. Production always 403s that route.

next.config.mjs rewrites /v1/:path* to /api/v1/:path*.

Data directory and postgres

VariableDefaultPurpose
DATA_DIR~/.9router or %APPDATA%\9routerPersistent root for SQLite, auth secrets, logs, intercept files, tunnels, Headroom venv, and backups. Created with permissions 0700 when set. Unix paths on Windows are ignored.
DURINDOOR_PG_URLunsetA nonempty libpq URL selects explicit PostgreSQL startup and wins over the dashboard secret. Packaged startup treats an exact empty value as unset.
DURINDOOR_DATABASE_ENGINEunsetSet to postgres for PostgreSQL-only startup, which fails closed even if the URL is missing or empty. Without either selector, the saved engine controls legacy cutover behavior.
DURINDOOR_PG_SSLMODEunset (prefer in Compose)Appended to the URL when it has no sslmode= already.
DURINDOOR_PG_PREFERRED_VERSION18 in ComposeOperator cap on the target major version (16, 17, 18). Compose only.

Rate-limit backoff

Positive decimal integers only. A resolved maximum below the base resets the whole schedule to defaults. Maximum delay is capped at 7 days.

VariableDefaultPurpose
BACKOFF_BASE_MS2000Initial account/model lock delay after rate-limit fallback.
BACKOFF_MAX_MS300000Maximum exponential lock delay.
BACKOFF_MAX_LEVEL15Maximum exponential backoff level.

Logs and request details

ENABLE_REQUEST_LOGS writes metadata-only files under logs/ in the routing core. It never enables or vetoes database persistence. OBSERVABILITY_ENABLED overrides the dashboard enableObservability setting when set to true or false; empty defers to the dashboard.

VariableDefaultPurpose
ENABLE_REQUEST_LOGSfalse (must be the string true)Diagnostic request files under cwd/logs. No payloads, stream chunks, stacks, or URL query/fragment.
OBSERVABILITY_ENABLEDunsettrue enables Usage → Details persistence; false vetoes it.
OBSERVABILITY_MAX_RECORDS200Cap on retained request-detail rows when settings omit it.
OBSERVABILITY_BATCH_SIZE20Flush batch size.
OBSERVABILITY_FLUSH_INTERVAL_MS5000Flush interval.
LOG_LEVELINFODEBUG, INFO, WARN, ERROR.
LOG_USAGE_VERBOSEunset1 prints extra usage-tracking debug.
STRIP_REASONING_CONTENTunset1 / true / on / yes strips non-streaming reasoning_content when the message also has content. Header x-9router-reasoning: off does the same per request.
DURINDOOR_REASONING_MIN_BUDGETunset (disabled)Opt-in floor for thinking-model output budgets: a caller max_tokens in [256, floor) on a thinking-capable model is raised to the floor (clamped to the model's known output cap) so reasoning tokens cannot consume the whole budget. Unset = the existing buffer heuristic runs unchanged.
X-DurinDoor-Effort: auto (header, not env)n/aAdaptive thinking effort: when a request carries no reasoning field of any shape (reasoning_effort, reasoning, thinking), the gateway resolves auto to low/medium/high from deterministic request-shape signals scoped to the current turn (last-user-message length, context size, prior tool results, tool-loop depth). Scoped to requests dispatched in the OpenAI Chat Completions shape; a no-op elsewhere.

Treat request-log metadata as sensitive operational data. Keep opt-in diagnostics off unless needed.

Outbound proxy

Dashboard proxy settings write NINE_ROUTER_PROXY_MANAGED plus the matching URL and no-proxy vars. Process-level HTTP_PROXY / HTTPS_PROXY / ALL_PROXY / NO_PROXY (and lowercase twins) are also read. Loopback targets (localhost, *.localhost, 0.0.0.0, 127.0.0.0/8, ::, ::1, and IPv4-mapped loopback) never use an outbound proxy.

VariableDefaultPurpose
HTTP_PROXY / http_proxyunsetProxy URL for http upstreams.
HTTPS_PROXY / https_proxyunsetProxy URL for https upstreams.
ALL_PROXY / all_proxyunsetFallback proxy for all protocols.
NO_PROXY / no_proxyunsetComma-separated hosts that bypass the proxy.
NINE_ROUTER_PROXY_URLunsetManaged proxy URL written by dashboard settings.
NINE_ROUTER_NO_PROXYunsetManaged no-proxy list.
NINE_ROUTER_PROXY_MANAGEDunset1 when dashboard owns the proxy env. Disabled settings clear only managed vars.
OUTBOUND_SSRF_GUARD_ENABLEDunset (guard on)false / 0 / no / off allows private provider URLs (legacy opt-out).
OMNIROUTE_ALLOW_PRIVATE_PROVIDER_URLSunset1 / true / yes / on allows every private URL.
OMNIROUTE_ALLOW_LOCAL_PROVIDER_URLSlocal allowedBlank defaults to allowing LAN/localhost probes. Metadata endpoints stay blocked while a guard mode is active.
PROXY_CONNECT_TIMEOUT_MS90000Connect timeout for proxied fetches.
PROXY_HEADERS_TIMEOUT_MS300000Headers timeout for proxied fetches.

Prefer dashboard proxy settings for day-to-day use. Use process-level vars for container egress.

Timeouts and stream bounds

Most timeout variables parse an integer greater than zero. Invalid or nonpositive values use the default. SSE_KEEPALIVE_MS and STREAM_EARLY_EOF_PEEK_MS also accept 0 to turn the feature off.

VariableDefaultPurpose
GITHUB_CREDIT_USAGE_CACHE_TTL_MS30000Reuse a GitHub Copilot credit reading for this duration before checking the local credit cutoff again.
SSE_KEEPALIVE_MS10000Claude SSE ping interval during upstream silence. 0 disables.
STREAM_STALL_TIMEOUT_MS360000Inter-chunk stall timeout once tokens flow.
STREAM_FIRST_CHUNK_TIMEOUT_MS200000Time-to-first-token timeout.
STREAM_EARLY_EOF_PEEK_MS10000How long a direct stream is held for its first content frame. A stream that ends or errors empty inside it retries once on a sibling connection. 0 disables.
OLLAMA_LOCAL_CONNECT_TIMEOUT_MS120000Connect timeout for Ollama Local. Raise it for slow 70B loads.
COMBO_MODEL_TIMEOUT_MS0 (off)Per-member combo timeout. 0 uses fetch connect timeout.
FETCH_CONNECT_TIMEOUT_MS60000Abort if upstream headers never arrive.
PROVIDER_BODY_TIMEOUT_MS120000Bound for a successful non-streaming provider body.
RESPONSE_BODY_TIMEOUT_MS120000Bound for forced stream-to-json conversion.
MAX_PROVIDER_BODY_BYTES8388608Max provider body bytes.
MAX_RESPONSES_OUTPUT_ITEMS1024Cap on Responses output items.
CODEX_SSE_PEEK_TIMEOUT_MS30000 (capped at 5 min)Bound for the Codex SSE peek.
GEMINI_NATIVE_TTS_FETCH_TIMEOUT_MS45000Gemini native TTS header timeout.
CONCURRENCY_GATE_TIMEOUT_MS120000Wait for a provider concurrency slot.
TRAE_STREAM_TIMEOUT_MS300000Trae stream timeout.
VIDEO_FETCH_TIMEOUT_MS120000Video fetch timeout.
CODEX_REFRESH_SPACING_MS2000Gap between sibling OAuth refreshes. 0 opts out.
BG_REFRESH_DELAY_MS1500Background token refresh delay (normal).
BG_REFRESH_GOOGLE_DELAY_MS12000Background refresh delay for Google-family tokens.
DISABLE_BACKGROUND_TOKEN_REFRESHunsetTruthy disables background refresh.
ONBOARD_MAX_ATTEMPTS2Gemini/Antigravity project-id onboard attempts.
ONBOARD_RETRY_DELAY_MS12000Delay between onboard attempts.
EAGER_PROJECT_ID_REFRESHunsettrue refreshes Google project ids eagerly.
VariableDefaultPurpose
FIRECRAWL_BASE_URLhttps://api.firecrawl.dev (hosted); http://127.0.0.1:3002 for firecrawl_custom if env is unsetFirecrawl-compatible base for /v1/web/fetch.
FIRECRAWL_API_KEYunsetFirecrawl key. Leave empty for a self-hosted instance that does not need one.
FIRECRAWL_TIMEOUT_MS15000Request timeout. .env.example writes 30000.
FIRECRAWL_DEFAULT_FORMATmarkdownDefault extraction format.
SEARXNG_URLhttp://localhost:8888/searchBuilt-in unauthenticated SearXNG web-search endpoint.
CLINE_LIVE_CATALOGunset (off)true fetches Cline's live OAuth model catalog. Default stays the registry.

OAuth client overrides

Most OAuth providers use built-in client metadata. Set these only when you run your own OAuth app.

VariableDefaultPurpose
MIMO_LOGIN_PROXYunsetHTTP proxy for non-CN Xiaomi MiMo browser login. Without it, login probes local HTTP proxies; CN login stays direct.
GEMINI_OAUTH_CLIENT_IDemptyGemini CLI OAuth client id.
GEMINI_OAUTH_CLIENT_SECRETemptyGemini CLI OAuth client secret.
GEMINI_CLIENT_IDunsetAlternate Gemini client id used by model-list helpers.
GEMINI_CLIENT_SECRETunsetAlternate Gemini client secret for those helpers.
ANTIGRAVITY_OAUTH_CLIENT_IDemptyAntigravity OAuth client id.
ANTIGRAVITY_OAUTH_CLIENT_SECRETemptyAntigravity OAuth client secret.
AGY_CLIENT_IDunsetAntigravity client id used by model-list helpers.
AGY_CLIENT_SECRETunsetAntigravity client secret for those helpers.
CLAUDE_CODE_CLIENT_VERSION2.1.282Claude Code version sent in the Claude User-Agent and billing header. Ignored unless it is a short header-safe token ([A-Za-z0-9][A-Za-z0-9._-]{0,31}). Read at startup.
KIMI_CODING_OAUTH_CLIENT_IDregistry clientIdKimi Coding device-code client id.
GHE_COPILOT_OAUTH_CLIENT_IDregistry clientIdGitHub Enterprise Copilot device-code client id, for a GHES instance with its own OAuth app.
GITLAB_BASE_URLhttps://gitlab.comGitLab origin.
GITLAB_DUO_BASE_URLhttps://gitlab.comGitLab Duo origin (preferred over GITLAB_BASE_URL).
GITLAB_OAUTH_CLIENT_IDregistryGitLab OAuth client id.
GITLAB_OAUTH_CLIENT_SECRETregistryGitLab OAuth client secret.
GITLAB_DUO_OAUTH_CLIENT_IDregistryGitLab Duo OAuth client id.
GITLAB_DUO_OAUTH_CLIENT_SECRETregistryGitLab Duo OAuth client secret.

MCP gateway, tunnels, Headroom

MCP OAuth needs a public https URL. If the dashboard is reached through a tunnel, set that origin here.

VariableDefaultPurpose
MCP_GATEWAY_OAUTH_PUBLIC_URLunsetPublic origin for MCP Gateway OAuth callbacks. Wins, then tunnel status, then the request.
OAUTH_PUBLIC_BASE_URLunsetOlder public OAuth origin fallback.
TUNNEL_WORKER_URLhttps://abc-tunnel.usCloudflare tunnel worker endpoint.
TUNNEL_TRANSPORT_PROTOCOLhttp2Quick tunnel protocol: http2, quic, auto.
CLOUDFLARED_PROTOCOLhttp2Alternate name for the same protocol.
HEADROOM_URLhttp://localhost:8787External Headroom proxy URL.
HEADROOM_API_KEYunsetOptional key forwarded to the Headroom proxy route.

Local intercept helper

The intercept helper is optional and local. Several of these are set by the manager for the child process. Do not set the nonce/gate vars by hand.

VariableDefaultPurpose
MITM_ROUTER_BASEhttp://localhost:20128Router base used by the intercept helper.
MITM_SERVER_PATHauto-detected src/mitm/server.jsOverride the intercept server entrypoint. Ignored in production unless the path is inside the installed tree.
MITM_LISTEN_PORT8443Intercept listen port. Must be 1025-65535 (Windows allows 1-65535).
DEBUG_MITMunsetTruthy enables verbose intercept handler logs.
ROUTER_API_KEYunsetOptional key the intercept helper sends to the local router.
MITM_GLOBAL_STATE_DIRunsetNon-production only: shared intercept state dir.
MITM_CA_PREPAREDset to 1 by the managerChild marker that the CA is ready.
MITM_INSTANCE_NONCEset by the managerLaunch-gate nonce.
MITM_LAUNCH_GATE_FILEset by the managerLaunch-gate file path.
MITM_MANAGER_PIDset by the managerParent pid for the launch gate.

ChatGPT Web

See ChatGPT Web for the transports these tune.

VariableDefaultPurpose
DURINDOOR_BROWSER_POOLonoff, 0 or false disables the shared browser pool; ChatGPT Web auto then uses HTTP.
DURINDOOR_BROWSER_AUTO_INSTALLoff1 runs playwright install chromium the first time no browser is found.
DURINDOOR_CHATGPT_WEB_HEADLESSoff1 runs the ChatGPT Web browser headless instead of headed off-screen.
CHATGPT_WEB_CHROME_PATHunset (CHROME_PATH, then standard install paths)Chrome or Chromium binary for the browser transport. The Docker image sets /usr/bin/chromium-browser.
OBSCURA_BIN, OBSCURA_CDP_ENDPOINT, OBSCURA_PORTunsetOptional Obscura engine for headless pool contexts.
DURINDOOR_CHATGPT_TLS_TIMEOUT_MS60000HTTP transport request timeout.
DURINDOOR_CHATGPT_TLS_GRACE_MS10000Grace period before a hung tls-client call is abandoned.
DURINDOOR_CHATGPT_STREAM_FIRST_BYTE_TIMEOUT_MS30000HTTP transport wait for the first streamed byte.
DURINDOOR_CGPT_WEB_PRO_TIMEOUT_MS1200000How long the HTTP transport polls for a Pro answer.
DURINDOOR_CGPT_WEB_PRO_POLL_INTERVAL_MS4000Pro answer poll interval.
DURINDOOR_CGPT_WEB_IMAGE_TIMEOUT_MS180000Wait for an asynchronous generated image.
DURINDOOR_CGPT_WEB_IMAGE_CACHE_MAX_MB10In-memory cache for generated images served at /v1/chatgpt-web/image/<id>.
DURINDOOR_PUBLIC_BASE_URLunset (then BASE_URL, NEXT_PUBLIC_BASE_URL, request headers, localhost:$PORT)Public origin used in generated image links.
DURINDOOR_XVFBon in Docker0 stops the image entrypoint from starting Xvfb.

Optional routing classifier

VariableDefaultPurpose
TYPESAFE_API_KEYunsetEnable the TypeSafe Jev complexity classifier for smart chat combos. Failures fall back to the local heuristic.
TYPESAFE_API_BASEhttps://api.typesafe.aiClassifier service origin; distinct from the direct System One provider connection.

Provider debug, sidecars, Azure

VariableDefaultPurpose
VALIDATE_OUTBOUNDtruefalse disables outbound payload validation. Keys are still stripped.
ENABLE_TRANSLATORunset (false)true enables the dashboard translator feature path.
CLIPROXYAPI_HOST127.0.0.1CLIProxyAPI sidecar host when settings have no URL.
CLIPROXYAPI_PORT8317CLIProxyAPI sidecar port.
OMNIROUTE_PROVIDER_MANIFEST_URLderived from BASE_URL or http://127.0.0.1:20128/api/v1/provider-plugin-manifestPublic provider manifest URL advertised to sidecars.
OMNIROUTE_PUBLIC_PROTOCOLhttpProtocol used when deriving that URL from host and port.
CURSOR_STREAM_DEBUGunset1 logs Cursor executor stream debug.
CURSOR_PROTOBUF_DEBUGunset1 logs Cursor protobuf debug.
CLAUDE_DISABLE_TOOL_NAME_CLOAKunsettrue disables Claude Code tool-name cloaking.
AZURE_ENDPOINThttps://api.openai.comAzure OpenAI endpoint when the connection has none.
AZURE_API_VERSION2024-10-01-previewAzure API version fallback.
AZURE_DEPLOYMENTgpt-4Azure deployment fallback.
AZURE_ORGANIZATIONunsetAzure OpenAI-Organization header.
OPENAI_API_KEYunsetAzure executor api-key fallback when the connection has none.
WINDSURF_API_KEYunsetDevin CLI executor key fallback.

Provider-level CLIProxyAPI routing lives in the upstreamProxyConfig settings map (enabled, mode = native / cliproxyapi / fallback, cliproxyapiModelMapping). A connection can set providerSpecificData.cliproxyapiMode = "claude-native" to route only that connection.

CLI binaries and local tools

VariableDefaultPurpose
AUGGIE_BIN / CLI_AUGGIE_BINunsetPath to the Auggie binary.
CLI_DEVIN_BINunsetPath to the Devin CLI binary.
GROK_HOME~/.grokGrok CLI home used by dashboard Grok Build settings.
TRAY_MODEunset1 marks a tray-launched process (set by the CLI).
DISPLAYunsetLinux tray needs an X display. Without it tray init returns null and the server still runs.
CODESPACESunsetCodespaces detection for printed URLs.
GITHUB_CODESPACES_PORT_FORWARDING_DOMAINunsetCodespaces forwarded-port domain.

Build, packaging, updater

VariableDefaultPurpose
NEXT_DIST_DIR.nextNext.js output directory.
NEXT_TRACING_ROOT_MODEproject rootworkspace traces from the parent of the project (CLI packaging).
NINEROUTER_PROXY_CLIENT_MAX_BODY_SIZE128mbNext.js proxy client body-size limit for large LLM requests.
NEXT_PHASEset by Nextphase-production-build / phase-export / phase-static skip app bootstrap.
NEXT_RUNTIMEset by Nextnodejs selects the Node instrumentation file.
DURINDOOR_BUILDunset1 also skips bootstrap during packaging.
DURINDOOR_WORKER_NONCEset by custom-server48-hex worker identity header. Do not set by hand.
NINEROUTER_PEER_TOKENminted by custom-serverProves x-9r-real-ip came from the wrapper. Do not set by hand.

Updater internals. Packaged updater only; they can change without notice.

VariableDefaultPurpose
UPDATER_PKG_NAME9routernpm package the updater installs.
UPDATER_PORT20129Updater progress port.
UPDATER_APP_PORT20128App port the updater waits on.
UPDATER_TAIL_LINES8Log tail lines.
UPDATER_RETRIES3Install retries.
UPDATER_RETRY_DELAY_MS5000Delay between retries.
UPDATER_LINGER_MS30000Linger after finish.
UPDATER_WAIT_MIN_MS3000Minimum wait for the app port.
UPDATER_WAIT_MAX_MS15000Maximum wait for the app port.
UPDATER_WAIT_CHECK_MS500Port poll interval.
UPDATER_SCRIPT_PATHderivedPath to the updater script.
UPDATER_RELAUNCHunsetRelaunch switch.
UPDATER_RELAUNCH_CMDunsetRelaunch command.
UPDATER_RELAUNCH_ARGSunsetRelaunch args.

Host process

Read for paths and temp dirs. Operators do not normally set these.

VariableDefaultPurpose
HOMEOS homeHeadroom python / detect paths.
USERPROFILEWindows homeHeadroom python on Windows.
APPDATAWindows roamingDefault DATA_DIR parent; updater and intercept paths.
LOCALAPPDATAWindows localCursor/Auggie/Devin local stores; Headroom detect.
XDG_CONFIG_HOMEunsetjcode settings path on Linux.
PATHOS pathHeadroom, Tailscale, CLI-tool binary lookup.
TMPDIR / TMP / TEMPOS tempIntercept helper temp files.
SystemRootC:\WindowsWindows hosts-file path for intercept-host cleanup.

On this page

Edit on GitHub