{
  "slug": "openclaw-gateway",
  "url": "/process/openclaw-gateway/",
  "name": "openclaw-gateway",
  "kind": "ai-agent",
  "package": "openclaw (npm); OpenClaw 2026.10.5 at the time of writing",
  "binary": "node — the gateway sets its process title to openclaw-gateway (ps shows the comm field truncated to openclaw-gatewa); its helper workers show as node MainThread running dist/process/spawn-broker/worker.js and dist/infra/sqlite-readonly-location.worker.js",
  "config": [
    "~/.openclaw/openclaw.json (JSON5)",
    "~/.openclaw/ (state, cache, media, credentials)",
    "/tmp/openclaw/openclaw-YYYY-MM-DD.log (file logs, as reported by openclaw gateway status)"
  ],
  "summary": "The OpenClaw Gateway: a Node.js daemon that serves the Control UI, the WebSocket and HTTP API (/v1/*, /tools/invoke, /api/channels/*) on one port, 18789 by default, and runs the agent's tools, terminal and browser control behind it.",
  "symptoms": [
    "0.0.0.0:18789 in ss -tlnp: gateway.bind is lan or custom, so every host that can reach the machine can reach the Control UI and the tool-invocation API",
    "a node process with a gigabyte of RSS plus two or three node workers: the gateway and its spawn broker and sqlite workers, normal while channels and browser control are enabled",
    "the gateway refuses to start: openclaw.json lacks gateway.mode = \"local\", or no authentication is configured (auth is required by default)"
  ],
  "safe_to_kill": "restart-instead",
  "safe_to_kill_note": "openclaw gateway restart is the clean way, and SIGUSR2 triggers an in-process restart; kill -TERM works but drops live chat sessions and any tool run in flight. If it is exposed to the network, fixing gateway.bind and the auth mode matters more than stopping it, because the service will come back with the same settings.",
  "what_it_can_do": "Whatever its tools allow, as the user that runs it: a terminal (gateway.terminal.enabled defaults to true), browser control, elevated tools, CLI agents (gateway.cliAgents.enabled defaults to true), file uploads (gateway.uploads.enabled defaults to true), and every configured chat channel. Authentication modes are token (recommended), password, trusted-proxy and none; none is an explicit opt-in, and without a valid auth path the gateway refuses WebSocket connections. gateway.bind is loopback by default; lan (0.0.0.0), tailnet, auto and custom widen exposure, and the docs pair them with auth and a real firewall. Port precedence: --port, then OPENCLAW_GATEWAY_PORT, then gateway.port, then 18789. Changes to auth mode and TLS need a restart; most other gateway.* changes hot-reload.",
  "diagnose": [
    {
      "cmd": "ss -tlnp | grep 18789",
      "why": "127.0.0.1:18789 and [::1]:18789 is the loopback default; 0.0.0.0 or * means the Control UI, WebSocket API and /tools/invoke face the network"
    },
    {
      "cmd": "openclaw gateway status",
      "why": "prints bind mode, port, which config file the CLI and the service use, the service state and the log file path in one screen"
    },
    {
      "cmd": "openclaw security audit",
      "why": "built-in check for the usual foot-guns: insecure flags, short or blank tokens, state directory readable by others, missing trusted proxies; --deep probes more"
    },
    {
      "cmd": "ps -eo pid,user,rss,etime,comm,args | grep -E '[o]penclaw'",
      "why": "who runs it and how big it is; the comm field reads openclaw-gatewa for the gateway and MainThread for its node workers"
    },
    {
      "cmd": "find ~/.openclaw -maxdepth 1 -perm /077 -printf '%m %p\\n'",
      "why": "the state directory holds credentials and session data; the audit expects it at mode 700 and flags 755"
    }
  ],
  "fixes": [],
  "harden": [
    {
      "title": "Stay on loopback and reach it through something that authenticates you.",
      "note": "Keep gateway.bind = \"loopback\". For remote access the docs recommend Tailscale Serve, which keeps the gateway on loopback; gateway.remote.transport defaults to ssh for the CLI's own remote mode. Never publish 18789 unauthenticated on 0.0.0.0, and in Docker enforce rules in the DOCKER-USER chain, since published ports bypass the host's INPUT rules."
    },
    {
      "title": "Use a real token and keep it off the command line.",
      "cmd": "openclaw doctor --generate-gateway-token",
      "note": "Sets a persistent token; the audit warns on tokens shorter than 24 characters and treats blank ones as critical. openclaw gateway auth-token --show reveals it only on an interactive terminal and refuses piped output, which is the right instinct: do not paste it into scripts, use OPENCLAW_GATEWAY_TOKEN from a protected environment instead."
    },
    {
      "title": "Lock the state directory.",
      "cmd": "chmod 700 ~/.openclaw",
      "note": "openclaw.json is written mode 600, but a 755 directory still lets other local users list what is there. Run the gateway under its own Unix account on a shared box."
    },
    {
      "title": "Turn off the surfaces you do not use.",
      "note": "gateway.terminal.enabled, gateway.uploads.enabled and gateway.cliAgents.enabled all default to true; the HTTP chat-completions endpoint and the admin HTTP RPC plugin default to off, keep them that way unless something needs them. The hosted widget pages under /__openclaw__/canvas carry agent-authored HTML and JavaScript; the docs say to treat them as untrusted."
    },
    {
      "title": "Behind a reverse proxy, name the proxy.",
      "note": "Set gateway.trustedProxies to the proxy addresses; otherwise the audit warns that forwarded-for headers are not trusted and the gateway cannot tell a local client from a remote one."
    }
  ],
  "impostors": [
    {
      "cmd": "p=$(pgrep -f '^openclaw-gateway' | head -1); readlink /proc/$p/exe; tr '\\0' ' ' < /proc/$p/cmdline; echo",
      "why": "a real gateway's executable is your node binary and its command line is the bare title openclaw-gateway; a static binary called openclaw-gateway, or node running a script outside your npm prefix, is not this program"
    },
    {
      "cmd": "openclaw --version",
      "why": "prints the release (OpenClaw 2026.10.5 and a commit hash when this was written)"
    }
  ],
  "listens": [
    {
      "port": "18789/tcp",
      "default_bind": "127.0.0.1 and ::1 (gateway.bind: loopback)",
      "note": "WebSocket, HTTP API and Control UI share this port; lan binds 0.0.0.0"
    }
  ],
  "distros": {
    "any": "npm install -g openclaw; openclaw gateway install registers a systemd user service, launchd agent or scheduled task, openclaw gateway run starts it in the foreground. Config is JSON5 at ~/.openclaw/openclaw.json and must contain gateway.mode = \"local\" for the gateway to start."
  },
  "applies_to": "OpenClaw 2026.10.x (the 2.0 line). Keys, defaults and commands taken from docs.openclaw.ai on 2026-10-20 and checked on a fresh install; this project changes monthly, see the verified date.",
  "see_also": [
    "ollama",
    "claude",
    "codex",
    "gemini"
  ],
  "sources": [
    {
      "title": "OpenClaw docs — Network exposure",
      "url": "https://docs.openclaw.ai/gateway/security/network-exposure",
      "fetched": "2026-10-20T00:00:00.000Z"
    },
    {
      "title": "OpenClaw docs — Gateway configuration (gateway.bind, gateway.port, gateway.auth)",
      "url": "https://docs.openclaw.ai/gateway/config-gateway",
      "fetched": "2026-10-20T00:00:00.000Z"
    },
    {
      "title": "OpenClaw docs — Run the Gateway",
      "url": "https://docs.openclaw.ai/cli/gateway/running",
      "fetched": "2026-10-20T00:00:00.000Z"
    }
  ],
  "tested_on": "Ubuntu 26.04 · OpenClaw 2026.10.5 via npm with a minimal token config (bind, ports, process title, gateway status, security audit)",
  "updated": "2026-10-20T00:00:00.000Z",
  "verified": "2026-10-20T00:00:00.000Z",
  "recheck_after": "2026-11-19T00:00:00.000Z",
  "changelog": [
    {
      "date": "2026-10-20T00:00:00.000Z",
      "note": "first version. On a fresh install with only gateway.mode, bind and a token set, the audit reported 0 critical, 2 warnings (trusted proxies, state dir 755) and tools.elevated plus browser control enabled by default"
    }
  ]
}