#origin not allowed (open the Control UI from the gateway host or allow it in gateway.controlUi.allow

1 messages · Page 1 of 1 (latest)

digital compass
#

origin not allowed (open the Control UI from the gateway host or allow it in gateway.controlUi.allowedOrigins)

remote caveBOT
high monolithBOT
#

This usually means the browser origin you opened the Control UI from is not on the gateway allowlist.

First, can you paste:

openclaw --version

Likely fix:

  1. If you’re on the gateway host, open the UI from:
http://127.0.0.1:18789/
  1. If you’re opening it remotely, add the exact browser origin to config, for example:
#
{
  gateway: {
    controlUi: {
      allowedOrigins: ["https://control.example.com"]
      // or ["http://192.168.1.50:18789"]
    }
  }
}

Then restart:

openclaw gateway restart

Important: use the full origin, scheme + host + port, no path. If you’re behind a reverse proxy, use the public URL, not the internal gateway URL.

digital compass
high monolithBOT
#

Ah, I think I see it, if you’re opening the UI through Tailscale Serve / MagicDNS, the browser origin is probably HTTPS, but your allowlist only has HTTP entries.

Try adding the exact HTTPS origin:

{
  gateway: {
    controlUi: {
      enabled: true,
      allowedOrigins: [
        "https://desktop-cmslndl.tail9f107f.ts.net",
        "http://100.90.11.46:18789"
      ]
    }
  }
}
#

Then restart the gateway:

openclaw gateway restart

A couple things to verify:

  • allowedOrigins must match the exact browser origin
  • scheme matters: http:// and https:// are different
  • if you use Tailscale Serve, the docs path is usually https://<magicdns>/, not http://...

Also paste these if it still fails:

openclaw --version
digital compass
#

│
â—‡
Service: systemd (enabled)
File logs: /tmp/openclaw/openclaw-2026-04-10.log
Command: /usr/local/bin/node /home/rr420/.npm-global/lib/node_modules/openclaw/dist/index.js gateway --port 18789
Service file: ~/.config/systemd/user/openclaw-gateway.service
Service env: OPENCLAW_GATEWAY_PORT=18789

Config (cli): ~/.openclaw/openclaw.json
Config (service): ~/.openclaw/openclaw.json

Gateway: bind=lan (0.0.0.0), port=18789 (service args)
Probe target: ws://127.0.0.1:18789
Dashboard: http://100.67.174.127:18789/
Probe note: bind=lan listens on 0.0.0.0 (all interfaces); probing via 127.0.0.1.

Runtime: running (pid 25680, state active, sub running, last exit 0, reason 0)
RPC probe: ok

Listening: *:18789
Troubles: run openclaw status

"controlUi": {
"enabled": true,
"allowedOrigins": [
"https://desktop-cmslndl.tail9f107f.ts.net",
"http://100.90.11.46:18789"
]
},
still origin not allowed (open the Control UI from the gateway host or allow it in gateway.controlUi.allowedOrigins)

high monolithBOT
#

Yep, there’s the mismatch.

Your gateway status says the dashboard is being served at:

http://100.67.174.127:18789/

But your allowedOrigins only has:

  • https://desktop-cmslndl.tail9f107f.ts.net
  • http://100.90.11.46:18789

So if you’re opening http://100.67.174.127:18789/, that origin is not allowed.

Add the exact current origin:

#
{
  gateway: {
    controlUi: {
      enabled: true,
      allowedOrigins: [
        "https://desktop-cmslndl.tail9f107f.ts.net",
        "http://100.67.174.127:18789"
      ]
    }
  }
}

Then restart:

#
openclaw gateway restart

Or simpler, open the UI using one of the origins already on the list.

If you want the cleanest setup, I’d avoid bind=lan and use either:

  • Tailscale Serve with https://<magicdns>/, or
  • loopback + SSH tunnel

Docs:

If it still fails after that, paste the exact browser URL you’re opening, because the allowlist has to match it exactly.

