$npx -y skills add jezweb/claude-skills --skill nemoclaw-setupInstall and configure NVIDIA NemoClaw (sandboxed OpenClaw agent platform) on Linux. Handles cloudflared tunnels, Docker cgroup fixes, OpenShell, sandbox creation, remote access via Cloudflare Tunnel, and known bug workarounds. Use whenever the user mentions installing NemoClaw, s
| 1 | # NemoClaw Setup |
| 2 | |
| 3 | Install NVIDIA NemoClaw — a sandboxed AI agent platform built on OpenClaw with Landlock + seccomp + network namespace isolation. Runs inside Docker via k3s (OpenShell). |
| 4 | |
| 5 | ## What You Get |
| 6 | |
| 7 | - Sandboxed AI agent with web UI and terminal CLI |
| 8 | - Powered by NVIDIA Nemotron models (cloud or local) |
| 9 | - Network-policy-controlled access to external services |
| 10 | - Optional remote access via Cloudflare Tunnel |
| 11 | |
| 12 | ## Prerequisites |
| 13 | |
| 14 | | Requirement | Check | Install | |
| 15 | |-------------|-------|---------| |
| 16 | | Linux (Ubuntu 22.04+) | `uname -a` | — | |
| 17 | | Docker | `docker ps` | `sudo apt install docker.io` | |
| 18 | | Node.js 20+ (22 recommended) | `node --version` | `nvm install 22` | |
| 19 | | NVIDIA GPU (optional but recommended) | `nvidia-smi` | — | |
| 20 | | NVIDIA API key | — | https://build.nvidia.com/settings/api-keys | |
| 21 | |
| 22 | ## Workflow |
| 23 | |
| 24 | ### Step 1: Pre-flight Checks |
| 25 | |
| 26 | ```bash |
| 27 | # Check Docker |
| 28 | docker ps 2>/dev/null || echo "Docker not running or no access" |
| 29 | |
| 30 | # Check Node.js |
| 31 | node --version |
| 32 | |
| 33 | # Check if already installed |
| 34 | which nemoclaw && nemoclaw --version |
| 35 | which openshell && openshell --version |
| 36 | ``` |
| 37 | |
| 38 | If `nemoclaw` is already installed, skip to Step 4. |
| 39 | |
| 40 | ### Step 2: Install NemoClaw |
| 41 | |
| 42 | ```bash |
| 43 | curl -fsSL https://nvidia.com/nemoclaw.sh | bash |
| 44 | ``` |
| 45 | |
| 46 | This installs NemoClaw and OpenClaw via npm globally (to `~/.npm-global/bin/`). |
| 47 | |
| 48 | **If the installer can't find Node.js**, install it first: |
| 49 | ```bash |
| 50 | curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - |
| 51 | sudo apt install -y nodejs |
| 52 | ``` |
| 53 | |
| 54 | ### Step 3: Install OpenShell |
| 55 | |
| 56 | ```bash |
| 57 | curl -LsSf https://raw.githubusercontent.com/NVIDIA/OpenShell/main/install.sh | sh |
| 58 | ``` |
| 59 | |
| 60 | Installs to `~/.local/bin/openshell`. |
| 61 | |
| 62 | ### Step 4: Fix Docker Permissions and cgroup |
| 63 | |
| 64 | **Docker group** — the user must be in the `docker` group: |
| 65 | ```bash |
| 66 | sudo usermod -aG docker $USER |
| 67 | newgrp docker |
| 68 | # or log out and back in |
| 69 | ``` |
| 70 | |
| 71 | **cgroup v2 fix** — required for k3s inside Docker: |
| 72 | ```bash |
| 73 | # Check if needed |
| 74 | grep cgroup2 /proc/filesystems && echo "cgroup v2 detected — fix needed" |
| 75 | |
| 76 | # Apply fix (needs sudo) |
| 77 | sudo $HOME/.npm-global/bin/nemoclaw setup-spark |
| 78 | ``` |
| 79 | |
| 80 | This adds `"default-cgroupns-mode": "host"` to `/etc/docker/daemon.json` and restarts Docker. |
| 81 | |
| 82 | **IMPORTANT**: The `nemoclaw setup-spark` command also asks for an NVIDIA API key. Have it ready (starts with `nvapi-`). Get one at https://build.nvidia.com/settings/api-keys. |
| 83 | |
| 84 | ### Step 5: Run Onboarding |
| 85 | |
| 86 | ```bash |
| 87 | PATH=$HOME/.npm-global/bin:$HOME/.local/bin:$PATH nemoclaw onboard |
| 88 | ``` |
| 89 | |
| 90 | The interactive wizard will: |
| 91 | 1. Check Docker and OpenShell |
| 92 | 2. Start the OpenShell gateway (k3s in Docker) |
| 93 | 3. Ask for a sandbox name — use `claw` or any name |
| 94 | 4. Configure the NVIDIA API key |
| 95 | 5. Set up inference (Nemotron 3 Super 120B via cloud API) |
| 96 | 6. Launch OpenClaw inside the sandbox |
| 97 | 7. Apply network policy presets — select the ones you need |
| 98 | |
| 99 | **Common port conflict**: If port 8080 is in use, find and kill the process: |
| 100 | ```bash |
| 101 | fuser -k 8080/tcp |
| 102 | ``` |
| 103 | |
| 104 | ### Step 6: Verify |
| 105 | |
| 106 | ```bash |
| 107 | # Check sandbox is running |
| 108 | PATH=$HOME/.npm-global/bin:$HOME/.local/bin:$PATH nemoclaw claw status |
| 109 | |
| 110 | # Connect via terminal |
| 111 | PATH=$HOME/.npm-global/bin:$HOME/.local/bin:$PATH nemoclaw claw connect |
| 112 | ``` |
| 113 | |
| 114 | ### Step 7: Set Up Web UI Access |
| 115 | |
| 116 | The web UI runs inside the sandbox and needs a port forward: |
| 117 | |
| 118 | ```bash |
| 119 | PATH=$HOME/.npm-global/bin:$HOME/.local/bin:$PATH openshell forward start 18789 claw |
| 120 | ``` |
| 121 | |
| 122 | Then open: `http://127.0.0.1:18789/` |
| 123 | |
| 124 | **Known bug (OpenClaw ≤ v2026.3.11)**: "device identity required" error. Workaround — append the gateway token to the URL: |
| 125 | |
| 126 | ```bash |
| 127 | # Get the token |
| 128 | ssh -F /tmp/nemoclaw-ssh-config openshell-claw \ |
| 129 | "python3 -c \"import json; print(json.load(open('/sandbox/.openclaw/openclaw.json'))['gateway']['auth']['token'])\"" |
| 130 | ``` |
| 131 | |
| 132 | Then visit: `http://127.0.0.1:18789/#token=<gateway-token>` |
| 133 | |
| 134 | **Fix**: Update to OpenClaw v2026.3.12+ (see Updating section below). |
| 135 | |
| 136 | ### Step 8: Make the Port Forward Persistent |
| 137 | |
| 138 | Create a health-checked keepalive script: |
| 139 | |
| 140 | ```bash |
| 141 | cat > ~/.local/bin/nemoclaw-keepalive.sh << 'KEEPALIVE' |
| 142 | #!/bin/bash |
| 143 | export PATH="$HOME/.npm-global/bin:$HOME/.local/bin:/usr/local/bin:/usr/bin:/bin" |
| 144 | cleanup() { kill %1 2>/dev/null; exit 0; } |
| 145 | trap cleanup SIGTERM SIGINT |
| 146 | while true; do |
| 147 | fuser -k 18789/tcp 2>/dev/null; sleep 1 |
| 148 | openshell forward start 18789 claw & |
| 149 | FORWARD_PID=$!; sleep 3 |
| 150 | while kill -0 $FORWARD_PID 2>/dev/null; do |
| 151 | if ! curl -sf -o /dev/null --connect-timeout 3 http://127.0.0.1:18789/ 2>/dev/null; then |
| 152 | echo "$(date): Health check failed, restarting..." |
| 153 | kill $FORWARD_PID 2>/dev/null; wait $FORWARD_PID 2>/dev/null; break |