Skip to content

fix(install): check ports 8080 and 18789 are free before starting gat…#329

Closed
webdevpraveen wants to merge 1 commit into
NVIDIA:mainfrom
webdevpraveen:fix/preflight-port-conflict-check
Closed

fix(install): check ports 8080 and 18789 are free before starting gat…#329
webdevpraveen wants to merge 1 commit into
NVIDIA:mainfrom
webdevpraveen:fix/preflight-port-conflict-check

Conversation

@webdevpraveen

@webdevpraveen webdevpraveen commented Mar 18, 2026

Copy link
Copy Markdown
Contributor

Fixes #51

install.sh starts the OpenShell gateway on port 8080 and the OpenClaw dashboard on port 18789 without checking whether those ports are already in use. Users with existing Docker containers, web servers, or other services on those ports get a cryptic startup failure:

Error: listen tcp 0.0.0.0:8080: bind: address already in use

This change adds a check_required_ports() preflight function that runs before any gateway or sandbox setup:

  • Detects conflicts using ss (iproute2) with netstat fallback
  • Prints a clear, named error identifying the conflicting port
  • Suggests NEMOCLAW_GATEWAY_PORT / NEMOCLAW_DASHBOARD_PORT env vars so users can override without stopping existing services
  • Degrades gracefully when neither ss nor netstat is available

Summary by CodeRabbit

  • Chores
    • Enhanced the installation process with preflight port-availability validation. The installer now verifies that required gateway and dashboard ports are available before beginning installation, preventing failures from port conflicts. Clear error messages display if ports are unavailable. Both ports are customizable via environment variables with sensible defaults.

…eway

Fixes NVIDIA#51

install.sh starts the OpenShell gateway on port 8080 and the OpenClaw
dashboard on port 18789 without checking whether those ports are
already in use. Users with existing Docker containers, web servers,
or other services on those ports get a cryptic startup failure:

  Error: listen tcp 0.0.0.0:8080: bind: address already in use

This change adds a check_required_ports() preflight function that
runs before any gateway or sandbox setup:

- Detects conflicts using ss (iproute2) with netstat fallback
- Prints a clear, named error identifying the conflicting port
- Suggests NEMOCLAW_GATEWAY_PORT / NEMOCLAW_DASHBOARD_PORT env vars
  so users can override without stopping existing services
- Degrades gracefully when neither ss nor netstat is available

Signed-off-by: webdevpraveen <pr4veensingh@proton.me>
@coderabbitai

coderabbitai Bot commented Mar 18, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

The installation script now includes a preflight port-availability check that validates both the gateway and dashboard ports are free before proceeding with Node.js installation. Port detection uses ss or netstat, with defaults overridable via environment variables, and the process exits with errors if ports are already in use.

Changes

Cohort / File(s) Summary
Port Preflight Validation
install.sh
Added _port_in_use() function to detect port usage via ss/netstat, and check_required_ports() to validate gateway and dashboard ports are available before installation. Integrated port-check into the Node.js installation path as a prerequisite step. Supports environment-variable port overrides with sensible defaults.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 A rabbit checks twice before it hops,
Peering at ports, confirming no blocks,
Before Docker's chaos and network collides—
A preflight glance where safety resides! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely identifies the main change: adding a port availability check for ports 8080 and 18789 before installation.
Linked Issues check ✅ Passed The PR implementation fulfills issue #51 requirements by validating port availability (8080 and 18789) before installation, providing clear error messages and environment variable overrides for port configuration.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the preflight port check requirement from issue #51; no unrelated modifications detected in the changeset.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

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

Tip

You can make CodeRabbit's review stricter and more nitpicky using the `assertive` profile, if that's what you prefer.

Change the reviews.profile setting to assertive to make CodeRabbit's nitpick more issues in your PRs.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 2

🧹 Nitpick comments (1)
install.sh (1)

98-98: Use info helper for consistency.

Line 98 uses a raw echo "[INFO]..." format while the rest of the script uses the info() helper (line 12) which includes color formatting.

