Node-RED on Kubernetes & OpenClaw on Ubuntu 24.04 — Integration Guide

Node-RED on Kubernetes & OpenClaw on Ubuntu 24.04 — Integration Guide


Table of Contents

  1. Part 1: Installing Node-RED on Kubernetes
  2. Part 2: Installing OpenClaw on Ubuntu 24.04 LTS
  3. Part 3: Integrating Node-RED with OpenClaw

Part 1: Installing Node-RED on Kubernetes

Prerequisites

  • A running Kubernetes cluster (k3s, OpenShift, EKS, GKE, AKS, etc.)
  • kubectl configured and connected to your cluster
  • A default StorageClass available for PersistentVolumeClaims

1.1 Create a Namespace

kubectl create namespace node-red

1.2 Create a PersistentVolumeClaim

Node-RED needs persistent storage for flows, credentials, and settings.

# nodered-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nodered-data
  namespace: node-red
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 2Gi
kubectl apply -f nodered-pvc.yaml

1.3 Create the Deployment

# nodered-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: node-red
  namespace: node-red
  labels:
    app: node-red
spec:
  replicas: 1
  selector:
    matchLabels:
      app: node-red
  template:
    metadata:
      labels:
        app: node-red
    spec:
      securityContext:
        runAsUser: 1000
        fsGroup: 1000
      containers:
        - name: node-red
          image: nodered/node-red:latest
          ports:
            - containerPort: 1880
              name: http
          env:
            - name: TZ
              value: "Europe/London"
          volumeMounts:
            - name: data
              mountPath: /data
          resources:
            requests:
              memory: "128Mi"
              cpu: "100m"
            limits:
              memory: "512Mi"
              cpu: "500m"
          livenessProbe:
            httpGet:
              path: /
              port: 1880
            initialDelaySeconds: 30
            periodSeconds: 10
          readinessProbe:
            httpGet:
              path: /
              port: 1880
            initialDelaySeconds: 10
            periodSeconds: 5
      volumes:
        - name: data
          persistentVolumeClaim:
            claimName: nodered-data
kubectl apply -f nodered-deployment.yaml

1.4 Create the Service

# nodered-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: node-red
  namespace: node-red
spec:
  selector:
    app: node-red
  ports:
    - name: http
      port: 1880
      targetPort: 1880
  type: ClusterIP
kubectl apply -f nodered-service.yaml
Note: If you need external access, change type: ClusterIP to type: LoadBalancer, or configure an Ingress resource (see section 1.5).

1.5 Optional: Ingress

If you have an Ingress controller installed (e.g. nginx-ingress):

# nodered-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: node-red
  namespace: node-red
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
    - host: nodered.yourdomain.local
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: node-red
                port:
                  number: 1880
kubectl apply -f nodered-ingress.yaml

1.6 Quick Access via Port-Forward

For immediate access without Ingress:

kubectl port-forward svc/node-red 1880:1880 -n node-red

Then open http://localhost:1880 in your browser.


1.7 Verify the Deployment

kubectl get all -n node-red
kubectl logs -l app=node-red -n node-red

Node-RED ships with no authentication by default. To add a password, create a settings.js ConfigMap and mount it into /data/settings.js.

Generate a bcrypt hash for your password first:

npx -p node-red node -e "console.log(require('bcryptjs').hashSync('YourPassword', 8))"

Then create a ConfigMap with your settings and mount it — refer to the Node-RED security docs for the full adminAuth config block.


1.9 OpenShift-Specific Notes

If deploying on OpenShift, you will need an SCC allowance for the UID:

oc adm policy add-scc-to-user nonroot -z default -n node-red

Or use anyuid if nonroot is insufficient for the image:

oc adm policy add-scc-to-user anyuid -z default -n node-red

Part 2: Installing OpenClaw on Ubuntu 24.04 LTS

OpenClaw is an AI agent gateway. This section covers installation on a bare Ubuntu 24.04 host and configuring it as a persistent systemd service.

Prerequisites

  • Ubuntu 24.04 LTS
  • Root or sudo access
  • Outbound internet access to reach your AI model provider (Anthropic, OpenAI, Gemini, etc.)
  • At least one API key for a model provider

2.1 Install Node.js 24

OpenClaw requires Node 22.14+ (Node 24 recommended). The installer script handles this automatically, but you can pre-install it:

curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash -
sudo apt-get install -y nodejs
node -v   # should report v24.x.x

2.2 Install OpenClaw

The recommended approach is the official installer script, which detects your OS, installs Node if needed, installs OpenClaw, and launches onboarding:

curl -fsSL https://openclaw.ai/install.sh | bash

To install without running the interactive onboarding (useful for servers):

curl -fsSL https://openclaw.ai/install.sh | bash -s -- --no-onboard

Verify the install:

openclaw --version
openclaw doctor

2.3 Alternative: npm Install

If you manage Node yourself:

npm install -g openclaw@latest
openclaw onboard --install-daemon

If openclaw is not found after install, add the npm global bin directory to your PATH:

echo 'export PATH="$(npm prefix -g)/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc

2.4 Set Your Model Provider API Key

Export your API key before starting the gateway. Replace ANTHROPIC with your provider (OPENAI, GEMINI, OPENROUTER):

export ANTHROPIC_API_KEY="sk-ant-..."

To make this permanent, add it to your shell profile or use the systemd environment approach below.


2.5 Start the Gateway

openclaw gateway --port 18789

Check it is healthy:

openclaw gateway status
openclaw status
openclaw logs --follow

A healthy baseline shows Runtime: running and RPC probe: ok.


Install the gateway as a systemd user service:

openclaw gateway install
systemctl --user enable --now openclaw-gateway.service

To keep the service running after you log out, enable lingering:

sudo loginctl enable-linger $USER

For a system-wide service (multi-user/always-on):

sudo systemctl daemon-reload
sudo systemctl enable --now openclaw-gateway.service

Tune the service for a server environment:

sudo systemctl edit openclaw-gateway

Add the following override:

[Service]
Environment=OPENCLAW_NO_RESPAWN=1
Environment=NODE_COMPILE_CACHE=/var/tmp/openclaw-compile-cache
Environment=ANTHROPIC_API_KEY=sk-ant-YOUR_KEY_HERE
Restart=always
RestartSec=2
TimeoutStartSec=90

Reload and restart:

sudo systemctl daemon-reload
sudo systemctl restart openclaw-gateway

2.7 Startup Tuning (Optional)

For faster repeated startup times, enable Node's module compile cache:

grep -q 'NODE_COMPILE_CACHE' ~/.bashrc || cat >> ~/.bashrc <<'EOF'
export NODE_COMPILE_CACHE=/var/tmp/openclaw-compile-cache
mkdir -p /var/tmp/openclaw-compile-cache
export OPENCLAW_NO_RESPAWN=1
EOF
source ~/.bashrc

2.8 Verify the Install

openclaw gateway status
openclaw channels status --probe
openclaw health

Access the Control UI at http://localhost:18789 (gateway binds to loopback by default).


2.9 Remote Access via SSH Tunnel

The gateway binds to loopback by default. To access it from another machine securely:

ssh -N -L 18789:127.0.0.1:18789 user@your-ubuntu-host

Then connect your browser to http://127.0.0.1:18789.

For persistent remote access, Tailscale Serve is the recommended approach — see the OpenClaw Tailscale docs.


Part 3: Integrating Node-RED with OpenClaw

OpenClaw exposes an OpenAI-compatible HTTP API on its gateway port (18789 by default). Node-RED integrates with it via standard HTTP request nodes — no special plugin required.


3.1 Architecture Overview

[Node-RED Flow]
      |
      | HTTP POST (JSON)
      v
[OpenClaw Gateway :18789]
      |
      | Routes to provider
      v
[AI Model (Anthropic / OpenAI / etc.)]
      |
      v
[Response back to Node-RED]

Node-RED sends a prompt to OpenClaw's OpenAI-compatible /v1/chat/completions endpoint. OpenClaw handles routing to whichever model provider you have configured.


3.2 Get Your Gateway Token

The gateway requires an auth token. Retrieve it:

# If running locally on Ubuntu:
openclaw gateway status --json | jq '.auth'

# Or check your openclaw.json config:
cat ~/.openclaw/openclaw.json | grep token

If you set OPENCLAW_GATEWAY_TOKEN as an environment variable, use that value.


3.3 Node-RED: Basic Prompt Flow

This flow takes a message payload, sends it to OpenClaw, and returns the AI response.

In Node-RED, create the following flow:

[inject] → [function: build request] → [http request] → [function: parse response] → [debug]

Function node: "Build Request"

// Set your OpenClaw gateway URL and token
const OPENCLAW_URL = "http://<openclaw-host>:18789/v1/chat/completions";
const OPENCLAW_TOKEN = "<your-gateway-token>";

msg.url = OPENCLAW_URL;
msg.method = "POST";
msg.headers = {
    "Content-Type": "application/json",
    "Authorization": "Bearer " + OPENCLAW_TOKEN
};
msg.payload = {
    model: "claude-sonnet-4-20250514",  // or whichever model you have configured
    messages: [
        {
            role: "user",
            content: msg.payload  // expects a string input from upstream
        }
    ],
    max_tokens: 1000
};
return msg;

HTTP Request node settings:

  • Method: POST
  • URL: leave blank (set by function node via msg.url)
  • Return: a parsed JSON object
  • Enable "Use msg.url" and "Use msg.headers"

Function node: "Parse Response"

// Extract the assistant's reply from the OpenAI-compatible response
if (msg.payload && msg.payload.choices && msg.payload.choices.length > 0) {
    msg.payload = msg.payload.choices[0].message.content;
} else {
    msg.payload = "Error: no response from OpenClaw";
}
return msg;

3.4 Node-RED: Reusable OpenClaw Subflow

For production use, create a subflow so any flow in your workspace can call OpenClaw without duplicating config.

