Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/inference/use-local-inference.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,10 @@ If both WSL and Windows-host Ollama are running, pick the intended menu entry du
### Authenticated Reverse Proxy

On non-WSL hosts, NemoClaw keeps Ollama bound to `127.0.0.1:11434` and starts a token-gated reverse proxy on `0.0.0.0:11435`.
The native install/start paths also reset NemoClaw-managed systemd launches to the loopback binding.
Containers and other hosts on the local network reach Ollama only through the
proxy, which validates a Bearer token before forwarding requests.
Ollama itself is never exposed without authentication.
On that native path, NemoClaw never exposes Ollama without authentication.

WSL Ollama paths do not use this proxy.
Windows-host Ollama uses the Windows daemon through `host.docker.internal`.
Expand Down
4 changes: 2 additions & 2 deletions src/lib/local-inference.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ export type RunCaptureFn = (cmd: string | string[], opts?: { ignoreError?: boole
// Hosts that the WSL-side onboard CLI tries when probing Ollama. Native Linux
// and macOS only ever reach Ollama on the local loopback. WSL with Docker
// Desktop can also reach a Windows-host Ollama through the docker-desktop
// integration's `host.docker.internal` alias when Ollama is bound to a
// non-loopback interface (typically OLLAMA_HOST=0.0.0.0).
// integration's `host.docker.internal` alias when that host explicitly exposes
// Ollama outside Windows loopback.
export const OLLAMA_LOCALHOST = "127.0.0.1";
export const OLLAMA_HOST_DOCKER_INTERNAL = "host.docker.internal";

Expand Down
33 changes: 18 additions & 15 deletions src/lib/onboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6116,14 +6116,12 @@ async function setupNim(
if (!checkOllamaPortsOrWarn()) continue selectionLoop;
if (!ollamaRunning) {
console.log(" Starting Ollama...");
// 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.
// Keep raw Ollama loopback-only. Non-WSL containers reach it through
// the authenticated proxy on OLLAMA_PROXY_PORT.
// Shell required: backgrounding (&), env var prefix, output redirection.
const ollamaEnv = isWsl() ? "" : `OLLAMA_HOST=0.0.0.0:${OLLAMA_PORT} `;
const ollamaEnv = isWsl() ? "" : `OLLAMA_HOST=127.0.0.1:${OLLAMA_PORT} `;
runShell(`${ollamaEnv}ollama serve > /dev/null 2>&1 &`, { ignoreError: true });
sleep(2);
if (!isWsl()) printOllamaExposureWarning();
}
if (isWsl()) {
// WSL2 doesn't need the proxy — Docker can reach the host directly.
Expand Down Expand Up @@ -6242,7 +6240,7 @@ async function setupNim(
// brew install doesn't auto-start a service; launch directly.
// Shell required: backgrounding (&), env var prefix, output redirection.
console.log(" Starting Ollama...");
runShell(`OLLAMA_HOST=0.0.0.0:${OLLAMA_PORT} ollama serve > /dev/null 2>&1 &`, {
runShell(`OLLAMA_HOST=127.0.0.1:${OLLAMA_PORT} ollama serve > /dev/null 2>&1 &`, {
ignoreError: true,
});
sleep(2);
Expand All @@ -6264,21 +6262,27 @@ async function setupNim(
],
{ ignoreError: true },
).trim();
// Linux native + systemd: override OLLAMA_HOST=0.0.0.0 via a drop-in
// Linux native + systemd: force a loopback-only OLLAMA_HOST drop-in
// and let systemd own the daemon (avoids racing the installer's
// daemon with our own `ollama serve`). WSL keeps the default
// 127.0.0.1 binding (wslrelay forwards it). No-systemd / daemon
// failed to start: manual launch with the right binding.
// daemon with our own `ollama serve`). This also repairs older
// NemoClaw-created overrides that exposed raw Ollama on all interfaces.
// WSL keeps Ollama's default binding. No-systemd / daemon failed to
// start: manual launch with the loopback binding.
if (!isWsl() && hasOllamaSystemdUnit) {
console.log(" Configuring Ollama systemd override...");
const dropInBody = `[Service]\nEnvironment="OLLAMA_HOST=0.0.0.0:${OLLAMA_PORT}"\n`;
console.log(" Configuring Ollama systemd loopback override...");
const dropInBody = `[Service]\nEnvironment="OLLAMA_HOST=127.0.0.1:${OLLAMA_PORT}"\n`;
const tmpDropIn = secureTempFile("nemoclaw-ollama-override", ".conf");
fs.writeFileSync(tmpDropIn, dropInBody, { mode: 0o644 });
runShell(
const overrideResult = runShell(
`sudo install -D -m 0644 ${shellQuote(tmpDropIn)} ${shellQuote("/etc/systemd/system/ollama.service.d/override.conf")} && sudo systemctl daemon-reload && sudo systemctl restart ollama`,

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 | 🟠 Major | ⚡ Quick win

Avoid clobbering an existing override.conf.

Writing directly to /etc/systemd/system/ollama.service.d/override.conf will replace any user-managed drop-in already living at that path. That can silently discard unrelated Ollama service customizations. A NemoClaw-specific drop-in filename is safer, with legacy cleanup limited to the old NemoClaw-managed override.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/onboard.ts` at line 6277, The current install command writes
tmpDropIn to /etc/systemd/system/ollama.service.d/override.conf which can
overwrite user-managed drop-ins; change it to install to a NemoClaw-specific
filename (e.g. /etc/systemd/system/ollama.service.d/nemoclaw.conf) instead of
override.conf, update the string that builds the shell command where tmpDropIn
is used, and add a one-time cleanup step that removes the old NemoClaw-managed
override (if present) rather than unconditionally clobbering override.conf;
ensure you still run systemctl daemon-reload and systemctl restart ollama after
the install.

{ ignoreError: true },
);
cleanupTempDir(tmpDropIn, "nemoclaw-ollama-override");
if (overrideResult.error || overrideResult.status !== 0) {
console.error(" Failed to apply Ollama systemd loopback override.");
console.error(" Refusing to continue with a potentially non-loopback Ollama bind.");
process.exit(1);
}
// Retry the probe for a few seconds before giving up — systemd's
// daemon may still be binding the port; a single probe could falsely
// conclude it's down and spawn a duplicate `ollama serve`.
Expand All @@ -6290,7 +6294,7 @@ async function setupNim(
// Fall back to manual start if systemd path failed or isn't present.
if (!findReachableOllamaHost()) {
console.log(" Starting Ollama...");
const ollamaEnv = isWsl() ? "" : `OLLAMA_HOST=0.0.0.0:${OLLAMA_PORT} `;
const ollamaEnv = isWsl() ? "" : `OLLAMA_HOST=127.0.0.1:${OLLAMA_PORT} `;
runShell(`${ollamaEnv}ollama serve > /dev/null 2>&1 &`, { ignoreError: true });
sleep(2);
}
Expand All @@ -6299,7 +6303,6 @@ async function setupNim(
// WSL2 doesn't need the proxy — Docker reaches the host directly.
console.log(` ✓ Using Ollama on localhost:${OLLAMA_PORT}`);
} else {
printOllamaExposureWarning();
if (!startOllamaAuthProxy()) {
process.exit(1);
}
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/test-gpu-double-onboard.sh
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ else
fi

# If the Ollama installer started a system service, stop it so onboard
# can start Ollama with OLLAMA_HOST=0.0.0.0:11434 (required for containers).
# can restart Ollama on loopback and expose only the authenticated proxy to containers.
if curl -sf http://127.0.0.1:11434/api/tags >/dev/null 2>&1; then
info "Ollama service is running — attempting to stop for clean onboard..."
systemctl --user stop ollama 2>/dev/null || true
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/test-gpu-e2e.sh
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ else
fi

# If the Ollama installer started a system service, stop it so onboard
# can start Ollama with OLLAMA_HOST=0.0.0.0:11434 (required for containers).
# can restart Ollama on loopback and expose only the authenticated proxy to containers.
# This needs the ollama process to be owned by our user, or systemctl access.
if curl -sf http://127.0.0.1:11434/api/tags >/dev/null 2>&1; then
info "Ollama service is running — attempting to stop for clean onboard..."
Expand Down
Loading
Loading