♻️ Proposed fix
-  echo "[INFO]  Ports ${NEMOCLAW_GATEWAY_PORT} (gateway) and ${NEMOCLAW_DASHBOARD_PORT} (dashboard) are free."
+  info "Ports ${NEMOCLAW_GATEWAY_PORT} (gateway) and ${NEMOCLAW_DASHBOARD_PORT} (dashboard) are free."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@install.sh` at line 98, Replace the raw echo statement that logs ports being
free with the script's info() helper to maintain consistent formatting and
color; locate the line printing "[INFO]  Ports ${NEMOCLAW_GATEWAY_PORT}
(gateway) and ${NEMOCLAW_DASHBOARD_PORT} (dashboard) are free." and call info
with the same message string so it uses the existing info() function's output
style.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@install.sh`:
- Around line 141-143: The call to check_required_ports is incorrectly nested
inside install_nodejs’s sha256sum branch; move the check out of install_nodejs
and invoke check_required_ports at the start of main() before any installation
logic so port checks run regardless of Node.js presence or which checksum tool
(sha256sum/shasum) is available; remove the misplaced check_required_ports
invocation inside the command_exists sha256sum conditional (and ensure no
duplicate calls remain).
- Around line 70-80: The _port_in_use function uses netstat with the invalid -H
flag and a brittle grep pattern; change the netstat branch to call netstat -tln
(no -H), skip header rows if present, and extract the port robustly (e.g., use
awk to split the local-address column on ":" and take the last field or use a
regex to capture the trailing port) so IPv4, IPv6 (::) and formats with brackets
are handled; keep the ss branch as-is (ss -tlnH), replace the grep ":${p}$"
check with a comparison against the extracted port (or grep -E "(:|\\])${p}$" if
you prefer) so _port_in_use reliably returns 0 when the port is in use across ss
and netstat.

---

Nitpick comments:
In `@install.sh`:
- Line 98: Replace the raw echo statement that logs ports being free with the
script's info() helper to maintain consistent formatting and color; locate the
line printing "[INFO]  Ports ${NEMOCLAW_GATEWAY_PORT} (gateway) and
${NEMOCLAW_DASHBOARD_PORT} (dashboard) are free." and call info with the same
message string so it uses the existing info() function's output style.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2613847c-2cfe-4fa9-a7a5-ea11d87e5c48

📥 Commits

Reviewing files that changed from the base of the PR and between 1e23347 and 1956973.

📒 Files selected for processing (1)
  • install.sh

Comment thread install.sh
Comment on lines +70 to +80
_port_in_use() {
local p="$1"
if command -v ss &>/dev/null; then
ss -tlnH 2>/dev/null | awk '{print $4}' | grep -q ":${p}$"
return $?
elif command -v netstat &>/dev/null; then
netstat -tlnH 2>/dev/null | awk '{print $4}' | grep -q ":${p}$"
return $?
fi
return 1
}

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify netstat flag support and output format differences

echo "=== Checking ss availability and -H flag ==="
if command -v ss &>/dev/null; then
  echo "ss is available"
  ss -tlnH 2>&1 | head -3
else
  echo "ss not found"
fi

echo ""
echo "=== Checking netstat -H flag (expected to fail on most systems) ==="
if command -v netstat &>/dev/null; then
  echo "netstat is available"
  netstat -tlnH 2>&1 | head -3
  echo ""
  echo "=== netstat without -H for comparison ==="
  netstat -tln 2>&1 | head -5
else
  echo "netstat not found"
fi

Repository: NVIDIA/NemoClaw

Length of output: 203


🏁 Script executed:

# Find and read the install.sh file
find . -name "install.sh" -type f | head -5

Repository: NVIDIA/NemoClaw

Length of output: 92


🏁 Script executed:

# Search for netstat documentation or usage patterns in the codebase
rg "netstat" --type sh -B 2 -A 2

Repository: NVIDIA/NemoClaw

Length of output: 332


🌐 Web query:

netstat -H flag compatibility unix systems

💡 Result:

netstat -H is not a portable/standard netstat option across Unix-like systems (Linux net-tools netstat doesn’t document -H, and BSD netstat uses -h for other purposes, not -H). (mankier.com)

What is widely compatible is H as a routing-table output flag (not a command-line option):

  • On Solaris, when you run netstat -rn, the routing table “Flags” column can include H meaning “route is to a host and not a network”. (docs.oracle.com)
  • On FreeBSD, the routing table flags include H (RTF_HOST) meaning “Host entry (net otherwise)”. (man.freebsd.org)

So if you’re trying to detect “host routes” portably, do something like:

  • netstat -rn and then interpret the Flags column; don’t rely on a -H option. (docs.oracle.com)

Citations:


🏁 Script executed:

# Read the install.sh file to confirm context and line numbers
head -100 install.sh | tail -40

Repository: NVIDIA/NemoClaw

Length of output: 1622


🏁 Script executed:

# Check for any IPv6 related patterns or tests in the codebase
rg -i "ipv6|\[::\]|::1" --type sh -B 2 -A 2

Repository: NVIDIA/NemoClaw

Length of output: 305


netstat does not support the -H flag on most Unix-like systems, causing silent failures on BSD, macOS, and traditional Linux installations.

The -H (no header) flag is specific to ss from iproute2. Traditional netstat on BSD, macOS, and systems using net-tools does not recognize -H and will error or ignore it. When netstat -tlnH fails, the fallback returns 1 (port free), which silently misses port conflicts during deployment.

Additionally, the grep pattern :${p}$ may not match all IPv6 listener formats consistently.

