Skip to content

fix(onboard): skip OLLAMA_HOST=0.0.0.0 on WSL2 to fix Docker routing#1104

Merged
ericksoa merged 1 commit intoNVIDIA:mainfrom
jieunl24:fix/ollama-wsl-dualstack
Mar 30, 2026
Merged

fix(onboard): skip OLLAMA_HOST=0.0.0.0 on WSL2 to fix Docker routing#1104
ericksoa merged 1 commit intoNVIDIA:mainfrom
jieunl24:fix/ollama-wsl-dualstack

Conversation

@jieunl24
Copy link
Copy Markdown
Contributor

@jieunl24 jieunl24 commented Mar 30, 2026

Summary

Ollama's Go runtime creates a dual-stack (AF_INET6) socket when given OLLAMA_HOST=0.0.0.0, but WSL2's port relay only forwards IPv4 sockets to the Windows host. Docker's host-gateway cannot reach the dual-stack socket, causing inference requests to fail with connection refused.

On WSL2, let Ollama bind to the default 127.0.0.1 instead, which creates an IPv4-only socket that the WSL2 relay forwards correctly.

Current support matrix on Windows / WSL Ollama inference path

┌─────────────────────┬──────────────────────┬─────────────────────────────────────────────────────┐
│ WSL Ollama          │ Windows Ollama       │ Result                                              │
├─────────────────────┼──────────────────────┼─────────────────────────────────────────────────────┤
│ running (systemd    │ -                    │ Works.                                              │
│ or manual)          │                      │ wslrelay forwards 127.0.0.1:11434 to Windows host,  │
│                     │                      │ gateway reaches it via host.openshell.internal.     │
├─────────────────────┼──────────────────────┼─────────────────────────────────────────────────────┤
│ installed, not      │ -                    │ Works with isWsl fix.                               │
│ running             │                      │ Onboard starts Ollama on 127.0.0.1 (default).       │
│                     │                      │ Without fix: Go binds dual-stack socket (*:11434),  │
│                     │                      │ wslrelay can't forward it (WSL#4851), gateway fails.│
├─────────────────────┼──────────────────────┼─────────────────────────────────────────────────────┤
│ not installed       │ installed / running  │ Ollama option doesn't show.                         │
│                     │                      │ hasOllama=false (binary not in WSL PATH),           │
│                     │                      │ ollamaRunning=false (WSL localhost can't reach      │
│                     │                      │ Windows 127.0.0.1).                                 │
├─────────────────────┼──────────────────────┼─────────────────────────────────────────────────────┤
│ running / started   │ running              │ Does not work.                                      │
│ by onboard          │                      │ Windows Ollama blocks wslrelay on port 11434.       │
│                     │                      │ Gateway hits Windows Ollama via host-gateway, but   │
│                     │                      │ model was pulled to WSL -> 404 model not found.     │
├─────────────────────┼──────────────────────┼─────────────────────────────────────────────────────┤
│ installed, not      │ running              │ Same as row 4.                                      │
│ running             │                      │                                                     │
└─────────────────────┴──────────────────────┴─────────────────────────────────────────────────────┘

Related Issue

#336 #417

Changes

On WSL2, skip setting OLLAMA_HOST=0.0.0.0:11434 when starting Ollama during onboard, letting it bind to the default 127.0.0.1 instead. Uses the existing isWsl() helper from platform.js to detect WSL2.

Type of Change

  • Code change for a new feature, bug fix, or refactor.
  • Code change with doc updates.
  • Doc only. Prose changes without code sample modifications.
  • Doc only. Includes code sample changes.

Testing

  • npx prek run --all-files passes (or equivalently make check).
  • npm test passes.
  • make docs builds without warnings. (for doc-only changes)

Checklist

General

Code Changes

  • Formatters applied — npx prek run --all-files auto-fixes formatting (or make format for targeted runs).
  • Tests added or updated for new or changed behavior.
  • No secrets, API keys, or credentials committed.
  • Doc pages updated for any user-facing behavior changes (new commands, changed defaults, new features, bug fixes that contradict existing docs).

Doc Changes

  • Follows the style guide. Try running the update-docs agent skill to draft changes while complying with the style guide. For example, prompt your agent with "/update-docs catch up the docs for the new changes I made in this PR."
  • New pages include SPDX license header and frontmatter, if creating a new page.
  • Cross-references and links verified.

Summary by CodeRabbit

  • Bug Fixes

    • Adjusted Ollama local startup so non-WSL systems explicitly set the host binding while WSL systems leave Ollama to use its default binding, preventing incorrect forced bindings during local startup.
  • Documentation

    • Clarified that the Ollama installation option is macOS-only.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 30, 2026

📝 Walkthrough

Walkthrough

