[Ubuntu 24.04][Onboard] nemohermes onboard rejects CHAT_UI_URL's port as taken even when only the external interface is occupied, and never persists the external dashboard URL
- Dominant language
- TypeScript
- Stars
- 22.5k
- Forks
- 3.1k
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 715
Description
## Description
When `CHAT_UI_URL` is set to an external HTTPS address so `nemohermes onboard` can put the Hermes dashboard behind a reverse proxy, two related defects appear: (1) the port-in-use check that decides whether NemoClaw can bind its own loopback dashboard port to the same port number as `CHAT_UI_URL` does not distinguish network interfaces, so it treats the port as unavailable even when the specific loopback interface it actually needs is completely free, and silently falls back to a different port; (2) after that fallback (or even without it), the external HTTPS URL from `CHAT_UI_URL` is never recorded anywhere queryable afterward, so `status`, `dashboard-url`, and `list` all keep reporting a plain loopback address instead of the browser-facing external URL.
Platform scope: Reproduced on Ubuntu 24.04 only; other platforms not tested.
Regression: Unknown — earlier versions not tested for this path.
## Environment
```text
Device: Ubuntu 24.04 server
OS: Ubuntu 24.04.4 LTS
Architecture: x86_64
Node.js: v22.23.2
npm: 10.9.8
Docker: 29.4.0
OpenShell CLI: 0.0.106
NemoClaw: v0.0.121
OpenClaw: Hermes Agent v0.20.6
```
## Steps to Reproduce
1. Start a local TLS-terminating reverse proxy bound ONLY to the host's external network interface (not `0.0.0.0`, not `127.0.0.1`) on a currently-free port, forwarding to `127.0.0.1` on that same port number. Confirm with `ss -tlnp` that the loopback interface for that port is still completely free.
2. Run:
```bash
CHAT_UI_URL=https://{external-hostname}:{proxy-port} nemohermes onboard --name {sandbox} --non-interactive --yes --fresh
```
3. Observe the onboard log during sandbox creation.
4. After onboarding completes, run:
```bash
nemohermes {sandbox} status
nemohermes {sandbox} dashboard-url
nemoclaw list --json
```
5. Verify the reverse proxy chain itself works:
```bash
curl -sk -o /dev/null -w '%{http_code}\n' https://{external-hostname}:{proxy-port}/
```
## Expected Result
NemoClaw binds its internal dashboard to the same port number as `CHAT_UI_URL`, since only the loopback interface for that port is actually needed and it is free. No port fallback occurs.
`status`, `dashboard-url`, and the JSON output of `list` all report the external HTTPS URL (or at minimum the correct hostname and the actual port NemoClaw is using) as the browser-facing dashboard address, so an operator can retrieve it later without re-reading the one-time onboarding banner.
## Actual Result
Onboard log:
```text
! Port {proxy-port} is taken. Using port {fallback-port} instead.
```
This appears even though `ss -tlnp` confirms the loopback interface for `{proxy-port}` was completely free at the time of the check — only the external-interface-bound reverse proxy occupied that port number, on a different interface.
`nemohermes {sandbox} status`, `nemohermes {sandbox} dashboard-url`, and `nemoclaw list --json` all report only the plain internal loopback address, e.g.:
```text
Dashboard URL:
http://127.0.0.1:{fallback-port}/
```
None of them contain the external hostname or the originally configured port. The external URL appears exactly once, in the one-time onboarding completion banner, and even there it is shown with the wrong (fallback) port number rather than the port that was actually configured in `CHAT_UI_URL`.
The reverse proxy chain itself works correctly when manually redirected to the fallback port (confirmed via curl returning HTTP 200), proving the underlying defect is in NemoClaw's port negotiation and URL bookkeeping, not in the reverse proxy setup.
## Logs
```text
Onboard log excerpt:
[6/8] Creating sandbox
──────────────────────────────────────────────────
! Port {proxy-port} is taken. Using port {fallback-port} instead.
...
Deployment verified — gateway, dashboard, and inference route are healthy.
Hermes Agent Dashboard
Port {fallback-port} must be forwarded before opening this URL.
http://127.0.0.1:{fallback-port}/
https://{external-hostname}:{fallback-port}/
nemohermes {sandbox} dashboard-url output:
Dashboard URL:
http://127.0.0.1:{fallback-port}/
nemoclaw list --json excerpt:
{
"name": "{sandbox}",
"dashboardPort": {fallback-port},
...
}
```
Contributor guide
Assessment
This issue has not been assessed yet.