#VPS Docker - Gateway issue

1 messages · Page 1 of 1 (latest)

spare loom
#

Hi, I have installed via Docker on a VPS. Bizarrely the gateway token in the .env file was different from the gateway token in the openclaw.json file.

I could access the Openclaw Control via browser, however I couldnt get access to any Workspace tab to view files.

I coud talk to my agent via Telegram fine, however she kept creating .md files and .py files and told me to view them in the workspace tab.

She then told me that she couldnt save anything to memory.md date files and that there was a token mismatch on the gateway. "Gateway Unreachable: Token mismatch - openclaw gateway restart fix." copied from her telegram message.

Thats when I noticed the difference in the .env and .json files.

Ive created a brand new token, and updated the .env and .json files. Ive got back onto the Openclaw control, but keep getting the following : unauthorized: gateway token mismatch (open the dashboard URL and paste the token in Control UI settings) - however the Gateway token space in Overview on the Control is the same new token Ive created. Ive restarted the Docker and the gateway container... but just keep going in a loop and get the Too many attempts error...
Anyhelp would be appreciated.

robust tinselBOT
#

To help others find answers, you can mark your question as solved via Right click solution message -> Apps -> âś… Mark Solution

grave jayBOT
#

This usually comes down to two separate “gotchas” in the Docker flow:

  1. The gateway token is coming from the container env (OPENCLAW_GATEWAY_TOKEN), and Docker doesn’t reload .env on a plain restart.
  2. The Control UI caches your token + gatewayUrl in browser localStorage, so it can keep hammering the gateway with the old token until you clear it → then you hit the rate limiter (“Too many attempts”).

Here’s the fastest, reliable reset sequence (without guessing):

0) Don’t paste tokens into Discord

Gateway token = admin secret. If you share logs/config, redact it (keep like first/last 4 chars).

1) Recreate the container so it actually picks up the new .env

From the folder that contains your docker-compose.yml and .env:

docker compose up -d --force-recreate openclaw-gateway
#

(If you’re not sure you’re in the right folder: that’s very commonly the cause—Compose will read a different .env than the one you edited.)

Then verify what the running container actually has:

docker compose exec openclaw-gateway sh -lc 'echo $OPENCLAW_GATEWAY_TOKEN'

That value is what the gateway expects right now.

Docs ref: https://docs.openclaw.ai/install/docker (see “Control UI token + pairing (Docker)”)

2) Generate a fresh dashboard link from inside Compose

This ensures you’re targeting the right gateway URL and token:

#
docker compose run --rm openclaw-cli dashboard --no-open

Copy the URL it prints.

3) Clear the Control UI’s cached token (this matters)

The Control UI stores auth in localStorage key openclaw.control.settings.v1 (docs mention this). Easiest way:

  • open the dashboard in an incognito/private window, paste token again.

This stops the reconnect loop and avoids instantly re-triggering the “Too many attempts” limiter.

FAQ ref: https://docs.openclaw.ai/help/faq#the-control-ui-says-unauthorized-or-keeps-reconnecting-what-now
Control UI ref: https://docs.openclaw.ai/web/control-ui

4) If you’re opening the UI via the VPS IP/domain (not localhost): check allowedOrigins

#

With Docker, people often load http://VPS_IP:18789/ in their laptop browser. The page loads, but the WS connect can be blocked unless gateway.controlUi.allowedOrigins includes that origin.

Check:

docker compose run --rm openclaw-cli config get gateway.controlUi.allowedOrigins

If it’s missing your origin, set it (example):

docker compose run --rm openclaw-cli config set gateway.controlUi.allowedOrigins \
  '["http://YOUR_VPS_IP:18789"]' --strict-json
docker compose restart openclaw-gateway

(Adjust http/https + host to match exactly what’s in your browser address bar.)

#

5) Still stuck? Paste these outputs (redact tokens)

These are usually enough to spot what’s mismatched:

docker compose ps
docker compose logs --tail=200 openclaw-gateway
docker compose run --rm openclaw-cli config get gateway.auth.mode
docker compose run --rm openclaw-cli config get gateway.controlUi.allowedOrigins