Detect WSL in bin/lib/onboard.js and omit setting OLLAMA_HOST when running under WSL; on non-WSL systems set OLLAMA_HOST=0.0.0.0:11434 for local Ollama startup. Added a comment noting the "install-ollama" option is macOS-only. (Lines changed: +7/-1)

Changes

Cohort / File(s) Summary
Ollama WSL startup
bin/lib/onboard.js
Import isWsl and use it in setupNim for provider "ollama" to conditionally include or omit the OLLAMA_HOST=0.0.0.0:11434 prefix when starting Ollama; add comment that "install-ollama" is macOS-only.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 I hopped through lines of code so neat,
Left host vars out when WSL took seat,
On other boxes I open the door,
A tiny tweak to start once more,
Nibbles of change, and then a treat 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: fixing Ollama host binding on WSL2 to resolve Docker routing issues, which is the core purpose of the PR.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

@jieunl24 jieunl24 requested a review from ericksoa March 30, 2026 16:45
@kjw3 kjw3 self-assigned this Mar 30, 2026
Ollama's Go runtime creates a dual-stack (AF_INET6) socket when given
OLLAMA_HOST=0.0.0.0, but WSL2's port relay only forwards IPv4 sockets
to the Windows host. Docker's host-gateway cannot reach the dual-stack
socket, causing inference requests to fail with connection refused.

On WSL2, let Ollama bind to the default 127.0.0.1 instead, which
creates an IPv4-only socket that the WSL2 relay forwards correctly.
@jieunl24 jieunl24 force-pushed the fix/ollama-wsl-dualstack branch from a7bf527 to 7c44475 Compare March 30, 2026 17:15
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
bin/lib/onboard.js (1)

1911-2324: setupNim is still too complex; consider extracting provider handlers.

This change adds more branching in an already very large function. Splitting remote/local provider flows into helpers would improve readability and testability while keeping policy limits in check.

As per coding guidelines, "Maintain cyclomatic complexity limit of 20 (target: ratchet down to 15) for all functions."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bin/lib/onboard.js` around lines 1911 - 2324, The setupNim function is too
large and has high cyclomatic complexity; refactor by extracting each provider
branch into small helper handlers and have setupNim orchestrate them. Create
functions like handleRemoteProviderSelection(selected, requestedModel) to
encapsulate the REMOTE_PROVIDER_CONFIG path (including
custom/anthropicCompatible handling, model prompting/validation,
ensureApiKey/ensureNamedCredential and return {model, provider, endpointUrl,
credentialEnv, preferredInferenceApi}), handleNimLocalSelection(gpu,
requestedModel) to encapsulate
nim.listModels/pullNimImage/startNimContainer/health check and return the same
object plus nimContainer or signal fallback, handleOllamaSelection(selectedKey,
gpu, requestedModel) to start/ensure Ollama, prompt/validate models and return
the same object, and handleVllmSelection(requestedModel) to query vLLM and
validate model; then simplify setupNim to call these handlers based on
selected.key, handle errors/continue selectionLoop when handlers indicate retry,
and keep return shape { model, provider, endpointUrl, credentialEnv,
preferredInferenceApi, nimContainer } unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@bin/lib/onboard.js`:
- Around line 2196-2200: The validateLocalProvider("ollama-local") guidance
needs to reflect the WSL exception used in onboard.js (isWsl() causes ollama to
bind to 127.0.0.1 instead of 0.0.0.0); update the user-facing message in
bin/lib/local-inference.js so it conditionally recommends 127.0.0.1:11434 when
isWsl() is true and 0.0.0.0:11434 otherwise (or add a short note that WSL should
use 127.0.0.1), keeping the check consistent with the isWsl() logic used around
run(`${ollamaEnv}ollama serve ...`) and ensuring
validateLocalProvider("ollama-local") outputs the correct host suggestion.
- Around line 2199-2200: The WSL branch currently sets ollamaEnv = "" which
leaves any parent OLLAMA_HOST exported and can leak into the child; change the
assignment so the WSL branch explicitly clears the variable for the child
process (e.g., set ollamaEnv to "OLLAMA_HOST= " or use "unset OLLAMA_HOST &&"
before the command) so the run call (run(`${ollamaEnv}ollama serve ...`, {
ignoreError: true })) executes with OLLAMA_HOST cleared; update the code that
defines ollamaEnv (the isWsl() ternary) accordingly.

---

