Short answer: to self-host OpenClaw 2026.10.5 you need Node 24.16+ or 26.1+, a config with gateway.mode=local and token auth, and a loopback bind that you reach over an SSH tunnel. In my run the gateway accepted connections 13 seconds after launch, sat at about 1 GB of memory idle, and came back 12 seconds after a kill -9.
Updated October 2026. Everything below was run on 22 October 2026 on Ubuntu 24.04.4 LTS (4 vCPUs, 7.7 GB RAM) with OpenClaw 2026.10.5 (build 1b58cb9), the latest version on npm that day. The machine was not idle while I tested, so treat the timings as rough upper bounds. Where a number comes from the documentation instead of my run, I say so and link the page.
1. The problem: guides that tell you where to host it, not what happens when you do
Search for OpenClaw self-hosting and the first page is mostly provider roundups and Docker walkthroughs. They tell you which VPS to rent. They rarely tell you what the current release does on first start, what it refuses to do, or how it behaves after a crash. Those are the things you find out at 2 a.m. instead.
So I set up a small lab and wrote down what happened. I installed the latest release into a throwaway directory, gave it its own state directory and port, ran it with no model provider and no chat channels, and then broke it in the ways a production server gets broken: wrong runtime, missing config, wrong token, a second copy, a hard kill, a bad config edit. This is a build log, not a benchmark. It covers one machine and one version, and the last section lists what I did not test.
If you are still deciding whether OpenClaw is the right agent for you, read the OpenClaw vs Hermes Agent comparison first. This post assumes you have chosen and want to run it yourself.
2. How I isolated the lab
I did not want a test gateway anywhere near anything real. Three things kept it contained. I pointed HOME at an empty directory, so every state file landed under /tmp/oc-lab/home/.openclaw instead of my real home. I installed OpenClaw with npm install --prefix instead of globally, so nothing touched the system Node or /usr/bin. And I used port 28789 instead of the default 18789, which the OpenClaw documentation gives as the Gateway default on its Linux server page.
I did not run openclaw onboard --install-daemon, so no systemd unit was created. I ran the gateway in the foreground with openclaw gateway run. That means I tested the process, not the service wrapper. The documented unit settings are in section 9.
3. Step one: the install fails on Node 22, and says so clearly
The machine's system Node is 22.23.1 with npm 10.9.8. I tried the obvious thing first, because that is what most people will do. The output below is trimmed to the lines that matter:
$ npm install --prefix /tmp/oc-lab/p22 openclaw@2026.10.5 --no-audit --no-fund
npm warn EBADENGINE Unsupported engine {
npm warn EBADENGINE package: 'openclaw@2026.10.5',
npm warn EBADENGINE required: { node: '>=24.16.0 <25 || >=26.1.0' },
npm warn EBADENGINE current: { node: 'v22.23.1', npm: '10.9.8' }
npm warn EBADENGINE }
npm error code 1
npm error command failed
npm error command sh -c node scripts/preinstall-package-manager-warning.mjs
npm error [openclaw] error: this OpenClaw release requires Node >=24.16.0 <25 || >=26.1.0.
npm error [openclaw] detected Node 22.23.1 (exec: /usr/bin/node).
npm error [openclaw] upgrade Node, then retry the OpenClaw update.
real 0m30.760s
Two things worth noticing. The failure is a deliberate preinstall guard, not a crash halfway through, so you do not end up with a half-installed package. And the engine warning alone would not have stopped the install: it is the guard script that exits with code 1. If you run npm with scripts disabled, that guard does not run, and you would find out about the Node requirement later and less politely.
The install page lists the requirement as "Node 24.16+ or 26.1+" and adds that "Node 26 is recommended". It also says the installer provisions Node 24 LTS on Linux when Node is missing. I did not run the installer, so I cannot tell you what it does when an older Node is already on the machine. A server that already has Node 22, like this one, hits the error above first.
4. Step two: get Node 24 and install into a prefix
To avoid replacing the system Node, I installed the node npm package into its own prefix and put its bin directory first on PATH:
$ npm install --prefix /tmp/oc-lab/node24 node@24 --no-audit --no-fund
added 2 packages in 6s
$ node -v
v24.22.1
$ npm install --prefix /tmp/oc-lab/p24 openclaw@2026.10.5 --no-audit --no-fund
added 344 packages in 17s
$ openclaw --version
OpenClaw 2026.10.5 (1b58cb9)
The Node 24 runtime is 190 MB on disk and the OpenClaw install is 619 MB across 344 packages. The install took 17 seconds on this connection. That disk figure matters on a small VPS: with a 20 GB disk, the runtime and package already take about 4% before you have any state, logs or plugins.
My command differs from the documented one in one way. The install page gives npm install -g openclaw@latest --allow-scripts=openclaw for npm 12 or npm 11.16+, notes that npm 12 blocks unapproved lifecycle scripts by default, and says to omit the flag on npm 11.15 and earlier. I was on npm 10.9.8, so I omitted the flag, and I used --prefix instead of -g to keep the install contained. On a newer npm, use the flag the page gives, or the preinstall guard from section 3 will not get to run.
5. Step three: first start with no config exits with code 78
I started the gateway before configuring anything, to see what a new server owner sees:
$ openclaw gateway run --port 28789
Missing config. Run `openclaw setup` or set gateway.mode=local (or pass --allow-unconfigured).
$ echo $?
78
The real output also contained 36 lines of [gateway] startup phase timing messages before that last line, so on a terminal the actual error is easy to miss. I redirected the output to a file and read the tail. Exit code 78 is useful under a supervisor. The hand-written systemd unit in the documentation sets RestartPreventExitStatus=78, so a config error stops the service instead of restart-looping on it.
I then configured it with five config set commands instead of the interactive wizard, because a wizard cannot be scripted or reviewed:
$ openclaw config set gateway.mode local
$ openclaw config set gateway.port 28789
$ openclaw config set gateway.bind loopback
$ openclaw config set gateway.auth.mode token
$ openclaw config set gateway.auth.token "$TOK" # 32 random characters
$ openclaw config validate
Config valid: ~/.openclaw/openclaw.json
Each command answered "Restart the gateway to apply." The file it produced, with the token redacted, is short:
{
"gateway": {
"mode": "local",
"port": 28789,
"bind": "loopback",
"auth": { "mode": "token", "token": "<REDACTED>" }
},
"meta": { "lastTouchedVersion": "2026.10.5" }
}
The real file also had a plugins block with two session-catalog settings and a meta.migrations block, which I left out here for length. Everything you need for a loopback, token-protected gateway fits in the four gateway keys above.
6. Step four: start it and measure what it costs
$ nohup openclaw gateway run > gateway.log 2>&1 &
time_to_listen_s=13.2
LISTEN 127.0.0.1:28789 (openclaw-gateway)
LISTEN [::1]:28789 (openclaw-gateway)
The port opened 13.2 seconds after I launched the command, polled every half second. The log reached [gateway] ready about one second after the HTTP server line, and the HTTP line itself reported 14 plugins loaded in 6.1 seconds. The gateway's first log line appeared several seconds after I launched the command, so a good part of the wait is the CLI starting up, before the gateway proper begins. If you put a health check in front of this, give it more than 15 seconds before you call it failed, and compare against the TimeoutStartSec=30 in the documented unit on your own plan.
Binding. It listened on 127.0.0.1 and on [::1] only. Nothing was reachable from another machine, which matches the documented default for a regular host install. The Linux page then tells you to reach it with ssh -N -L 18789:127.0.0.1:18789 user@host and open the local port. That is the access pattern I would use too.
Memory. One gateway process, no channels, no model provider and no sessions:
PID RSS (KiB) ELAPSED
467620 1024688 00:30
(same process, about two minutes later: 1008 MiB)
That is about 1,000 MiB resident for an idle gateway. It is one reading on one version, and it will grow once channels, a model provider and real sessions are attached. It is still enough to rule out the smallest 512 MB plans. For a real deployment I would not plan below 2 GB of RAM; that is my estimate from this reading plus headroom, not a measurement under load.
Health. openclaw health answered in 51 ms with an event-loop reading of max 23 ms and no sessions in the store. An HTTP request to /health returned {"ok":true,"status":"live"} with no token, and GET / returned 200 with security headers. I did not inspect what the root page serves, so I cannot tell you whether it exposes anything beyond the shell of the Control UI. If you put the gateway behind a reverse proxy, decide deliberately whether /health should be public. The Docker page also lists /healthz, /startupz and /readyz as no-auth container check endpoints; I only tried /health and the CLI command.
Ambient credentials. The shell I ran this from had Telegram credentials set as environment variables. The gateway did not use it. It logged suppressed ambient channel auto-configuration for 1 channel: telegram. Configure channels.<id> (openclaw channels add <id>) to enable the channel, or pass --ambient-channels to allow ambient env credentials. I am glad that is the default. A throwaway test gateway that silently adopted a production bot's token from the environment would be a bad afternoon. Do not pass --ambient-channels on a machine that holds credentials for anything else.
7. Step five: breaking it on purpose
Here is every failure I tried, what the command printed, and what it means for you. All of these are observed in my run.
| What I did | What happened | What I take from it |
|---|---|---|
Used a wrong token with openclaw gateway call health | unauthorized: gateway token mismatch (use this gateway's gateway.auth.token or pair the device) | Token auth rejects a bad token at the connect step. I only tested the CLI client, not a browser WebSocket. |
Started a second gateway run with the same state | Exit 78: Another gateway (pid 467620) already owns this state directory; refusing to run automatic startup migrations or report the gateway ready. | The guard is on the state directory, not on the port. Two gateways on different ports with the same state still collide, which is the safe behavior. |
Killed the gateway with kill -9, then restarted | Port freed at once. The restart was listening in 12.2 s and /health returned live. No repair command was needed. | A hard kill with no sessions in the store recovers cleanly. A busy gateway with in-flight work is a different test that I did not run. |
| Sent SIGTERM | Process gone in 1.0 s. Log: shutdown completed cleanly in 201ms. | A normal stop is fast when there is no work to drain. The documented unit allows far longer, see section 9. |
Ran openclaw gateway stop under my overridden HOME | Refused: This stops the operator's running gateway service. Use an isolated dev gateway ... or re-run with --force if you really mean it. | It appears to act on the service manager, not on a foreground process. I stopped the lab process by PID and did not use --force. |
Tried config set gateway.bind bogus | Config change declined. No settings were saved. It listed the allowed values: auto, lan, loopback, custom, tailnet. | Bad values are rejected before they reach the file. |
| Edited the port in the file to a string, then validated | gateway.port: Invalid input: expected number, received string, pointing at line 4, plus a pointer to openclaw doctor --fix. | Hand edits get a line number. I restored the file from a copy. |
The gateway stop result is the one I would have gotten wrong without reading it. My first attempt to stop the test process used a pgrep -f name pattern, and the pattern also matched my own shell, which ended that command with no output. I checked afterwards that nothing else on the machine had been touched, but I had been careless. Stop lab processes by the PID that owns the port, and never by a broad name match.
8. Step six: openclaw doctor changes things
Most health tools only read. I ran openclaw doctor --non-interactive expecting a report. Before it printed any warning, it printed this:
Doctor changes
- Installed missing configured plugin "brave" from @openclaw/brave-plugin@2026.10.5.
- Installed missing configured plugin "featherless" from @openclaw/featherless-provider@2026.10.5.
- Installed missing configured plugin "firecrawl" from @openclaw/firecrawl-plugin@2026.10.5.
- Installed missing configured plugin "tavily" from @openclaw/tavily-plugin@2026.10.5.
It had pulled four packages from npm; the lab state directory was 72 MB afterwards. I had not asked for any search or scraping plugin. The messages say "configured plugin", so these appear to come from default configuration, but I did not trace where. The practical point is simple: on a server with a locked-down outbound firewall or a change-control process, doctor is not a safe read-only check. Run it deliberately.
After the changes it printed warnings I found useful:
- Plaintext token.
openclaw.json contains plaintext secret-bearing config fields, naminggateway.auth.token. It suggestedopenclaw secrets configureto move it to a SecretRef, and warned that agents or workspace tools that can read config files may see the token. I set the token as a plain string, as most quick-start guides do, so this warning is about my own setup. - No command owner. It explained that the owner is the trusted operator account allowed to update OpenClaw, restart the gateway, change config and approve commands, and that you set it by completing a channel's setup.
- Loopback-only warning. A node-hosting check noted the gateway is bound only to loopback and pointed at
gateway.publicOriginand an edge-proxy fix for remote node onboarding. I have no remote nodes, so this was expected. - Startup hints for small hosts. It suggested setting
NODE_COMPILE_CACHEto a directory under/var/tmpandOPENCLAW_NO_RESPAWN=1to keep restarts in-process instead of handing off to a supervisor.
It also printed service management skipped: non-default state dir or config path, which is consistent with the gateway stop behavior above. It suggested openclaw security audit --deep. I did not run that, so I have nothing to report about what it finds.
9. What the documentation says that I did not test
These are vendor-reported claims, read on 22 October 2026. I link each page so you can check them against the current version.
| Topic | What the page says | Page |
|---|---|---|
| Systemd unit | A user unit at ~/.config/systemd/user/openclaw-gateway.service. The example sets Restart=always, RestartSec=5, RestartPreventExitStatus=78, TimeoutStartSec=30, TimeoutStopSec=330 (the five-minute cooperative drain plus teardown reserve), OOMPolicy=continue and KillMode=mixed. It says to write a unit by hand only for a custom setup, because hand-written units do not inherit the adaptive heap sizing that openclaw gateway install writes. | Linux server |
| Remote access | Reach the gateway from your laptop with ssh -N -L 18789:127.0.0.1:18789 <user>@<host>. Use HTTPS or wss:// for public direct connections; keep plain HTTP or ws:// to loopback, trusted private networks and Tailnet hosts. | Linux server |
| Auth | Token by default; password if gateway.auth.mode is set to "password". | Install |
| Trust boundary | One trust boundary per gateway. It is not a hostile multi-tenant boundary for mutually adversarial users who share one agent or gateway. | Security |
| Docker build | At least 6 GB RAM for a local source image build. Pre-built images avoid that requirement. | Docker |
| Install methods | Installer script, desktop apps, a local-prefix installer, npm/pnpm/bun, source build, standalone builds, and container platforms. | Install |
Containers bind differently from a host install. The security page says: "On a regular host install the Gateway binds to loopback", and then lists an exception: "container images default to an exposed bind (pair that with auth - see the exposure runbook)". The Docker page's own configuration example sets gateway.bind to lan. What I measured in section 6 is the host install, so it tells you nothing about a container. I did not run the Docker path. Before you publish a container port on a VPS, check how the port is published and what address the gateway listens on inside the container, and make sure auth is on. A successful install does not prove either one.
Two items in the unit line up with what I saw. The missing-config exit code of 78 is the one status the example refuses to restart on. And the 30 second start timeout is more than double my 13 second start on a busy 4 vCPU machine, which leaves room on that hardware but is worth testing on the cheapest plan you intend to use.
10. What I would do on a real server
This section is judgment, not measurement. It is what I would do with the evidence above and the documentation, and you should weigh it that way.
- Pin the version and the Node line. Install
openclaw@2026.10.5(or whichever version you validate), not@latest, and write the Node version into your runbook. The Node 22 failure shows a minor release can change the runtime requirement. - Keep the bind on loopback and use an SSH tunnel for the Control UI, as the documentation describes. Add a reverse proxy only when you have a reason, and then follow the docs' guidance on HTTPS and trusted-proxy auth.
- Move the token to a SecretRef before an agent with file tools exists on the box. The doctor warning gives the reason: anything that can read the config can read the token.
- Run it under a dedicated OS user, with nothing else of value in that user's home, and one gateway per trust boundary as the security page asks.
- Use the managed installer,
openclaw gateway install, instead of a hand-written unit. The documentation says hand-written units miss the adaptive heap sizing. Keep--ambient-channelsoff. - Budget at least 2 GB of RAM and 5 GB of disk for the gateway alone, plus whatever your channels and tools add. That is my estimate from one idle reading, not a sizing guarantee.
- Treat doctor as a change. Take a copy of the state directory first.
On cost, the server is the small part. Hetzner's cloud page, read on 22 October 2026, lists "Cost-Optimized" plans from €5.99 per month and "Regular Performance" plans from €6.49 per month, both excluding VAT. That page did not show vCPU or RAM, so I cannot map either price to a plan that fits the 2 GB estimate above; check the plan table before you buy. Your model provider bill is a separate line that I did not measure, and for most workloads it will be larger than the server.
11. What I did not test
A guide that hides its gaps is worse than no guide. This run did not cover:
- The Docker install, including the address it actually listens on (see section 9).
- The installer script, the
install-cli.shlocal-prefix installer, pnpm, bun and the desktop apps. - Installing and running the systemd service, including a restart under load.
- Any chat channel, model provider, agent turn, tool call, cron job or memory write. The session store had zero entries throughout.
- Exposing the gateway beyond loopback, with or without a reverse proxy.
openclaw security audit --deep, backups and restores, and upgrades from an older version.- Anything above one machine and one day. The behavior may differ on other versions.
For security history, the comparison post lists publicly disclosed vulnerabilities on both projects. I did not re-verify them here. If your agent will run long campaigns or calls, the failure-recovery questions in durable execution for voice and AI agent campaigns apply to anything you build on top of a gateway like this. And if you are weighing a self-hosted tool against a hosted workflow tool, the n8n self-hosting guide covers the same ownership trade-off.
12. When to hire help instead
Everything above takes an afternoon if you are comfortable with Linux, Node and systemd. The part that takes longer is what comes after: connecting channels, choosing a model and budget, restricting tools so an agent cannot do more than you intend, and deciding who gets paged when it stops. If you want that built and handed over with a runbook, my AI agents page describes how I work, and the ROI calculator and AI readiness assessment will help you decide whether it is worth doing at all. For broader planning, see consulting.
Frequently Asked Questions
What Node version does OpenClaw 2026.10.5 need?
Node 24.16 or newer in the 24 line, or Node 26.1 or newer. Node 22 fails at install time: npm ran the package's preinstall check and exited with 'this OpenClaw release requires Node >=24.16.0 <25 || >=26.1.0'. The documentation recommends Node 26.
How much memory does a self-hosted OpenClaw gateway use?
In my run, one gateway process with no channels, no model provider and no sessions held about 1,000 MiB resident at 30 seconds and 1,008 MiB two minutes later. That is one idle measurement on Node 24.22.1, not a load test. I would not plan below 2 GB of RAM for a real deployment.
Is it safe to expose the OpenClaw gateway to the internet?
The documentation says a regular host install binds to loopback and recommends reaching it through an SSH tunnel, with HTTPS or wss only for public connections. It also states that one gateway is one trust boundary and is not a security boundary between mutually untrusted users. I tested only the loopback and token-auth case.
How long does OpenClaw take to restart after a crash?
After I killed the gateway process with SIGKILL, the port was free immediately and a fresh start was listening 12.2 seconds later with no repair step. A normal SIGTERM stop took 1.0 second, and the log reported a clean shutdown in 201 ms. There were no sessions in the store, so this says nothing about recovering a busy gateway.
Does openclaw doctor only report problems?
No. Run non-interactively on a fresh state directory, it installed four plugin packages from npm before printing its warnings. Treat it as a command that changes the machine, and run it in a maintenance window rather than as a read-only check.
Ready to Get Started?
Book a free 30-minute discovery call. We'll identify your biggest opportunities and show you exactly what AI automation can do for your business.