openclaw node CLI: Headless Node Host for Remote Execution
Run a headless node host that connects to the Gateway via WebSocket and executes commands on remote systems. Ideal for Linux, Windows, or CI nodes without the macOS app.
Read this when
- Running the headless node host
- Pairing a non-macOS node for system.run
openclaw node
Operate a headless node host that links to the Gateway through WebSocket and exposes
system.run / system.which on the local system.
On macOS, the menu bar application already incorporates this node-host runtime into its
own node connection and adds native macOS capabilities. Only run openclaw node run on a
Mac when you deliberately require a headless node without the graphical app. Having
both active results in two node identities for the same device.
Why use a node host?
Deploy a node host when agents need to execute commands on remote machines within your infrastructure without installing the full macOS companion application there.
Typical scenarios:
- Execute commands on remote Linux or Windows systems (build servers, lab equipment, NAS devices).
- Keep execution sandboxed at the gateway, but hand off approved operations to other hosts.
- Offer a minimal, headless execution target for automation pipelines or CI nodes.
Execution remains protected by exec approval rules and per-agent allowlists on the node host, so command access stays explicit and scoped.
After connecting, openclaw node run can expose plugin or MCP-based tools.
The Gateway trusts descriptors from the paired node automatically, but demands
that each descriptor's command stays within the node's approved command set. The
agent sees every accepted descriptor as a standard plugin tool, though execution
still routes through node.invoke, so removing the node removes the tool from future
agent runs. Gateway operators can block publication with
gateway.nodes.pluginTools.enabled: false.
For declarative MCP tools, place the usual MCP server definition under
nodeHost.mcp.servers inside openclaw.json on the node machine, then restart the
node host. The node announces the approval-gated mcp.tools.call.v1 command
family and exposes listed tools after connecting; changing the server list later
does not require re-pairing. See
Node-hosted MCP servers.
Browser proxy (zero-config)
Node hosts automatically advertise a browser proxy unless browser.enabled is
disabled on the node. This enables the agent to use browser automation on that node
without manual configuration.
By default, the proxy reveals the node's standard browser profile surface. If you
set nodeHost.browserProxy.allowProfiles, the proxy becomes restrictive:
targeting non-allowlisted profiles is denied, and persistent profile
creation and deletion routes are blocked through the proxy.
Disable it on the node when needed:
{
nodeHost: {
browserProxy: {
enabled: false,
},
},
}
Run (foreground)
openclaw node run --host <gateway-host> --port 18789
Flags:
--host <host>: Gateway WebSocket address (default:127.0.0.1)--port <port>: Gateway WebSocket port (default:18789)--context-path <path>: Gateway WebSocket context path (for example,/openclaw-gw). Appended to the WebSocket URL.--tls: Enable TLS for the gateway connection--no-tls: Force an unencrypted Gateway connection even when the local Gateway configuration has TLS enabled--tls-fingerprint <sha256>: Expected TLS certificate fingerprint (sha256)--node-id <id>: Override the client instance ID stored in shared SQLite state (does not reset pairing)--display-name <name>: Override the node display name
Gateway auth for node host
openclaw node run and openclaw node install resolve gateway authentication from configuration or environment (no --token/--password flags on node commands):
OPENCLAW_GATEWAY_TOKEN/OPENCLAW_GATEWAY_PASSWORDare evaluated first.- Then local configuration fallback:
gateway.auth.token/gateway.auth.password. - In local mode, the node host intentionally does not inherit
gateway.remote.token/gateway.remote.password. - If
gateway.auth.token/gateway.auth.passwordis explicitly configured through SecretRef and remains unresolved, node authentication resolution fails closed (no remote fallback hiding the failure). - In
gateway.mode=remote, remote client fields (gateway.remote.token/gateway.remote.password) are also eligible according to remote precedence rules. - Node host authentication resolution only respects
OPENCLAW_GATEWAY_*environment variables.
For a node connecting to a plaintext ws:// Gateway, loopback, private IP
addresses, .local, and Tailnet *.ts.net hosts are permitted. For other
trusted private-DNS names, set OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1; without
it, node startup fails closed and prompts you to use wss://, an SSH tunnel, or
Tailscale. This is a process-environment opt-in, not an openclaw.json configuration
key.
openclaw node install stores it in the supervised node service when it
exists in the install command environment.
Service (background)
Install a headless node host as a user service (launchd on macOS, systemd on Linux, Windows Task Scheduler on Windows).
openclaw node install --host <gateway-host> --port 18789
Flags:
--host <host>: Host address for the Gateway WebSocket (default:127.0.0.1)--port <port>: Port number for the Gateway WebSocket (default:18789)--context-path <path>: Context path for the Gateway WebSocket (for example,/openclaw-gw). Gets added to the end of the WebSocket URL.--tls: Enable TLS for the gateway connection--tls-fingerprint <sha256>: Expected SHA256 fingerprint of the TLS certificate--node-id <id>: Override the client instance ID kept in the shared SQLite state (pairing is not reset)--display-name <name>: Override the display name of the node--runtime <runtime>: Service runtime (node)--force: Reinstall or overwrite when already installed
Handle the service:
openclaw node status
openclaw node start
openclaw node stop
openclaw node restart
openclaw node uninstall
Run openclaw node run to start a node host in the foreground without a service.
Service commands support --json for output that machines can parse.
The node host internally retries Gateway restarts and network closures. When the Gateway indicates a terminal pause for token, password, or bootstrap authentication, the node host records the closure details in the log and exits with a non-zero status. This allows launchd, systemd, or Task Scheduler to restart the process using updated configuration and credentials. Pauses that require pairing stay within the foreground flow so the pending request can be approved.
Pairing
The initial connection generates a pending device pairing request (role: node) on the Gateway.
If the Gateway host can SSH into the node host without interactive authentication (same user, trusted host key), the pending request gets approved automatically. The Gateway runs openclaw node identity --json on the node host via SSH and approves the request when the device key matches exactly. This behavior is enabled by default. Refer to SSH-verified device auto-approval for prerequisites and instructions on disabling it (gateway.nodes.pairing.sshVerify: false).
Otherwise, approve manually by using:
openclaw devices list
openclaw devices approve <requestId>
Inspect the local node identity that the Gateway uses for verification:
openclaw node identity --json
This outputs the device ID and public key from the primary row inside state/openclaw.sqlite. It never creates the database or a new identity.
In tightly controlled node networks, the Gateway operator can explicitly enable automatic approval of first-time node pairing from trusted CIDRs:
{
gateway: {
nodes: {
pairing: {
autoApproveCidrs: ["192.168.1.0/24"],
},
},
},
}
This feature is off by default (autoApproveCidrs is not set). It applies only to new role: node pairing requests that have no requested scopes and originate from a client IP the Gateway trusts. Manual approval is still required for operator or browser clients, Control UI, WebChat, and any changes to role, scope, metadata, or public key.
When a node retries pairing with modified authentication details (role, scopes, or public key), the previous pending request is replaced, and a new requestId is created. Run openclaw devices list again before approval.
Identity and pairing state
The headless node keeps its client instance ID separate from the signed device identity used by the Gateway for pairing and routing. This state resides in the OpenClaw state directory (~/.openclaw by default, or $OPENCLAW_STATE_DIR when set):
| State | Purpose |
|---|---|
state/openclaw.sqlite (node_host_config) | Client instance ID, display name, and Gateway connection metadata. The client sends this ID as instanceId. |
state/openclaw.sqlite (device_identities, primary) | Signed Ed25519 keypair and derived device ID. For signed connections, this device ID is the routed node ID and pairing identity. |
state/openclaw.sqlite (device_auth_tokens) | Paired device tokens, keyed by cryptographic device ID and role. |
--node-id only modifies the client instance ID within the shared SQLite state. It does not alter the cryptographic device ID or clear pairing authentication. Migrating a retired node.json using openclaw doctor --fix also does not reset pairing. To revoke and re-pair a node:
- On the Gateway, execute
openclaw nodes remove --node <id|name|ip>. - On the node, restart the installed service with
openclaw node restart, or stop and relaunch the foregroundopenclaw node runcommand. This initiates the device-pairing flow. Ifopenclaw devices listdoes not show a request and the node reportsAUTH_DEVICE_TOKEN_MISMATCH, restart or rerun it once more. The rejected attempt removes the now-revoked local token, allowing the next attempt to request pairing. - On the Gateway, run
openclaw devices list, thenopenclaw devices approve <deviceRequestId>. - Restart or rerun the node again. A client paused for pairing does not resume automatically after approval; this reconnection creates the separate command-surface request.
- On the Gateway, run
openclaw nodes pending, thenopenclaw nodes approve <nodeRequestId>.
The two request IDs are different. A trusted-CIDR policy that applies can auto-approve the initial device-pairing step, but command-surface approval remains a separate check.
Older OpenClaw releases stored node-host state in node.json, the signed identity in identity/device.json, and paired authentication in identity/device-auth.json. Stop the node host and run openclaw doctor --fix once. Doctor claims each retired source, validates it, imports and verifies the canonical SQLite row, then removes the old file. Normal node commands fail closed with this repair instruction while either a retired file or an interrupted Doctor claim remains. Keep state/openclaw.sqlite private; it contains the device keypair and authentication tokens.
Exec approvals
system.run is controlled by local exec approvals:
$OPENCLAW_STATE_DIR/exec-approvals.json, or~/.openclaw/exec-approvals.jsonwhen no value is assigned to the variable- Approvals for execution
openclaw approvals --node <id|name|ip>(modified through the Gateway)
For an approved asynchronous node execution, OpenClaw generates a canonical systemRunPlan
before issuing the prompt. The subsequently approved system.run reuses that stored
plan, so any modifications to command, cwd, or session fields made after the approval request was created are refused rather than altering what the node runs.