#What is the correct gateway configuration?

1 messages · Page 1 of 1 (latest)

pallid ridge
#

My bot just broke the gateway configuration and I dont know the original values, I want to use tailscale:

  "gateway": {
    "port": 18789,
    "mode": "local",
    "auth": {
      "mode": "token",
      "token": "<hidden>"
    },
    "tailscale": {
      "mode": "serve",
      "resetOnExit": false
    },
    "nodes": {
      "denyCommands": [
        "camera.snap",
        "camera.clip",
        "screen.record",
        "calendar.add",
        "contacts.add",
        "reminders.add"
      ]
    }
  }```
icy rootBOT
#

Your snippet is very close to valid, but two gotchas:

  1. Tailscale Serve wants the Gateway bound to loopback (so Tailscale proxies it with HTTPS).
  2. OpenClaw config is schema-validated — any unknown key will make the Gateway refuse to start. I’m pretty sure gateway.nodes is not a valid config section, so that alone can “break the gateway configuration”.

Working Tailscale Serve config (tailnet-only HTTPS)

{
  gateway: {
    mode: "local",
    port: 18789,
    bind: "loopback",

    auth: {
      mode: "token",
      token: "<your token>",
#
      allowTailscale: true, // lets Tailscale Serve identity headers satisfy auth
    },

    tailscale: {
      mode: "serve",
      resetOnExit: false,
    },
  },
}

Then run/restart the gateway and open:

  • https://<magicdns>/ (Serve)

Docs:

#

If you want “tailnet bind” (no Serve/Funnel proxy)

This is the alternative where the Gateway listens directly on the Tailscale IP (HTTP, and you paste the token into the UI):

{
  gateway: {
    mode: "local",
    bind: "tailnet",
    port: 18789,
    auth: { mode: "token", token: "<your token>" },
  },
}

Open:

  • http://<tailscale-ip>:18789/
#

About your gateway.nodes.denyCommands

I don’t see any config field like that in the current config schema, so it likely breaks validation. If your goal is “don’t allow camera/screen/etc”, the usual way is:

  • don’t pair a node that has those permissions enabled, or
  • disable camera/screen permissions on the node device itself, or
  • block node access at the tool level (e.g. deny the nodes tool), depending on what you’re trying to protect.

Quick next step

On the gateway host, run:

openclaw doctor

It’ll print the exact config validation error (including the path of the unknown key). If you paste that output + openclaw --version, I can tell you exactly what to delete/rename.

pallid ridge
#

what is the default config for gateway so it listens in locahost only?

icy rootBOT
#

By default, the Gateway listens on localhost only (loopback). So the “default config” is effectively: don’t set anything under gateway, and it will bind to loopback on port 18789.

If you want to be explicit in ~/.openclaw/openclaw.json (JSON5), use:

{
  gateway: {
    bind: "loopback",      // localhost only (127.0.0.1)
    port: 18789,
    tailscale: { mode: "off" },
    // auth can be omitted if you already have OPENCLAW_GATEWAY_TOKEN set,
    // or set explicitly:
    // auth: { mode: "token", token: "your-token" },
  },
}
#

Then you open the UI on the same machine at:

  • http://127.0.0.1:18789/ (or http://localhost:18789/)
pallid ridge
#

i have this error now: [openclaw] Failed to start CLI: Error: gateway closed (1008): pairing required

icy rootBOT
#

That error means the Gateway is reachable, but it rejected this CLI instance because the device is not paired/approved yet (WebSocket close code 1008).

You need to approve the pending device pairing from an already-trusted place (usually on the gateway host via localhost, which is auto-approved).

Fix (recommended)

On the gateway machine (same box that runs openclaw gateway):

openclaw devices list
openclaw devices approve <requestId>

Then re-run whatever you were running.

Notes:

  • Local connections (127.0.0.1) are auto-approved, but Tailnet/LAN connections are not.
  • This is separate from gateway.auth.token / gateway.auth.allowTailscale. Tailscale Serve can satisfy auth, but you still need the one-time device approval.
pallid ridge
#

in what folder should the openclaw avatar image how?

icy rootBOT
#

The avatar path is workspace-relative.

So you can put the image file anywhere inside your agent’s workspace directory (whatever agents.defaults.workspace / agents.list[].workspace is), and then reference it with a relative path.

Example (recommended layout):

  1. Put the file here (default workspace):
  • ~/.openclaw/workspace/avatars/my-avatar.png
  1. Set in config:
{
  agents: {
    list: [
      {
        id: "main",
#
        identity: {
          avatar: "avatars/my-avatar.png"
        }
      }
    ]
  }
}

Also supported: http(s) URL or a data: URI (so you don’t need a local file).

Source: identity.avatar: “workspace-relative path, http(s) URL, or data: URI.” (docs: /gateway/configuration-reference, Identity section)

pallid ridge
icy rootBOT
#

MEMORY.md is not auto-created by OpenClaw.

From the docs: the workspace bootstrap creates AGENTS.md, SOUL.md, TOOLS.md, IDENTITY.md, USER.md, HEARTBEAT.md — but MEMORY.md is optional (not auto-created). When it exists, it gets loaded for normal sessions. (/start/openclaw)

So if you want it, just create it yourself (empty is fine) in your agent workspace, e.g.:

  • default workspace: ~/.openclaw/workspace/MEMORY.md

Two more common “why didn’t it write memory?” gotchas:

  1. You’re in a group chat / server channel
    MEMORY.md is intended for the main/private session (DM with your bot). In group contexts it won’t load/use it. Use a DM to ask “remember this” / “write this to memory”.

  2. Memory files only get written when prompted
    The daily log memory/YYYY-MM-DD.md is typically created when you explicitly ask the bot to store something, or when the session gets close to compaction (silent “memory flush”). If you haven’t asked + the chat isn’t long, nothing gets created yet.

If you tell me what your workspace path is (openclaw config get agents.defaults.workspace) and where you’re chatting (DM vs Discord channel), I can tell you which behavior you’re seeing.

pallid ridge
#

The interface dashboard does not show the agent icon, it returns always 404 not found

icy rootBOT
#

The avatar 404 is almost always one of these two things:

  1. Base path mismatch (you’re serving the Control UI under a prefix, but /avatar/... isn’t going through that same prefix), or
  2. The gateway can’t resolve/read the configured avatar (wrong path, outside workspace, missing file, or >2 MB) so the /avatar/<agentId> route returns 404.

1) Check your Control UI basePath

If you set:

gateway: { controlUi: { basePath: "/openclaw" } }

then the avatar endpoint is also under that prefix:

  • âś… https://<host>/openclaw/avatar/<agentId>
  • ❌ https://<host>/avatar/<agentId> (will 404 behind many proxies)
#

So first question: are you using gateway.controlUi.basePath (or Tailscale Serve path routing) at all?

2) Verify the avatar file + config location

Make sure you’re setting it here (this is the schema-valid spot):

{
  agents: {
    list: [{
      id: "main",
      identity: { avatar: "avatars/my-avatar.png" }
    }]
  }
}

And the file must be:

#
  • inside that agent’s workspace (e.g. ~/.openclaw/workspace/avatars/my-avatar.png)
  • a real file (not a directory)
  • ≤ 2 MB (hard limit)

Quick test: open the avatar route directly in a browser on the gateway host:

  • http://127.0.0.1:18789/avatar/main
    (or with basePath: http://127.0.0.1:18789/openclaw/avatar/main)

If that 404s, the gateway isn’t able to load the avatar you configured.

3) Separate issue: 1008 pairing required

That one won’t fix the 404, but you’ll keep hitting it for remote browsers until you approve the device:

openclaw devices list
#
openclaw devices approve <requestId>

If you paste:

  • the exact URL you’re opening (including any /openclaw prefix), and
  • the exact avatar config line you set (identity.avatar: ...)

…I can tell you which of the two buckets your 404 is in.

pallid ridge
#

claw@ubuntu-4gb-hel1-1:~$ ls .openclaw/workspace/avatars/icon.png
.openclaw/workspace/avatars/icon.png

icy rootBOT
#

That file location looks right on disk — the usual gotcha is the value you put into identity.avatar.

identity.avatar must be workspace-relative, not a full/partial path from ~:

âś… correct (given your file):

agents: {
  list: [{
    id: "main",
    identity: { avatar: "avatars/icon.png" }
  }]
}

❌ common wrong ones that will 404:

  • "~/.openclaw/workspace/avatars/icon.png" (absolute/tilde paths rejected)
  • ".openclaw/workspace/avatars/icon.png" (gets resolved inside the workspace → effectively ~/.openclaw/workspace/.openclaw/... which doesn’t exist)
#

A couple quick sanity checks if it still 404s:

  1. Confirm the agent id you’re using is really main
    The URL is /avatar/<agentId> (so if your agent id is home, it’s /avatar/home).

  2. Check the avatar endpoint locally (bypasses any Tailscale/basePath confusion):

  • http://127.0.0.1:18789/avatar/main

If you have gateway.controlUi.basePath: "/openclaw", then it becomes:

  • http://127.0.0.1:18789/openclaw/avatar/main
  1. Size limit: avatar must be ≤ 2 MB:
stat -c %s ~/.openclaw/workspace/avatars/icon.png

If you paste your current agents.list[...] snippet (just the agent id + workspace + identity.avatar) and whether you set gateway.controlUi.basePath, I can point to the exact mismatch.

pallid ridge
#

is empty, is the default value

icy rootBOT
#

If identity.avatar is empty / unset, then there is no default image avatar to serve — so a 404 on:

  • /avatar/<agentId>

is basically “no avatar configured” (the Control UI should fall back to initials/emoji, but the backend route itself can still 404 when there’s nothing to return).

Since you do have a file at ~/.openclaw/workspace/avatars/icon.png, you just need to point the agent at it (workspace-relative):

# (optional) confirm the agent id you’re using
openclaw config get agents.list[0].id

# set avatar (workspace-relative!)
openclaw config set agents.list[0].identity.avatar "avatars/icon.png"

# restart gateway so it reloads config
#
openclaw gateway restart

Then test locally on the gateway host:

  • http://127.0.0.1:18789/avatar/<that-agent-id>

One more thing: what’s your openclaw --version? If the UI is showing a broken image instead of falling back nicely when no avatar is set, that might be a version-specific UI bug/regression.

pallid ridge
#

openclaw version: 2026.2.19-2

icy rootBOT
#

2026.2.19-2 is current enough here — nothing special about that version for avatars.

If identity.avatar is unset/empty, then the gateway typically has nothing to serve at /avatar/<agentId> → a 404 is normal. The Control UI should fall back to initials/emoji, but the /avatar/... endpoint itself won’t magically produce an image.

To make the image work, explicitly set it to the workspace-relative path and restart:

openclaw config set agents.list[0].identity.avatar "avatars/icon.png"
openclaw gateway restart

Then test on the gateway host:

  • http://127.0.0.1:18789/avatar/main

If you configured a Control UI basePath, the URL is:

#
  • http://127.0.0.1:18789/<basePath>/avatar/main

Quick checks if it still 404s:

openclaw config get agents.list[0].id
openclaw config get agents.list[0].identity.avatar
openclaw config get gateway.controlUi.basePath
stat -c %s ~/.openclaw/workspace/avatars/icon.png  # must be <= 2MB