digital compass
#

control ui requires device identity (use HTTPS or localhost secure context)

high monolithBOT
#

Yep, that’s the next gate, and it makes sense.

You’ve moved past origin not allowed. Now the problem is that the Control UI is being opened over plain remote HTTP, and device identity needs a secure context.

So this will fail:

http://100.x.x.x:18789/

Safe fixes:

  1. Open it on the gateway host itself
http://127.0.0.1:18789/
#
  1. Use HTTPS for remote access, best option is Tailscale Serve:
{
  gateway: {
    bind: "loopback",
    tailscale: { mode: "serve" },
    controlUi: {
      allowedOrigins: ["https://desktop-cmslndl.tail9f107f.ts.net"]
    }
  }
}

Then restart:

#
openclaw gateway restart

and open:

https://desktop-cmslndl.tail9f107f.ts.net/

Important:

  • allowInsecureAuth only helps on localhost
  • it does not make remote http://100.x.x.x work
  • I would not use dangerouslyDisableDeviceAuth except as a brief debugging hack

So, short version: remote Control UI needs HTTPS or localhost.

digital compass
#

Hmmm… can't reach this page
100.67.174.127 refused to connect.
Try:

Search the web for 100 67 174 127
Checking the connection
Checking the proxy and the firewall
Hmmm… can't reach this page
msi.tail9f107f.ts.net refused to connect.
Try:

Search the web for msi tail9f107f ts net
Checking the connection
Checking the proxy and the firewall
ERR_CONNECTION_REFUSED

high monolithBOT
#

Got it. Two separate things are happening now:

  1. msi.tail9f107f.ts.net without a port will refuse unless you’ve set up Tailscale Serve or a reverse proxy.
  2. http://100.67.174.127:18789/, even if reachable, is still the wrong long-term path for Control UI because remote plain HTTP will hit the secure-context/device-identity wall.

Also, RPC probe: ok only means the gateway is reachable locally on the host, not from your other machine.

I’d stop fighting the raw LAN/Tailnet bind and use one of these instead:

Easiest: SSH tunnel

From your client machine:

ssh -N -L 18789:127.0.0.1:18789 user@<gateway-host>

Then open locally:

#
http://127.0.0.1:18789/

Better permanent setup: Tailscale Serve

Set:

{
  gateway: {
    bind: "loopback",
    tailscale: { mode: "serve" },
    controlUi: {
      allowedOrigins: ["https://msi.tail9f107f.ts.net"]
    }
  }
#
}

Then restart:

openclaw gateway restart

and open:

https://msi.tail9f107f.ts.net/

If you want to debug the current direct bind anyway, check from another machine:

#
nc -vz 100.67.174.127 18789

or on the gateway host:

ss -ltnp | grep 18789

But honestly, I’d recommend SSH tunnel or Tailscale Serve here. It avoids both the port-connectivity problem and the secure-context problem.

Docs:

If you want, I can give you the exact minimal SSH tunnel or Tailscale Serve setup based on your machine layout.

digital compass
#

ss -ltnp | grep 18789
LISTEN 0 511 127.0.0.1:18789 0.0.0.0:* users:(("openclaw-gatewa",pid=26628,fd=22))
LISTEN 0 511 [::1]:18789 [::]:* users:(("openclaw-gatewa",pid=26628,fd=23))

Test-NetConnection 100.67.174.127 -Port 18789
WARNING: TCP connect to (100.67.174.127 : 18789) failed

"port": 18789,
"bind": "loopback",
"tailscale": {
"mode": "serve"
},
"trustedProxies": [
"100.0.0.0/10",
"127.0.0.1"
],
"controlUi": {
"enabled": true,
"allowedOrigins": [
"https://msi.tail9f107f.ts.net"
]
},
ERR_CONNECTION_REFUSED

high monolithBOT
#

This is actually useful, you’re very close now.

Your ss output shows the gateway is listening on 127.0.0.1 only, which is correct for:

bind: "loopback",
tailscale: { mode: "serve" }