Nitpick comments:
In `@bin/lib/onboard.js`:
- Around line 1911-2324: The setupNim function is too large and has high
cyclomatic complexity; refactor by extracting each provider branch into small
helper handlers and have setupNim orchestrate them. Create functions like
handleRemoteProviderSelection(selected, requestedModel) to encapsulate the
REMOTE_PROVIDER_CONFIG path (including custom/anthropicCompatible handling,
model prompting/validation, ensureApiKey/ensureNamedCredential and return
{model, provider, endpointUrl, credentialEnv, preferredInferenceApi}),
handleNimLocalSelection(gpu, requestedModel) to encapsulate
nim.listModels/pullNimImage/startNimContainer/health check and return the same
object plus nimContainer or signal fallback, handleOllamaSelection(selectedKey,
gpu, requestedModel) to start/ensure Ollama, prompt/validate models and return
the same object, and handleVllmSelection(requestedModel) to query vLLM and
validate model; then simplify setupNim to call these handlers based on
selected.key, handle errors/continue selectionLoop when handlers indicate retry,
and keep return shape { model, provider, endpointUrl, credentialEnv,
preferredInferenceApi, nimContainer } unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: bebd8d60-0401-4688-8063-18dc8febe542

📥 Commits

Reviewing files that changed from the base of the PR and between a7bf527 and 7c44475.

📒 Files selected for processing (1)
  • bin/lib/onboard.js

Comment thread bin/lib/onboard.js
Comment on lines +2196 to +2200
// On WSL2, binding to 0.0.0.0 creates a dual-stack socket that Docker
// cannot reach via host-gateway. The default 127.0.0.1 binding works
// because WSL2 relays IPv4-only sockets to the Windows host.
const ollamaEnv = isWsl() ? "" : "OLLAMA_HOST=0.0.0.0:11434 ";
run(`${ollamaEnv}ollama serve > /dev/null 2>&1 &`, { ignoreError: true });
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Update local-validation guidance to include the WSL exception.

With Line 2199 intentionally avoiding 0.0.0.0 on WSL, the current validateLocalProvider("ollama-local") message in bin/lib/local-inference.js still tells users to bind 0.0.0.0:11434, which is now the known-bad path on WSL.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bin/lib/onboard.js` around lines 2196 - 2200, The
validateLocalProvider("ollama-local") guidance needs to reflect the WSL
exception used in onboard.js (isWsl() causes ollama to bind to 127.0.0.1 instead
of 0.0.0.0); update the user-facing message in bin/lib/local-inference.js so it
conditionally recommends 127.0.0.1:11434 when isWsl() is true and 0.0.0.0:11434
otherwise (or add a short note that WSL should use 127.0.0.1), keeping the check
consistent with the isWsl() logic used around run(`${ollamaEnv}ollama serve
...`) and ensuring validateLocalProvider("ollama-local") outputs the correct
host suggestion.

Comment thread bin/lib/onboard.js
Comment on lines +2199 to +2200
const ollamaEnv = isWsl() ? "" : "OLLAMA_HOST=0.0.0.0:11434 ";
run(`${ollamaEnv}ollama serve > /dev/null 2>&1 &`, { ignoreError: true });
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Clear inherited OLLAMA_HOST in the WSL path.

At Line 2199, omitting inline assignment does not remove an already-exported OLLAMA_HOST from the parent environment. That can silently bypass this fix on WSL.

💡 Proposed fix
-        const ollamaEnv = isWsl() ? "" : "OLLAMA_HOST=0.0.0.0:11434 ";
-        run(`${ollamaEnv}ollama serve > /dev/null 2>&1 &`, { ignoreError: true });
+        const ollamaEnvPrefix = isWsl() ? "env -u OLLAMA_HOST " : "OLLAMA_HOST=0.0.0.0:11434 ";
+        run(`${ollamaEnvPrefix}ollama serve > /dev/null 2>&1 &`, { ignoreError: true });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const ollamaEnv = isWsl() ? "" : "OLLAMA_HOST=0.0.0.0:11434 ";
run(`${ollamaEnv}ollama serve > /dev/null 2>&1 &`, { ignoreError: true });
const ollamaEnvPrefix = isWsl() ? "env -u OLLAMA_HOST " : "OLLAMA_HOST=0.0.0.0:11434 ";
run(`${ollamaEnvPrefix}ollama serve > /dev/null 2>&1 &`, { ignoreError: true });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bin/lib/onboard.js` around lines 2199 - 2200, The WSL branch currently sets
ollamaEnv = "" which leaves any parent OLLAMA_HOST exported and can leak into
the child; change the assignment so the WSL branch explicitly clears the
variable for the child process (e.g., set ollamaEnv to "OLLAMA_HOST= " or use
"unset OLLAMA_HOST &&" before the command) so the run call
(run(`${ollamaEnv}ollama serve ...`, { ignoreError: true })) executes with
OLLAMA_HOST cleared; update the code that defines ollamaEnv (the isWsl()
ternary) accordingly.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fix intentionally avoids overriding OLLAMA_HOST on WSL2 to let Ollama use its default binding. If a user has explicitly exported OLLAMA_HOST=0.0.0.0 in their environment, that's an intentional configuration choice - overriding it silently would be surprising. This is an unlikely edge case since neither the Ollama installer nor NemoClaw sets this variable in shell profiles.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jieunl24, that's a fair point — respecting an explicitly exported OLLAMA_HOST is consistent with the principle of least surprise for users who intentionally configure their own binding. The edge case is unlikely enough that silently clearing it would probably cause more confusion than it prevents. I'll defer to your judgment here.