🐛 Proposed fix
 _port_in_use() {
   local p="$1"
   if command -v ss &>/dev/null; then
     ss -tlnH 2>/dev/null | awk '{print $4}' | grep -q ":${p}$"
     return $?
   elif command -v netstat &>/dev/null; then
-    netstat -tlnH 2>/dev/null | awk '{print $4}' | grep -q ":${p}$"
+    # netstat output varies by OS; skip header with tail, match port at end
+    netstat -tln 2>/dev/null | tail -n +3 | awk '{print $4}' | grep -qE "[:.]${p}$"
     return $?
   fi
   return 1
 }
📝 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
_port_in_use() {
local p="$1"
if command -v ss &>/dev/null; then
ss -tlnH 2>/dev/null | awk '{print $4}' | grep -q ":${p}$"
return $?
elif command -v netstat &>/dev/null; then
netstat -tlnH 2>/dev/null | awk '{print $4}' | grep -q ":${p}$"
return $?
fi
return 1
}
_port_in_use() {
local p="$1"
if command -v ss &>/dev/null; then
ss -tlnH 2>/dev/null | awk '{print $4}' | grep -q ":${p}$"
return $?
elif command -v netstat &>/dev/null; then
# netstat lacks -H flag; skip single header line
netstat -tln 2>/dev/null | tail -n +2 | awk '{print $4}' | grep -qE ":${p}$"
return $?
fi
return 1
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@install.sh` around lines 70 - 80, The _port_in_use function uses netstat with
the invalid -H flag and a brittle grep pattern; change the netstat branch to
call netstat -tln (no -H), skip header rows if present, and extract the port
robustly (e.g., use awk to split the local-address column on ":" and take the
last field or use a regex to capture the trailing port) so IPv4, IPv6 (::) and
formats with brackets are handled; keep the ss branch as-is (ss -tlnH), replace
the grep ":${p}$" check with a comparison against the extracted port (or grep -E
"(:|\\])${p}$" if you prefer) so _port_in_use reliably returns 0 when the port
is in use across ss and netstat.

Comment thread install.sh
Comment on lines 141 to 143
if command_exists sha256sum; then
check_required_ports
actual_hash="$(sha256sum "$nvm_tmp" | awk '{print $1}')"

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 | 🔴 Critical

Critical: check_required_ports is incorrectly placed inside conditional hash-check logic.

The port check is nested inside the if command_exists sha256sum branch within install_nodejs(). This means:

  1. Skipped if Node.js exists: install_nodejs() returns early at line 129 if node is found, so ports are never checked for existing Node.js installations.
  2. Skipped if sha256sum unavailable: The check only runs in the sha256sum branch, not the shasum fallback (lines 144-145) or the "no tool" fallback (lines 147-148).
  3. Wrong scope: Port availability is a preflight concern independent of Node.js installation.

Move check_required_ports to the beginning of main() before any installation steps.

🐛 Proposed fix

Remove the misplaced call from line 142:

   if command_exists sha256sum; then
-check_required_ports
     actual_hash="$(sha256sum "$nvm_tmp" | awk '{print $1}')"

Add the port check at the start of main():

 main() {
   info "=== NemoClaw Installer ==="
+
+  check_required_ports

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

In `@install.sh` around lines 141 - 143, The call to check_required_ports is
incorrectly nested inside install_nodejs’s sha256sum branch; move the check out
of install_nodejs and invoke check_required_ports at the start of main() before
any installation logic so port checks run regardless of Node.js presence or
which checksum tool (sha256sum/shasum) is available; remove the misplaced
check_required_ports invocation inside the command_exists sha256sum conditional
(and ensure no duplicate calls remain).

@ericksoa

Copy link
Copy Markdown
Contributor

Thanks for the contribution! We're going with a different approach for this one that integrates the port check into the Node.js preflight step rather than install.sh. Closing in favor of #251.

@ericksoa ericksoa closed this Mar 18, 2026
@webdevpraveen webdevpraveen deleted the fix/preflight-port-conflict-check branch March 18, 2026 21:33
@webdevpraveen webdevpraveen restored the fix/preflight-port-conflict-check branch March 18, 2026 21:33
mafueee pushed a commit to mafueee/NemoClaw that referenced this pull request Mar 28, 2026
…IA#329)

Docker Desktop 29.x defaults to private cgroupns which prevents k3s
kubelet from accessing cgroup v2 controllers (cpu, cpuset, memory,
pids, hugetlb). This causes ContainerManager to fail during startup.

Explicitly set cgroupns_mode to host, which is backwards compatible
with all Docker versions and matches what k3s-in-Docker tooling
(k3d) requires.
@wscurran wscurran added the bug-fix PR fixes a bug or regression label Jun 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug-fix PR fixes a bug or regression

Projects

None yet

Development

Successfully merging this pull request may close these issues.

./install.sh assumes port 8080 isn't already in use

3 participants