Create a subflow with:

  • Input: msg.prompt (string)
  • Output: msg.response (string)

Subflow function node:

const OPENCLAW_URL = env.get("OPENCLAW_URL") || "http://localhost:18789/v1/chat/completions";
const OPENCLAW_TOKEN = env.get("OPENCLAW_TOKEN");

msg.url = OPENCLAW_URL;
msg.method = "POST";
msg.headers = {
    "Content-Type": "application/json",
    "Authorization": "Bearer " + OPENCLAW_TOKEN
};
msg.payload = {
    model: env.get("OPENCLAW_MODEL") || "claude-sonnet-4-20250514",
    messages: [{ role: "user", content: msg.prompt }],
    max_tokens: parseInt(env.get("OPENCLAW_MAX_TOKENS") || "1000")
};
return msg;

Set the environment variables in the subflow's properties panel:

Variable Example Value
OPENCLAW_URL http://192.168.1.x:18789/v1/chat/completions
OPENCLAW_TOKEN your-gateway-token
OPENCLAW_MODEL claude-sonnet-4-20250514
OPENCLAW_MAX_TOKENS 1000

3.5 Connecting Node-RED (in Kubernetes) to OpenClaw (on Ubuntu)

When Node-RED runs in Kubernetes and OpenClaw runs on a separate Ubuntu host, you have a few connectivity options:

Option A — Direct IP (simplest)

Use the Ubuntu host's LAN IP in Node-RED's HTTP request node:

http://192.168.1.x:18789/v1/chat/completions

Note: the OpenClaw gateway binds to loopback by default. You need to change the bind mode to allow external connections. Edit ~/.openclaw/openclaw.json:

{
  "gateway": {
    "bind": "lan",
    "auth": {
      "token": "your-strong-token-here"
    }
  }
}

Then restart the gateway:

openclaw gateway restart

Option B — Tailscale (recommended for security)

If both your K8s nodes and Ubuntu host are on Tailscale, use the Tailscale IP:

http://100.x.x.x:18789/v1/chat/completions

Set the bind to tailnet in openclaw.json and keep auth enabled. This keeps the gateway off your LAN entirely.

Option C — Kubernetes ExternalName Service

For a clean in-cluster DNS approach, create an ExternalName service in the node-red namespace pointing at your Ubuntu host:

# openclaw-external-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: openclaw
  namespace: node-red
spec:
  type: ExternalName
  externalName: your-ubuntu-host.home  # or IP
  ports:
    - port: 18789
kubectl apply -f openclaw-external-svc.yaml

Node-RED can then reference OpenClaw via the in-cluster DNS name http://openclaw.node-red.svc.cluster.local:18789.


3.6 Storing the Gateway Token Securely in Kubernetes

Rather than hardcoding the token in your Node-RED flows, store it as a Kubernetes Secret and mount it as an environment variable:

kubectl create secret generic openclaw-token \
  --from-literal=OPENCLAW_TOKEN=your-gateway-token \
  -n node-red

Add to your Node-RED deployment spec under spec.template.spec.containers[0].env:

- name: OPENCLAW_TOKEN
  valueFrom:
    secretKeyRef:
      name: openclaw-token
      key: OPENCLAW_TOKEN

Then reference it in your Node-RED function nodes via env.get("OPENCLAW_TOKEN") (using the subflow approach from section 3.4).


3.7 Testing End-to-End

  1. Deploy Node-RED and verify it is accessible at http://localhost:1880
  2. Verify OpenClaw is healthy: openclaw gateway status
  3. In Node-RED, inject a test string (e.g. "Hello, what is 2+2?") into your flow
  4. Check the debug panel for the AI response
  5. Check OpenClaw logs for the request: openclaw logs --follow

3.8 Example Use Cases

  • Automated summaries: Feed MQTT sensor data into Node-RED → OpenClaw → summarise and push to a dashboard or Slack channel
  • Natural language commands: Translate plain-English instructions from a UI into structured actions via OpenClaw, then execute them with Node-RED automation nodes
  • Alert enrichment: Receive a webhook alert, send it to OpenClaw for analysis and suggested remediation, then route the enriched alert to your ticketing system
  • Scheduled AI reports: Trigger a cron-style inject node on a schedule, gather data, pass to OpenClaw for a written summary, and email or post it

Troubleshooting Reference

Symptom Likely Cause Fix
Node-RED pod CrashLoopBackOff PVC not bound / permissions Check StorageClass; add SCC on OpenShift
ECONNREFUSED from Node-RED to OpenClaw Gateway bound to loopback Change gateway.bind to lan or tailnet
unauthorized from OpenClaw Token mismatch Check OPENCLAW_TOKEN env var matches openclaw.json
openclaw not found after install npm global bin not in PATH export PATH="$(npm prefix -g)/bin:$PATH"
Gateway won't bind non-loopback without auth Security guard Set gateway.auth.token before changing bind mode
Node-RED flows lost after pod restart PVC not mounted Verify PVC is bound and mounted to /data