✏️ Learnings added
Learnt from: jieunl24
Repo: NVIDIA/NemoClaw PR: 1104
File: bin/lib/onboard.js:2199-2200
Timestamp: 2026-03-30T17:32:13.519Z
Learning: In `bin/lib/onboard.js` (NemoClaw project), the WSL2 Ollama startup path intentionally does NOT clear an inherited `OLLAMA_HOST` environment variable (e.g., via `env -u OLLAMA_HOST`). The design decision is to respect any explicitly exported `OLLAMA_HOST` as an intentional user configuration choice. The fix only avoids *setting* `OLLAMA_HOST=0.0.0.0:11434` inline on WSL2; it does not override pre-existing env values. This is considered acceptable because neither the Ollama installer nor NemoClaw sets `OLLAMA_HOST` in shell profiles.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@ericksoa ericksoa merged commit 07589f8 into NVIDIA:main Mar 30, 2026
8 checks passed
laitingsheng pushed a commit that referenced this pull request Apr 2, 2026
…1104)

Ollama's Go runtime creates a dual-stack (AF_INET6) socket when given
OLLAMA_HOST=0.0.0.0, but WSL2's port relay only forwards IPv4 sockets
to the Windows host. Docker's host-gateway cannot reach the dual-stack
socket, causing inference requests to fail with connection refused.

On WSL2, let Ollama bind to the default 127.0.0.1 instead, which
creates an IPv4-only socket that the WSL2 relay forwards correctly.
lakamsani pushed a commit to lakamsani/NemoClaw that referenced this pull request Apr 4, 2026
…VIDIA#1104)

Ollama's Go runtime creates a dual-stack (AF_INET6) socket when given
OLLAMA_HOST=0.0.0.0, but WSL2's port relay only forwards IPv4 sockets
to the Windows host. Docker's host-gateway cannot reach the dual-stack
socket, causing inference requests to fail with connection refused.

On WSL2, let Ollama bind to the default 127.0.0.1 instead, which
creates an IPv4-only socket that the WSL2 relay forwards correctly.
gemini2026 pushed a commit to gemini2026/NemoClaw that referenced this pull request Apr 14, 2026
…VIDIA#1104)

Ollama's Go runtime creates a dual-stack (AF_INET6) socket when given
OLLAMA_HOST=0.0.0.0, but WSL2's port relay only forwards IPv4 sockets
to the Windows host. Docker's host-gateway cannot reach the dual-stack
socket, causing inference requests to fail with connection refused.

On WSL2, let Ollama bind to the default 127.0.0.1 instead, which
creates an IPv4-only socket that the WSL2 relay forwards correctly.
prekshivyas added a commit that referenced this pull request Apr 15, 2026
Ollama has no built-in auth and binding to 0.0.0.0 exposes it to the
network (CWE-668, #1140). This adds an authenticated reverse proxy so
Ollama stays on localhost while containers can still reach it.

- Add scripts/ollama-auth-proxy.js — Node.js proxy on 0.0.0.0:11435
  that validates a per-instance Bearer token before forwarding to
  Ollama on 127.0.0.1:11434. Health check (GET /api/tags) is exempt.
  Uses crypto.timingSafeEqual for timing-safe token comparison.
- Bind Ollama to 127.0.0.1 instead of 0.0.0.0 during onboard
- Start the auth proxy after Ollama, with stale proxy cleanup and
  startup verification
- Route sandbox inference through proxy port (11435) with the
  generated token as the OpenAI API key credential
- Gate macOS hint on process.platform === "darwin"
- Add OLLAMA_PROXY_PORT (11435) to ports.ts
- Add 7 e2e tests and CI job for the proxy
- Update unit tests for new port and error messages

Reimplements the approach from #679 (closed in favor of #1104) against
the current TypeScript codebase, addressing CodeRabbit findings from
the original PR (timing-safe comparison, stale proxy cleanup, startup
verification).

Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
prekshivyas added a commit that referenced this pull request Apr 15, 2026
- Persist proxy token to ~/.nemoclaw/ollama-proxy-token (mode 0600)
  so it survives process restarts and onboard --resume
- Add ensureOllamaAuthProxy() called on sandbox connect to auto-restart
  the proxy after host reboots
- Restore WSL2 compatibility: skip proxy on WSL2 where Docker reaches
  the host directly (#1104), use OLLAMA_CONTAINER_PORT that adapts
  per platform
- Fix e2e test: replace invalid 0.0.0.0 reachability test with
  localhost liveness check (0.0.0.0 as destination routes to loopback
  on both Linux and macOS)

Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants