CLI
Launcher flags, listen defaults, heap settings, tray behavior, and updates.
The durindoor npm package starts the bundled standalone server. It has no subcommands. The package pins Node.js 20.20.2; the repository pins npm 10.8.2.
npm install --global durindoor
durindoor --host 127.0.0.1npx durindoor runs the same launcher without a global install. The default dashboard URL is http://localhost:20128/dashboard; the client base URL is http://localhost:20128/v1. Source npm start has a separate startup path.
Flags
| Flag | Default | Effect |
|---|---|---|
-p, --port <port> | 20128 | Listen port. Parses the next argument as an integer; an invalid or zero value falls back to 20128. |
-H, --host <host> | 0.0.0.0 | Bind address. 127.0.0.1 restricts access to this machine. |
-n, --no-browser | off | Accepted for compatibility. Startup does not automatically open a browser with either value. |
-l, --log | off | Show server stdout and stderr. Without it, stdout is hidden and stderr retains a 50-line crash buffer. |
-t, --tray | off | Start in tray mode and skip the terminal menu. |
--skip-update | off | Skip the npm registry version check. Without a TTY, this also selects tray mode. |
-h, --help | Print usage and exit 0. | |
-v, --version | Print the installed package version and exit 0. |
The default bind accepts connections on all interfaces. Remote access requires the settings in Security.
Heap and DNS
The server prefers IPv4 DNS results. The default V8 heap cap is 6144 MB.
NINEROUTER_MAX_OLD_SPACE_SIZE | Effect |
|---|---|
| unset | Add --max-old-space-size=6144. |
0 | Add no heap flag; Node selects the heap size. |
| positive integer | Set the heap cap to that many MB. |
| other value | Print a warning and use the unset behavior. |
An existing --max-old-space-size or --max_old_space_size in NODE_OPTIONS takes precedence. The launcher leaves NODE_OPTIONS intact.
NINEROUTER_MAX_OLD_SPACE_SIZE=8192 durindoorPersistent data and optional dependencies
DATA_DIR defaults to ~/.9router on macOS and Linux, or %APPDATA%\9router on Windows. Windows ignores a Unix-style configured path. An unwritable configured directory falls back to the platform default. See Data management for files and backups.
Optional dependencies live under DATA_DIR/runtime/node_modules. A missing bundled WASM triggers installation of sql.js@1.14.1. Postinstall can install better-sqlite3@12.10.1; startup does not wait for a native build. macOS and Linux use systray2@2.1.4; Windows uses PowerShell NotifyIcon. Optional-install failure does not prevent server startup.
Tray and terminal menu
Readiness probes http://127.0.0.1:<port>/api/health for up to 60 seconds. The tray can attach even when readiness fails; the terminal menu waits for readiness.
The tray supports macOS, Windows, and Linux with DISPLAY set. Other environments run the server without an icon. Its menu opens the dashboard, toggles login autostart, or quits. Quit stops MITM, Headroom, tunnels, and the server.
The terminal menu offers Web UI, Terminal UI, Hide to Tray, and Exit. An available update adds Update. Terminal UI manages providers, keys, combos, CLI tools, and settings through the local API.
Hide to Tray keeps the same process on macOS. On Windows and Linux, it replaces the current server with a detached tray launcher using --tray --skip-update -p <port>. The first hide enables autostart once; DATA_DIR/autostart-decided records that choice. Tray mode ignores SIGHUP so closing the terminal does not stop it.
Login entries retain compatibility names:
| Platform | Entry |
|---|---|
| macOS | ~/Library/LaunchAgents/com.9router.autostart.plist; logs at /tmp/9router.log |
| Windows | %APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\9router.vbs |
| Linux | ~/.config/autostart/9router.desktop |
Updates
Startup checks https://registry.npmjs.org/durindoor/latest unless --skip-update is set. The request timeout is 3 seconds, with an 8-second safety timeout. Check failure does not prevent startup.
Update prints the install command, cleans up, and exits 0; it does not execute npm. Back up DATA_DIR, review Upgrading, then install and restart:
npm i -g durindoor@latest --prefer-online
durindoornpm update --global durindoor is another manual update path.
Process lifecycle
Before startup, the launcher recovers stale MITM ownership, removes leftover app processes, and tries to free the listen port. If MITM cleanup cannot be confirmed, startup stops to preserve redirect ownership. A missing bundled server exits 1 with a reinstall message.
Foreground SIGINT, SIGTERM, and SIGHUP trigger cleanup. Cleanup keeps the server alive if MITM ownership cannot be released safely.
The launcher restarts a crashed server up to twice. A run lasting 30 seconds resets the counter. Repeated crashes trigger one MITM recovery worker before exit 1; failed recovery can retain that worker for a cleanup retry.