So this failing is expected now:

Test-NetConnection 100.67.174.127 -Port 18789

because port 18789 is not supposed to be exposed directly anymore.

#

The real problem is this part:

https://msi.tail9f107f.ts.net -> ERR_CONNECTION_REFUSED

That means Tailscale Serve is not actually active on the gateway host yet.

Please run on the gateway host:

tailscale status
tailscale serve status
openclaw gateway restart
openclaw logs --follow
#

What I’d expect:

  • tailscale status shows the machine is logged in
  • tailscale serve status shows HTTPS for msi.tail9f107f.ts.net forwarding to http://127.0.0.1:18789
  • if it doesn’t, the gateway likely failed to configure Serve, often because:
    • Tailscale CLI is not installed
    • Tailscale is not logged in
    • HTTPS is not enabled for the tailnet
    • startup logged a Serve error

So: loopback is fine, direct IP refusal is fine, the missing piece is Tailscale Serve itself.

Docs:

Paste the output of tailscale serve status and the relevant openclaw logs --follow lines, and I’ll help pin it down.

digital compass
#

I am using wsl for openclaw but i install tailscale on win11

high monolithBOT
#

Aha, that’s the missing piece.

If OpenClaw runs in WSL and your browser is on Windows, the simplest path is:

http://127.0.0.1:18789/

from Windows, not the Tailnet IP / MagicDNS name.

There’s a specific WSL2 rule in the docs: when the UI is opened from Windows, use Windows localhost unless you’ve set up deliberate HTTPS.

Why this got weird:

  • OpenClaw is listening inside WSL
  • Tailscale is installed on Windows
  • so tailscale.mode: "serve" inside WSL is not the same as having Tailscale Serve on the actual gateway host environment
#

Quick test in PowerShell on Windows:

Test-NetConnection 127.0.0.1 -Port 18789

If that succeeds, open:

http://127.0.0.1:18789/

and you should stop hitting the Tailnet-origin / secure-context mess.

So my recommendation:

  1. Ignore Tailnet URL for now
  2. Open http://127.0.0.1:18789/ on Windows
digital compass
#

need access from a different device

high monolithBOT
#

Then I’d recommend SSH tunnel for your current setup.

Because right now you have a split host setup:

  • OpenClaw Gateway in WSL
  • Tailscale on Windows

That makes direct remote Control UI access awkward. The supported clean options are:

Option 1, recommended now: SSH tunnel

Keep:

gateway.bind: "loopback"

From the other device, tunnel to the machine running WSL/Windows:

#
ssh -N -L 18789:127.0.0.1:18789 <user>@<windows-or-wsl-host>

Then on that other device, open:

http://127.0.0.1:18789/

This avoids:

  • origin allowlist headaches
  • insecure remote HTTP
  • WSL/Windows Tailscale split weirdness

Option 2, cleaner permanent setup

Run OpenClaw and Tailscale on the same host and then use Tailscale Serve.

#

So either:

  • move OpenClaw out of WSL and run it on Windows, or
  • run OpenClaw on a Linux box/VPS with Tailscale on that same box

Then remote access via https://<magicdns>/ is much cleaner.

What I would not do

I would not go back to bind=lan and raw http://100.x.x.x:18789 for Control UI. You already found why, it runs into both connectivity and secure-context/device-auth issues.

Docs:

If you want, I can help you set up the SSH tunnel path step by step for your exact devices.

digital compass
#

how about the config

high monolithBOT
#

For your current WSL + Windows split, I’d use this config and go with SSH tunnel.

Recommended config, SSH tunnel

{
  gateway: {
    bind: "loopback",
    auth: {
      mode: "token",
      token: "replace-with-a-long-random-token"
    },
    controlUi: {
      enabled: true
    }
  }
}
#

Notes:

  • no allowedOrigins needed
  • no tailscale.mode: "serve" needed
  • keep it loopback-only

Then restart:

openclaw gateway restart

From the other device:

ssh -N -L 18789:127.0.0.1:18789 user@host
#

Then open on that device:

http://127.0.0.1:18789/

and paste the token if prompted.

If you want Tailscale Serve later

That works best when OpenClaw and Tailscale are on the same host:

{
  gateway: {
    bind: "loopback",
    tailscale: { mode: "serve" },
digital compass
#

But with OpenClaw in WSL and Tailscale on Windows, I would not start there. why?
SSH tunnel work, but later on I may have other device as node to use

high monolithBOT
#

Yeah, fair question.

The reason is basically you have two different “hosts” right now:

  • the Gateway process lives in WSL
  • the Tailnet identity / Tailscale daemon lives on Windows

That split matters because:

  1. Tailscale Serve / identity-header auth is cleanest when Tailscale and the Gateway are on the same host
  2. Inbound Tailnet traffic reaches Windows first, then has to be forwarded into WSL
  3. for browser UI, remote nodes, and WebSocket upgrades, that extra hop adds more moving parts

So it’s not that WSL + Windows Tailscale is impossible, it’s just a more fragile place to start if you want to grow into remote Control UI + nodes.

If you want nodes later, I’d recommend one of these

#

Best long-term

Run OpenClaw and Tailscale on the same machine

Either:

  • OpenClaw on Windows, Tailscale on Windows
  • or OpenClaw on Linux/VPS, Tailscale on that same Linux/VPS

That gives you one clean network identity, and then:

  • Control UI can use Tailscale Serve
  • nodes can connect over the same Gateway WS

Keep WSL for now

That’s still fine, but I’d treat it like:

  • Control UI via SSH tunnel
  • future nodes only after you deliberately set up forwarding/proxying from Windows into WSL

That second path can work, but it’s more DIY.

digital compass
#

how about win11 uninstall tailscale, wsl use tailscale?

high monolithBOT
#

Yes, that’s a much more coherent setup than:

  • OpenClaw in WSL
  • Tailscale on Windows

If WSL is going to be your real gateway host, then having Tailscale in that same WSL environment is the cleaner direction, especially if you want other devices as nodes later.

Why it’s better

It gives you one real host identity:

  • Gateway process
  • Tailscale daemon
  • Tailscale Serve
  • inbound node/WebSocket traffic

all on the same machine/context.

#

That avoids the Windows ↔ WSL forwarding weirdness.

My recommendation

Yes, I’d consider that path.

But I would not uninstall Windows Tailscale first.

I’d do it in this order:

  1. get Tailscale working inside WSL
  2. verify it has the Tailnet identity you want
  3. verify remote access works
  4. then disable/remove Windows Tailscale if you no longer need it there

Config I’d use once they’re on the same host

{
#
  gateway: {
    bind: "loopback",
    auth: {
      mode: "token",
      token: "replace-with-a-long-random-token"
    },
    tailscale: {
      mode: "serve"
    },
    controlUi: {
      enabled: true,
      allowedOrigins: ["https://<your-magicdns-name>"]
    }
  }
}
#

Then restart:

openclaw gateway restart

And open:

https://<your-magicdns-name>/

For future nodes

This is a much better base. Other devices can connect to the gateway much more cleanly once the gateway and Tailscale live together.

So short version: yes, better idea, but migrate carefully, don’t uninstall Windows Tailscale until the WSL side is confirmed working.

digital compass
#

"port": 18789,
"bind": "loopback",
"tailscale": {
"mode": "serve"
},
"controlUi": {
"enabled": true,
"allowedOrigins": [ "https://msi-1.tail9f107f.ts.net" ]
},
╰─ ping msi-1.tail9f107f.ts.net

Pinging msi-1.tail9f107f.ts.net [100.65.1.106] with 32 bytes of data:
Reply from 100.65.1.106: bytes=32 time=2ms TTL=64
Reply from 100.65.1.106: bytes=32 time=2ms TTL=64
Reply from 100.65.1.106: bytes=32 time=2ms TTL=64
Reply from 100.65.1.106: bytes=32 time=2ms TTL=64

Ping statistics for 100.65.1.106:
Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
Minimum = 2ms, Maximum = 2ms, Average = 2ms

https://msi-1.tail9f107f.ts.net/

Hmmm… can't reach this page
msi-1.tail9f107f.ts.net refused to connect.
Try:

Checking the connection
Checking the proxy and the firewall
ERR_CONNECTION_REFUSED

high monolithBOT
#

This is actually a good sign.

ping working means:

  • MagicDNS resolves
  • Tailnet reachability is fine

But ERR_CONNECTION_REFUSED on https://msi-1.tail9f107f.ts.net/ means something simpler:

Tailscale Serve is not actually serving HTTPS there yet.

So at this point, this is not an allowedOrigins problem anymore.

What to check on the WSL host

Run:

#
tailscale status
tailscale serve status
openclaw gateway restart
openclaw logs --follow

What you want to see

tailscale serve status should show something like:

https://msi-1.tail9f107f.ts.net/  ->  http://127.0.0.1:18789

If it does not, then one of these is true:

  • Tailscale Serve was never configured
#
  • the WSL Tailscale daemon is not the one owning that MagicDNS name
  • HTTPS/Serve is not enabled for that tailnet
  • OpenClaw tried to configure Serve and failed on startup

Key point

Your config:

tailscale: { mode: "serve" }

does not by itself prove Serve is active.
It only tells OpenClaw to try.

So now the next proof point is really tailscale serve status.

If you paste that output, plus the first relevant lines from openclaw logs --follow after restart, I can tell you exactly where it’s failing.

digital compass
#

just serve, its works now, thx, later how to set if I have other network run as node?

high monolithBOT
#

Nice, glad Serve is working now 🎉

For other devices as nodes later, there are really 2 paths:

1) Phone / app-style node

If it’s something like Android/iOS, your current gateway setup is fine:

{
  gateway: {
    bind: "loopback",
    tailscale: { mode: "serve" }
  }
}

Then on the device:

#
  • connect to the Serve URL (https://... / wss://...)
  • approve pairing on the gateway host:
openclaw devices list
openclaw devices approve <requestId>
openclaw nodes status

2) Another computer as a headless node host

If you want another machine to run commands/tools for the gateway, use a node host.

Because your gateway is loopback-only, the clean setup is:

On the node machine

#
# tunnel to the gateway host
ssh -N -L 18790:127.0.0.1:18789 user@gateway-host

In another terminal on that node machine:

export OPENCLAW_GATEWAY_TOKEN="<gateway-token>"
openclaw node run --host 127.0.0.1 --port 18790 --display-name "Build Node"

On the gateway host

Approve it:

#
openclaw devices list
openclaw devices approve <requestId>
openclaw nodes status

If you want the gateway to send exec there by default:

openclaw config set tools.exec.host node
openclaw config set tools.exec.node "Build Node"
openclaw config set tools.exec.security allowlist

Then allowlist commands for that node as needed.

My recommendation

digital compass
#

tailscale serve status
https://msi-1.tail9f107f.ts.net (tailnet only)
|-- / proxy http://127.0.0.1:18789

09:56:58+08:00 [tailscale] serve failed: Command failed: /usr/bin/tailscale serve --bg --yes 18789
sending serve config: Access denied: serve config denied

Use 'sudo tailscale serve --bg --yes 18789'.
To not require root, use 'sudo tailscale set --operator=$USER' once.

09:56:58+08:00 [gateway] starting channels and sidecars...
09:56:58+08:00 [hooks] loaded 4 internal hook handlers
09:57:19+08:00 [bonjour] watchdog detected non-announced service; attempting re-advertise (gateway fqdn=MSI (OpenClaw)._openclaw-gw._tcp.local. host=openclaw.local. port=18789 state=probing)

why?

high monolithBOT
#

That log is basically saying:

Serve is already configured, but OpenClaw is not allowed to manage it itself.

Why:

  • tailscale serve status shows a Serve config already exists
  • but OpenClaw runs as your normal user
  • Tailscale only lets root or an approved operator user change Serve config

So on startup OpenClaw tries:

tailscale serve --bg --yes 18789

and Tailscale replies:

#
Access denied: serve config denied

Fix, one-time

In WSL, run:

sudo tailscale set --operator=$USER

Then restart OpenClaw:

openclaw gateway restart
#

After that, OpenClaw should be able to manage tailscale serve without root.

If it already works right now

You can also just leave it for the moment.
It likely works because Serve was already configured manually or by sudo, and OpenClaw is only failing when trying to update/reapply it.

About the Bonjour line

That part is unrelated to the Tailscale Serve permission issue. The important bit is the serve config denied message.

So short version:

  • why? OpenClaw user lacks permission to edit Tailscale Serve config
  • fix? sudo tailscale set --operator=$USER once

Docs:

#

If this fixed it, please right-click the solution message → Apps → ✅ Mark Solution.
This helps Answer Overflow index the solution for future users.

digital compass
#

09:57:30+08:00 [ws] Proxy headers detected from untrusted address. Connection will not be treated as local. Configure gateway.trustedProxies to restore local client detection behind your proxy.
09:57:30+08:00 [ws] closed before connect conn=85f4fcf2-2f5b-4644-8ace-6a98bed2c425 remote=127.0.0.1 fwd=100.90.11.46 origin=https://msi-1.tail9f107f.ts.net host=msi-1.tail9f107f.ts.net ua=Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0 code=1006 reason=n/a
09:57:41+08:00 [ws] Proxy headers detected from untrusted address. Connection will not be treated as local. Configure gateway.trustedProxies to restore local client detection behind your proxy.

high monolithBOT
#

That warning means the Gateway is seeing Tailscale Serve as a proxy on loopback, but your config does not currently trust that loopback proxy source.

From the log:

  • remote=127.0.0.1
  • fwd=100.90.11.46

So Tailscale Serve is forwarding correctly, but OpenClaw is saying:

“I got proxy headers, but the proxy IP itself is not in gateway.trustedProxies.”

Fix

Add loopback to trustedProxies:

{
#
  gateway: {
    bind: "loopback",
    tailscale: { mode: "serve" },
    trustedProxies: ["127.0.0.1", "::1"],
    controlUi: {
      enabled: true,
      allowedOrigins: ["https://msi-1.tail9f107f.ts.net"]
    }
  }
}

Then restart:

#
openclaw gateway restart

Important

Do not switch to:

gateway.auth.mode: "trusted-proxy"

for this.

That mode is for a non-loopback identity-aware reverse proxy.
For Tailscale Serve on the same host, the right fix is just gateway.trustedProxies.

So short version:

digital compass
#

10:03:50+08:00 [bonjour] watchdog detected non-announced service; attempting re-advertise (gateway fqdn=MSI (OpenClaw)._openclaw-gw._tcp.local. host=openclaw.local. port=18789 state=probing)
10:03:50+08:00 [ws] closed before connect conn=41bc76c3-aa40-44d5-b557-bc7161a78c17 remote=127.0.0.1 fwd=100.90.11.46 origin=https://msi-1.tail9f107f.ts.net host=msi-1.tail9f107f.ts.net ua=Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0 code=1006 reason=n/a

high monolithBOT
#

This looks a lot less scary than the earlier errors.

  • The old proxy warning is gone, so that part is likely fixed.
  • bonjour ... re-advertise is unrelated to the Control UI issue.
  • closed before connect ... code=1006 by itself usually just means the browser/WebSocket got dropped before the handshake finished. That can happen on refresh, tab close, retry, or a client-side failure.

So this log line alone is not the real root cause.

If the UI works now

You can mostly ignore these two lines.

If the UI still does not work

What I need next is the actual UI error text in the browser, for example:

  • pairing required
  • unauthorized
  • origin not allowed