And tell me how you’re accessing the UI (direct http://ip:18789, via reverse proxy, SSH tunnel, Tailscale, etc.).

spare loom
#

OK, I fed all your feedback into Grok and asked him to talk me through each stage at a time. We got stuck in crazy loop where we couldnt actually get the container to restart. I ve now resolved this and successfully opened up the Openclaw control, but get this error :
control ui requires device identity (use HTTPS or localhost secure context)

grave jayBOT
#

That error is expected when you open the Control UI over plain HTTP from a non-localhost origin (e.g. http://<vps-ip>:18789). Browsers treat that as a non-secure context, so WebCrypto/device identity can’t run, and OpenClaw blocks the connection.

Docs: https://docs.openclaw.ai/web/control-ui#insecure-http

Recommended fix (VPS): SSH tunnel → open localhost

On your laptop:

ssh -N -L 18789:127.0.0.1:18789 user@your-vps

Then open:

127.0.0.1 is treated as a secure context by browsers, so device identity works.

#

If it then says disconnected (1008): pairing required, approve the browser device:

docker compose run --rm openclaw-cli devices list
docker compose run --rm openclaw-cli devices approve <requestId>

Even better: don’t expose the port publicly

In docker-compose.yml, bind the published port to localhost only:

ports:
  - "127.0.0.1:18789:18789"

Then docker compose up -d --force-recreate openclaw-gateway and only access via the SSH tunnel.

#

Alternatives

  • Use HTTPS (Tailscale Serve or your own TLS reverse proxy) and open https://...
  • There is a break-glass config gateway.controlUi.dangerouslyDisableDeviceAuth, but it’s a serious security downgrade—avoid unless you’re unblocking temporarily.

If you tell me how you’re currently accessing it (direct IP, domain behind proxy, Tailscale, etc.), I can point you at the cleanest HTTPS option too.

spare loom
#

Hi, got in via the 127.0.0.1 port, Browser Control loaded - pasted correct Gateway token into the Overview > Gateway token box, then got error about pairing device. I successfully paired my laptop. Now however the chat wouldnt work :

⚠️ Agent failed before reply: No API key found for provider "anthropic". Auth store: /home/node/.openclaw/agents/main/agent/auth-profiles.json (agentDir: /home/node/.openclaw/agents/main/agent). Configure auth for this agent (openclaw agents add <id>) or copy auth-profiles.json from the main agentDir.
Logs: openclaw logs --follow

Im not using Anthropic - using Grok4.1 - the json file has my API - but I cannot find how to edit provider to XAI so Im stuck now.

grave jayBOT
#

That error means the model the agent is actually trying to run is still an anthropic/... model, and the gateway can’t find Anthropic credentials for it — so it fails before generating any reply.

Two key points for your “Grok 4.1” setup:

  1. xAI is provider id xai, and it uses the env var XAI_API_KEY (you don’t “edit provider to XAI” somewhere in the UI).
  2. There are two different “Grok” things in OpenClaw:
    • LLM provider: xai/* models (needs XAI_API_KEY)
    • Web search provider: “Grok” search (separate config; not what Chat uses)

Docs: https://docs.openclaw.ai/concepts/model-providers (see “xAI: xai (XAI_API_KEY)”)

Fix (Docker): add XAI_API_KEY, then switch primary model to xai/...

1) Put your xAI key where the gateway container will load it

Easiest: create/edit the OpenClaw state env file inside the mounted config dir:

  • On the VPS host, add this line to:
#

$OPENCLAW_CONFIG_DIR/.env (this maps to /home/node/.openclaw/.env in the container)

XAI_API_KEY=your_key_here

(Do not paste the key into Discord.)

Then restart:

docker compose up -d --force-recreate openclaw-gateway

2) Confirm OpenClaw sees xAI auth + what model is selected

Run:

#
docker compose run --rm openclaw-cli models status

This will tell you what your resolved primary model is, and which providers have “Missing auth”.

3) Switch the model to an xAI one

List the available xAI model ids on your install:

docker compose run --rm openclaw-cli models list --all --provider xai

Pick one of the xai/... entries and set it:

#
docker compose run --rm openclaw-cli models set xai/<whatever-you-picked>

Then try chat again.

If you still hit “anthropic” after setting xAI

Paste (redacted) output of:

docker compose run --rm openclaw-cli config get agents.defaults.model
docker compose run --rm openclaw-cli models status

and I’ll point to the exact spot overriding it (common causes: agents.defaults.models allowlist, or a per-agent override).

spare loom
grave jayBOT
#

That specific error:

Error: Cannot find module '/app/models'

…is what you get when the container is effectively running node models ... (i.e. Node thinks models is a JavaScript file at /app/models), instead of running the OpenClaw CLI router (node dist/index.js …).

In practice that usually means one of these happened:

  • the command was run against the wrong service (easy to do: openclaw-gateway instead of openclaw-cli), or
  • you’re not using the stock docker-compose.yml (so openclaw-cli isn’t using the expected entrypoint), or
  • Compose is being run from a different directory than you think.

Quick workaround (forces the correct entrypoint)

Run this exactly:

#
docker compose run --rm \
  --entrypoint "node dist/index.js" \
  openclaw-cli models list --all --provider xai

If that prints a model list, you’re unblocked.

Then set your model (example format):

docker compose run --rm --entrypoint "node dist/index.js" openclaw-cli models set xai/<model-id>

Sanity check

Also confirm you’re really using openclaw-cli:

#
docker compose config | rg -n "openclaw-cli:|entrypoint:|openclaw-gateway:"

If you paste the exact command you ran (just the command line, no secrets), I can tell you which of the above cases you hit.

spare loom
#

OK, so API key and model is set. I got an error that says Command 'rg' not found, but can be installed with :

grave jayBOT
#

Yep — rg is ripgrep, and lots of VPS images don’t have it.

You can just use plain grep instead (no install needed). For example, this is the rg command I suggested, rewritten:

docker compose config | grep -nE 'openclaw-cli:|entrypoint:|openclaw-gateway:'

Or, if you want a bigger chunk around the openclaw-cli service:

docker compose config | sed -n '/openclaw-cli:/,/openclaw-gateway:/p'

If your API key + model are set and chat is working now, you can also ignore the whole “config grep” step — it was just for debugging the earlier /app/models weirdness.

spare loom
#

Ok chat now works. Thank you.

I think now I need to make sure I can access the control via my browser, but not via using the ip 127.0.0.1etc. Whats the steps for that ?

grave jayBOT
#

You can’t reliably use the Control UI from a remote machine over plain http://<vps-ip>:18789/ anymore — the browser is in a non-secure context, so you hit:

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

So the “steps” are basically: keep using localhost (tunnel) or make it HTTPS.

Option A (recommended): keep the Gateway private + use SSH tunnel

This is what you already did. It’s the safest (you’re not exposing an admin UI to the internet).

If you want it to feel “remote but convenient”, bookmark http://127.0.0.1:18789/ and just run the tunnel when needed.

Option B: HTTPS (tailnet-only recommended)

Best pattern on a VPS is: don’t expose 18789 publicly, put it behind a private HTTPS access layer (Tailscale Serve is the nicest).

High-level steps:

  1. Bind the published docker port to localhost only (so it’s not public):
#
   ports:
     - "127.0.0.1:18789:18789"

then:

docker compose up -d --force-recreate openclaw-gateway
  1. Put an HTTPS front door in front of http://127.0.0.1:18789 (Tailscale Serve or an HTTPS reverse proxy on the VPS).

  2. Tell OpenClaw to allow that HTTPS origin for WebSocket connects:

    docker compose run --rm openclaw-cli config set gateway.controlUi.allowedOrigins \
      '["https://YOUR_HOSTNAME_HERE"]' --strict-json
    docker compose restart openclaw-gateway
    
#

Then you browse to https://YOUR_HOSTNAME_HERE/, paste your gateway token (unless you intentionally set up tokenless Tailscale identity auth), and you’re in.

Docs to follow for the HTTPS approaches:

If you tell me which HTTPS front door you want (Tailscale Serve vs “I have a domain, use Caddy/Nginx”), I’ll give you the exact minimal config for that route.

Also: glad you got it working — if this fixed your thread, please right-click the solution message → Apps → ✅ Mark Solution so Answer Overflow indexes it.