NVIDIA / NVIDIA/NemoClaw

No supported way to configure device-pair publicUrl, so the OpenClaw mobile app cannot pair with a NemoClaw-managed sandbox

Open
#8,837 2 comments 0 reactions 0 assignees View on GitHub
area: networking integration: openclaw needs: design needs: unblock
Dominant language
TypeScript
Stars
22.5k
Forks
3.1k
Avg merge
1d 1h
Merged PRs (30d)
715

Description

### Investigation Summary

- The OpenClaw mobile app reaches the gateway successfully over Tailscale Serve — the gateway receives the connection request and returns a pairing request ID, so the network path and TLS termination both work.
- `/pair` inside the sandbox fails with: `Error: Gateway is only bound to loopback. Set gateway.bind=lan, enable tailscale serve, or configure plugins.entries.device-pair.config.publicUrl.` Tailscale Serve is already enabled and proxying to the gateway, but the plugin evaluates the gateway's own bind address (`ws://127.0.0.1:18789`) rather than the external proxy.
- Of the three remediations the error names, none is reachable on a NemoClaw-managed sandbox: `openclaw.json` is Landlock read-only at runtime, Tailscale Serve is already active and not detected, and there is no exposed setting for `publicUrl`.
- Searches of `scripts/generate-openclaw-config.mts`, the `Dockerfile`, and `nemoclaw --help` return no match for `publicUrl`, `device-pair`, `DEVICE_PAIR`, `PUBLIC_URL`, or any device/pair subcommand.
- `/pair approve ` cannot be used as a workaround: the app retries on a short interval and each retry mints a new request ID, so every manual approval returns `Pairing request not found.`

### Description

The official OpenClaw mobile app cannot complete pairing with a gateway running inside a NemoClaw-managed sandbox, because NemoClaw exposes no way to configure the device-pair plugin's `publicUrl`.

The gateway is reachable. Tailscale Serve fronts it with TLS:

$ tailscale serve status
https://spark-2c8e..ts.net (tailnet only)
|-- / proxy http://127.0.0.1:18789

The browser dashboard connects successfully over that URL with the gateway token, and the
mobile app also reaches the gateway — it receives a pairing request ID and reports "This
device is not approved yet," which confirms the request arrives.

Pairing itself fails. Running `/pair` returns:

Error: Gateway is only bound to loopback. Set gateway.bind=lan, enable tailscale serve,
or configure plugins.entries.device-pair.config.publicUrl.

The plugin appears to evaluate the gateway's own bind (`ws://127.0.0.1:18789`, loopback)
rather than the external proxy, so it reports loopback-only even though Tailscale Serve is
active.

None of the three suggested remediations is available in this deployment:

1. `gateway.bind=lan` — `openclaw.json` is Landlock read-only at runtime and regenerated
from build arguments, so it cannot be edited in place.
2. "enable tailscale serve" — already enabled; not detected.
3. `plugins.entries.device-pair.config.publicUrl` — no NemoClaw environment variable, build
argument, or CLI flag sets this.

Expected: a supported way to declare the externally reachable gateway URL, so device pairing
works when the gateway is fronted by a proxy such as Tailscale Serve.

Actual: pairing is unreachable, and the OpenClaw mobile app cannot be used with a
NemoClaw-managed sandbox.

### Reproduction Steps

1. Onboard a NemoClaw sandbox normally (Docker driver, local vLLM inference).

2. Expose the gateway over Tailscale Serve on the host:

tailscale serve --bg 18789
tailscale serve status
# https://..ts.net (tailnet only)
# |-- / proxy http://127.0.0.1:18789

3. Confirm the path works: open `https://..ts.net` on a phone with Tailscale
connected, paste the gateway token from `nemoclaw dashboard-url --quiet`.
The browser dashboard connects.

4. Install the OpenClaw mobile app. Choose Remote Domain mode, host
`..ts.net`, port 443, TLS on, and supply the gateway token.
The app reports "This device is not approved yet" with a request ID — the gateway
received the request.

5. Attempt to approve. In the sandbox:

nemoclaw connect
openclaw devices approve

fails because the CLI's own connection now needs approval:

gateway closed (1008): pairing required: device is asking for more scopes than
currently approved

6. Attempt `/pair` from the already-authenticated browser dashboard:

/pair
→ Error: Gateway is only bound to loopback. Set gateway.bind=lan, enable tailscale
serve, or configure plugins.entries.device-pair.config.publicUrl.

/pair approve
→ Pairing request not found.
(the app retries every few seconds; each retry mints a new request ID)

7. Confirm no setting exists:

grep -ri "publicUrl\|device-pair\|DEVICE_PAIR" ~/.nemoclaw/source/scripts/generate-openclaw-config.mts
grep -ri "DEVICE_PAIR\|PUBLIC_URL" ~/.nemoclaw/source/Dockerfile
nemoclaw --help | grep -i "device\|pair"
# all return no matches

### Environment

- Platform: NVIDIA DGX Spark (GB10, aarch64), 128 GB unified memory
- Host OS: Ubuntu 24.04 / DGX OS 7.5.0, kernel 6.17.0-1026-nvidia
- GPU driver: 580.173.02, CUDA 13.0
- Docker: 29.2.1 (Docker driver)
- Node.js: v22.22.2
- NemoClaw: v0.0.106
- OpenShell: 0.0.101
- OpenClaw: 2026.7.1
- Tailscale Serve fronting the gateway with TLS on the tailnet
- Client: OpenClaw mobile app for iOS, Remote Domain mode
- Sandbox onboarded with NEMOCLAW_DISABLE_DEVICE_AUTH=1 (note: pairing still enforces
device approval, so that flag appears to govern the dashboard rather than the pairing flow)

### Debug Output

Available on request:

nemoclaw debug --output /tmp/nemoclaw-debug.tar.gz

The relevant evidence is inline in the Logs section below.

### Logs

```shell
### Tailscale Serve is active and proxying to the gateway

$ tailscale serve status
https://spark-2c8e..ts.net (tailnet only)
|-- / proxy http://127.0.0.1:18789

### The mobile app reaches the gateway

This device is not approved yet
The gateway received the connection request, but this device must be approved first.
Request ID: 40dd0bcc-4b99-40be-84d5-f8a95ba8ac9b

### /pair fails on the loopback check despite Tailscale Serve being enabled

/pair
Error: Gateway is only bound to loopback. Set gateway.bind=lan, enable tailscale serve,
or configure plugins.entries.device-pair.config.publicUrl.

### Manual approval cannot win the race — request IDs rotate on each retry

/pair approve d213696c-f5e6-4437-a59f-6beab037bcf
Pairing request not found.

### The CLI cannot be used to approve, because it needs approval itself

gateway connect failed: GatewayClientRequestError: scope upgrade pending approval
[openclaw] Reason: gateway closed (1008): pairing required: device is asking for more
scopes than currently approved
Gateway target: ws://127.0.0.1:18789
Source: local loopback
Config: /sandbox/.openclaw/openclaw.json
Bind: loopback

### No configuration surface exists

$ grep -ri "publicUrl\|device-pair\|DEVICE_PAIR" ~/.nemoclaw/source/scripts/generate-openclaw-config.mts
(no output)
$ grep -ri "DEVICE_PAIR\|PUBLIC_URL" ~/.nemoclaw/source/Dockerfile
(no output)
$ nemoclaw spark-nemo --help | grep -i "device\|pair"
(no output)
```

### Checklist

- [x] I confirmed this bug is reproducible
- [x] I searched existing issues and this is not a duplicate

Contributor guide

Open the contributing guide

Research direction

Start by reading scripts/generate-openclaw-config.mts and the Dockerfile, then inspect nemoclaw --help for existing configuration entry points. Trace how sandbox runtime settings reach OpenClaw and verify completion by confirming that a supported external URL setting survives generation and enables the documented Tailscale Serve/mobile pairing flow.

Written by the indexing model from the issue text.

Assessment

Tech stack
docker, typescript
Domain
cli, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.