OpenClaw's official Docker Compose file publishes the gateway's port 18789 on every network interface of the host. On a laptop, that means anyone on the same café Wi-Fi can reach it. On a VPS, it means the whole internet can, and Ubuntu's ufw won't stop it, because Docker routes published ports around ufw's rules. The gateway still demands a token, but a token is then the only thing standing between strangers and an agent that runs shell commands.

The short answer: For most people, run OpenClaw with the official Docker setup on a small VPS (a 2 GB DigitalOcean Droplet is $12 a month in US or European regions; Hetzner's cheaper CX line was listed as unavailable on 2 October 2026), publish port 18789 only on 127.0.0.1, put a cloud firewall in front that admits SSH alone, and reach the Control UI through an SSH tunnel. Buy a Mac mini only if you need iMessage or a residential IP. Run Docker on your laptop to try it, not to depend on it. OpenClaw is safe enough for one trusted operator when the gateway is private, DMs require pairing, the image is pinned and updated, and skills are vetted — it is not built to separate people who don't trust each other.

OpenClaw hosting compared: Docker, VPS or Mac mini

Pick a VPS if the agent must answer while your laptop sleeps, a Mac mini if you need iMessage or a home IP for browser automation, and your own machine only for a trial. The trade-offs, from OpenClaw's docs and the vendors' price pages (checked 2 October 2026):

PathCost per month (2 Oct 2026)Stays up whenGets youCosts youDefault exposure
Docker on your laptop or desktop$0 extraThe machine is awakeLocal files, a visible browser, host Ollama via host.docker.internalStops on sleep, reboots and network drops; no iMessage from the Linux containerPort 18789 on every interface: your LAN or café Wi-Fi sees a token-protected gateway
VPS with Docker$12 (DigitalOcean 2 GB) to $24 (DigitalOcean 4 GB); Hostinger KVM 1 from $6.49 promoAlways, barring provider outagesA stable network, no sleep, SSH access from anywhereDatacenter IPs get blocked by many sites; headless browser; iMessage only via SSH to a MacPublic IP: the published port bypasses ufw unless a cloud firewall or DOCKER-USER rule blocks it
Mac mini or home server, native install$899 up front (≈$25/month over three years) plus $0.53–$9.36 of powerPower and home internet are up, sleep disablediMessage, a residential IP, macOS-only tools; can serve as a node for a VPS gatewayYou are the ops team; full iMessage features need SIP disabledBehind your router's NAT; Bonjour advertises the gateway on your LAN by default on macOS
Managed (Hostinger 1-Click OpenClaw)$5.99 promo, renews at $11.99 (term paid up front)The provider keeps it upFastest start; Hostinger runs Docker and updatesLess control over the image and update timingSet by the provider

Sources: OpenClaw's hosting FAQ, macOS VM page and Docker networking page; VPS prices as sourced in the VPS table below, plus DigitalOcean's Droplet pricing and Hostinger's OpenClaw page; the Mac mini price from Apple's announcement. The power range is my arithmetic: Apple's M6 Mac mini power figures (4 W idle, 70 W max) over 730 hours at 18.31¢/kWh, the July 2026 US residential average in EIA's Electric Power Monthly released 24 September 2026 (EIA table 5.6.A, which rolls forward to the latest month).

Decision rules:

  • You want it answering from your phone at 3 a.m. VPS. The hosting FAQ lists the laptop's cons plainly: sleep and network drops disconnect it, and OS updates and reboots interrupt it.
  • You want iMessage. OpenClaw iMessage needs a Mac signed into Messages. Either run the gateway on that Mac, or keep it on a VPS and point channels.imessage.cliPath at an SSH wrapper that runs imsg on the Mac.
  • Your agent browses sites that fight bots. OpenClaw's macOS VM page notes that many sites block datacenter IPs; a box at home browses from a residential one.
  • You're evaluating. Docker on the machine you already own, torn down afterwards.

This guide assumes you've already settled on OpenClaw. If you haven't, the OpenClaw alternatives roundup and the Hermes Agent vs OpenClaw comparison cover that choice.

OpenClaw Docker Compose setup, step by step

The official method is a script in the OpenClaw repo that pulls or builds the image, runs onboarding, writes a gateway token to .env and starts the stack with Docker Compose. Most commands below are quoted from OpenClaw's Docker guide or its Docker VM runtime page. The exceptions: the SSH tunnel comes from OpenClaw's Hetzner page, the Telegram pairing command from Simon Willison's TIL (sourced at Step 5), and the pinned image tag is my substitution for latest. I did not run the full setup for this article.

Prerequisites:

  • Docker Engine or Docker Desktop with Compose v2. Prefer Engine 28 or later: Docker's port publishing docs warn that in older releases, hosts on the same L2 segment can reach ports published to localhost.
  • 2 GB of RAM or more for the pre-built image (the FAQ's recommendation; 1 GB is the stated floor), or 6 GB if you build the image from source.
  • On a Debian or Ubuntu VPS, Docker comes from curl -fsSL https://get.docker.com | sh per the Hetzner guide.
  • Versions in this guide: OpenClaw 2026.9.7, the latest GitHub release as of 2 October 2026.

Step 0 (VPS only): firewall first. In your provider's cloud firewall, allow TCP 22 from your own network and nothing else. The Hetzner guide is explicit: no inbound rule for 18789, because you'll reach it through SSH. A cloud firewall sits outside the server, so Docker's port rules can't route around it.

Step 1: clone the repo and check versions.

bash
git clone https://github.com/openclaw/openclaw.git
cd openclaw
docker --version
docker compose version

Expect a Docker version line and a Compose version line starting with v2 or newer.

Step 2: pin the official OpenClaw Docker image and run setup. The docs show the moving latest tag. Pin a release instead; version tags are immutable. I confirmed 2026.9.7 resolves on GHCR on 2 October 2026.

bash
export OPENCLAW_IMAGE="ghcr.io/openclaw/openclaw:2026.9.7"
./scripts/docker/setup.sh

The script asks for your model provider key, generates a gateway token into .env, and starts the gateway. Use ghcr.io/openclaw/openclaw or its Docker Hub mirror openclaw/openclaw. OpenClaw's docs say to avoid unofficial mirrors — which includes two of the top search results for "openclaw docker", alpine/openclaw and phioranex/openclaw-docker. Older tutorials call ./docker-setup.sh; the maintained path is ./scripts/docker/setup.sh.

Step 3: verify the gateway.

bash
docker compose ps
docker compose logs --tail=100 openclaw-gateway
curl -fsS http://127.0.0.1:18789/healthz

A 200 from /healthz means the gateway process is listening. The image's built-in health check polls the same endpoint.

[AUTHOR: If you ran ./scripts/docker/setup.sh with the pinned 2026.9.7 image on a 2 GB VPS (such as the $12 DigitalOcean Droplet), how long did it take to reach a healthy gateway, and how much RAM did docker stats show after onboarding?]

Step 4: open the Control UI. On your own machine, open http://127.0.0.1:18789/ and paste the token from .env into Settings. On a VPS, open a tunnel from your laptop first and leave it running:

bash
ssh -N -L 18789:127.0.0.1:18789 root@<vps-ip>

Then browse to http://127.0.0.1:18789/ locally. If the browser shows pairing required, approve it on the server:

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

Step 5: connect a channel. Telegram is the shortest path: create a bot with @BotFather, then:

bash
docker compose run --rm openclaw-cli channels add --channel telegram --token "<token>"

Message the bot from your account. With the default pairing policy, it replies with a pairing code instead of processing your message; approve it with docker compose run --rm openclaw-cli pairing approve telegram <CODE>, the form in Simon Willison's OpenClaw Docker TIL. OpenClaw's Hostinger page gives the bare openclaw pairing approve telegram <CODE>; under Compose, CLI commands go through docker compose run --rm openclaw-cli. End state: a healthy gateway, a paired browser, a paired Telegram account.

Keep port 18789 private (the step most guides skip)

Docker publishes a port on all host addresses unless you name one, and the official Compose file names none. I checked this rather than assume it. On 2 October 2026 I ran docker compose config (Compose v5.1.2) against OpenClaw's docker-compose.yml from main: ports 18789, 18790 and 3978 rendered with no host_ip. Docker's bridge network docs define that as every IPv4 and IPv6 address on the host. Docker's firewall docs add that published-port traffic is diverted before ufw's rules see it.

Inside the container, the gateway has to bind to lan. OpenClaw's networking page warns that loopback there would lock the gateway inside the container. So don't paste the hardened baseline's bind: "loopback" into a Docker config — restrict the host side instead, in three layers:

1. A cloud firewall that admits only SSH (Step 0). This is the layer that survives everything below.

2. An override file that publishes on 127.0.0.1. Save this as docker-compose.override.yml next to docker-compose.yml:

yaml
services:
  openclaw-gateway:
    ports: !override
      - '127.0.0.1:18789:18789'
      - '127.0.0.1:18790:18790'

!override replaces the port list instead of appending to it (Compose merge docs; needs Compose 2.24.4+). With this file in place, the same docker compose config run rendered both ports with host_ip: 127.0.0.1 and dropped 3978. That port is the Microsoft Teams legacy webhook listener: current OpenClaw serves the Teams webhook on the gateway port at /api/messages, so new Teams setups don't need 3978. Keep it only for an existing install still on the legacy listener (Teams configuration). Port 18790 is the sandbox origin for MCP Apps, used only when you enable them.

Apply it with docker compose up -d openclaw-gateway. One trap: scripts/docker/setup.sh calls Compose with an explicit -f docker-compose.yml, which skips override files. In my docker compose config test, the explicit -f form rendered the all-interfaces ports again. So after any setup-script run, including updates, run docker compose up -d openclaw-gateway once more.

3. DOCKER-USER rules if you rely on ufw. OpenClaw's network exposure page ships a block for /etc/ufw/after.rules that drops new inbound connections to published ports except from private ranges and 80/443, plus a matching IPv6 note. Its verification step is the one to keep:

bash
nmap -sT -p 1-65535 <public-ip> --open

Run it from outside the server. Expect only port 22. If 18789 shows up, one of the layers above isn't in place.

What not to copy: IONOS's OpenClaw Docker tutorial (March 2026) tells readers to run ufw allow 18789/tcp and browse http://YOUR_SERVER_IP:18789. That puts the gateway token on the public internet over plain HTTP.

Is OpenClaw safe to self-host? What 722 advisories and the docs say

OpenClaw is safe enough for a single trusted operator who keeps the gateway private, pairs every sender, vets skills and updates often. It is not safe as a shared agent for people who don't trust each other, and the project says so: its trust model supports one trust boundary per gateway and points adversarial users to separate gateways, ideally separate OS users or hosts.

The advisory record. I pulled every published advisory from the OpenClaw GitHub security advisories on 2 October 2026: 722 in total, 14 rated critical, 249 high, 390 medium and 69 low. They arrive in batches:

Month (2026)Advisories published
January3
February220
March204
April108
May67
June45
July–August0
September75 (all on 11 September)

Read that as an actively audited project, not a finished one. The practical rule: pin a version and move it forward on a schedule, never run a months-old image.

Loopback alone doesn't save you. The January advisory GHSA-g8p2-7wf7-98mq was a one-click remote code execution: the Control UI accepted a gatewayUrl from the link and sent the stored token to it. The advisory states it was "exploitable even on instances configured to listen on loopback only," because the victim's browser made the outbound connection. Fixed in 2026.1.29. Private networking narrows the attack surface; updates close the holes in it.

Exposure is real. Censys counted 21,639 OpenClaw instances reachable from the internet on 31 January 2026, most still gated by a token (Censys).

Defaults worth knowing. From OpenClaw's security pages:

  • Gateway auth is on by default, and onboarding generates a token even for loopback.
  • Unknown DM senders get a pairing code; their message isn't processed. Pending requests cap at 3 per channel.
  • For the trusted owner, host exec runs without approval prompts by default (security="full", ask="off"). In Docker, that host is the gateway container, with your workspace mounted into it.
  • Unsandboxed agents can list and read every agent's sessions by default (tools.sessions.visibility is all).
  • Sandboxing is off by default, and the docs call it "not a perfect security boundary."

Hardening checklist, each item from the OpenClaw docs unless noted:

  1. Private port. The three layers above, Control UI over an SSH tunnel or Tailscale Serve.
  2. A long token. Generate one with openssl rand -hex 32. Gateway startup rejects blank and placeholder tokens, and the audit warns below 24 characters.
  3. Pairing or allowlists for DMs, mentions for groups. Keep dmPolicy: "pairing" and groups: { "*": { requireMention: true } }, as in the hardened baseline.
  4. Fewer tools wherever untrusted content flows in. For tool-enabled agents, the security FAQ says to keep web_search, web_fetch and browser off, and to have a read-only or tool-disabled "reader" agent summarize untrusted web pages, email or attachments. Prompt injection doesn't need a stranger to DM you.
  5. Sandbox with eyes open. OPENCLAW_SANDBOX=1 ./scripts/docker/setup.sh runs tool calls in sibling containers with no network, a read-only root and all capabilities dropped. To create them, the gateway container gets the host's Docker socket, and Docker's security docs say only trusted users should control the daemon. My read: the gateway container then has host-level reach.
  6. Treat skills and plugins as code you chose to run. The security FAQ says OpenClaw does no local dangerous-code blocking at install or update. Check the ClawHub audit status (Pass, Review, Warn, Malicious), pin versions, read the skill before enabling it.
  7. Guard the state directory. OAuth access and refresh tokens sit in plaintext SQLite under ~/.openclaw (Docker VM runtime). Back it up encrypted, and let security audit --fix tighten permissions to 600 files and 700 directories.
  8. Separate identities. Give the bot its own number, email and GitHub account so revoking it never touches yours.
  9. Audit after every change. docker compose run --rm openclaw-cli security audit --deep — the documented CLI command, run through the Compose CLI container.

For the agent-agnostic version of this list, see the AI agent security checklist.

Which VPS for OpenClaw, and how much RAM

Buy 2 GB of RAM or more on Ubuntu LTS, which is OpenClaw's recommendation; the 6 GB figure in its Docker guide applies only to building the image from source. The FAQ lists OpenClaw system requirements with an absolute floor of 1 vCPU, 1 GB RAM and about 500 MB of disk, and the DigitalOcean guide makes 1 GB work with a native install plus 2 GB of swap.

Prices checked 2 October 2026, monthly, before VAT:

PlanvCPU / RAM / diskPriceFits
Hetzner CX23 (Germany/Finland)2 / 4 GB / 40 GB$6.49 + $0.60 IPv4 = $7.09; not available on 2 Oct 2026Pre-built image
Hetzner CX33 (Germany/Finland)4 / 8 GB / 80 GB$9.99 + $0.60 = $10.59; not available on 2 Oct 2026Building from source
Hetzner CPX22 (Germany/Finland)2 / 4 GB / 80 GB$22.99 + $0.60 = $23.59Pre-built image
Hetzner CPX11 (US)2 / 2 GB / 40 GB$20.49 + $0.60 = $21.09Pre-built image, US location
DigitalOcean Basic 1 GB1 / 1 GB / 25 GB$6Native install with swap
DigitalOcean Basic 2 GB1 / 2 GB / 50 GB$12Pre-built image
DigitalOcean Basic 4 GB2 / 4 GB / 80 GB$24More headroom for browser and media tools
Hostinger KVM 11 / 4 GB / 50 GB$6.49 promo, renews $11.99Pre-built image, prepaid term
Hostinger KVM 22 / 8 GB / 100 GB$8.99 promo, renews $14.99Building from source

Hetzner's figures come from its 15 June 2026 price adjustment, which more than doubled some lines (CPX22 in Germany went from $9.49 to $22.99). CX23 and CX33 specs are from its Cost-Optimized page, which on 2 October 2026 marked every CX and CAX plan "not available" with the note "This product is currently unavailable. Please check back later." CPX specs are from its Regular Performance page, where those plans carried no such flag. Hostinger's promo prices require paying the term up front (Hostinger VPS pricing).

Picks for the best VPS for OpenClaw:

  • In Europe: DigitalOcean's $12 Droplet in Amsterdam, London or Frankfurt, or Hostinger's KVM 1 if you'll prepay. Hetzner's CX23 ($7.09) would be the cheaper fit, and Hetzner is the provider OpenClaw's own Docker VPS guide is written for, but the CX line was listed as unavailable on 2 October 2026. Hetzner's next plan with a published EU price, the CPX22, is $23.59.
  • In the US, cheapest: DigitalOcean's $12 plan with the pre-built image. Hetzner's US servers start at $21.09.
  • Hostinger VPS for OpenClaw: KVM 1 fits at the promo price; compare its $11.99 renewal with DigitalOcean's $12 before you prepay. Hostinger also sells an "OpenClaw on VPS" option that deploys the Docker setup for you and manages it from hPanel's Docker Manager.
  • Skip third-party 1-click images unless you've read their startup scripts and firewall defaults. OpenClaw's DigitalOcean guide gives that warning about Marketplace images.

Mac mini for OpenClaw: when the $899 box earns its place

A Mac mini is worth it for iMessage, a residential IP, or macOS-only tools; for everything else a $12 VPS does the job. OpenClaw's FAQ says you don't need one, and any Mac signed into Messages works for iMessage.

What the Mac path involves:

  • Native install, not Docker. iMessage runs through imsg on macOS, which the Debian-based container can't host. The installer, curl -fsSL https://openclaw.ai/install.sh | bash, provisions Node (24.16+ or 26.1+ is required) and starts onboarding; openclaw onboard --install-daemon or openclaw gateway install registers the LaunchAgent that keeps the gateway running (install docs).
  • macOS permissions. Messages signed in on that Mac, plus Full Disk Access and Automation for the process running OpenClaw and imsg (iMessage setup).
  • The SIP trade-off. Out of the box, imsg runs in basic mode: text and media in and out. Reactions, edits, threaded replies, effects and group management need its private API, which requires disabling System Integrity Protection (private API page). OpenClaw's own warning calls that "a real security tradeoff"; if you do it, give that Mac no other job.
  • Sleep. Turn off sleep in Energy settings. The macOS VM page also suggests caffeinate.
  • Bonjour. On macOS the gateway's mDNS advertising starts automatically, in minimal mode by default, which leaves out the CLI path and SSH port but still advertises the gateway. To stop it, set discovery.mdns.mode to "off" or set OPENCLAW_DISABLE_BONJOUR=1, unless you need LAN discovery.

The cheaper hybrid: keep the gateway on a VPS and pair a Mac you already own as a node for screen, camera and system.run, or reach its Messages through the SSH-wrapper cliPath. Power for a dedicated M6 Mac mini runs $0.53 a month at idle and $9.36 flat out at the July 2026 US average rate. The $899 hardware is the real cost.

Docker errors you'll actually hit

These come up repeatedly on the OpenClaw issue tracker. Each fix is from the docs.

  • disconnected (1008): pairing required (issue #4531, 36 comments). Each new browser must be approved with the devices list / devices approve pair from Step 4. If the CLI container can't reach the gateway, Simon Willison's OpenClaw Docker notes run the same command inside the gateway: docker compose exec openclaw-gateway node dist/index.js devices list.
  • EACCES: permission denied, open '/home/node/.openclaw/openclaw.json…' (issue #5434). The container runs as node, uid 1000, and your host folders are owned by someone else. Fix: sudo chown -R 1000:1000 /path/to/openclaw-config /path/to/openclaw-workspace (Compose operations).
  • origin not allowed (open the Control UI from the gateway host or allow it in gateway.controlUi.allowedOrigins) (issue #29809). The setup script allowlists http://localhost:18789 and http://127.0.0.1:18789, so open the UI through the SSH tunnel at one of those. A different address needs an exact match in gateway.controlUi.allowedOrigins, scheme and port included. The reporter in that issue had opened 18789 on a public IP; the tunnel fixes both problems.
  • Build ends with Killed or exit code 137. Out of memory during a source build. Move to 6 GB+ or use the pre-built image.
  • Your apt packages vanish after an update. Anything installed inside a running container is lost when the container is recreated. Bake packages in at build time instead: OPENCLAW_IMAGE_APT_PACKAGES="git curl jq" works when the setup script builds the image locally (the 6 GB path), or extend the repo's Dockerfile as the Docker VM runtime page describes.

Update, back up, roll back, remove

Update. Change OPENCLAW_IMAGE in .env to the new tag, then:

bash
docker compose pull openclaw-gateway openclaw-cli
docker compose up -d openclaw-gateway
docker compose run --rm openclaw-cli doctor --json

Don't rerun the setup script from an empty shell just to switch images: it rewrites .env from the current shell and defaults. On start, the new image runs openclaw doctor --fix against your state and saves <database>.pre-startup-migration-<id>.bak copies before schema changes.

Back up three host folders: ~/.openclaw, ~/.openclaw/workspace and ~/.openclaw-auth-profile-secrets. They hold credentials, so encrypt the copy.

Roll back by restoring the matching state from before the upgrade together with the old image tag. The docs warn that the old image alone isn't enough once a migration has run.

Remove it:

bash
docker compose down
docker image rm ghcr.io/openclaw/openclaw:2026.9.7

Then delete the three folders once you've kept a backup. Rotate the gateway token and every provider key and bot token it held, as OpenClaw's incident response page lists.

Where each path falls short (honest version)

This guide's limits. I didn't run OpenClaw for this article; the setup commands are quoted from the official docs, with the exceptions named at the top of the setup section. What I did run: rendering the Compose file with Docker Compose v5.1.2, pulling the advisory data from GitHub's API, and checking the image tag on GHCR. Prices and stock move — Hetzner repriced its cloud servers on 15 June 2026, and its cheapest line was unavailable when I checked.

Docker on a laptop is a demo, not a deployment: sleep kills it, and the default port is visible to whatever network you're on. A Mac mini costs $899 up front, depends on your home power and ISP, and full iMessage support means running it with SIP disabled.

A VPS trades your residential IP for uptime, and many sites block datacenter addresses, so browser-heavy agents suffer. You also own patching for Ubuntu, Docker and OpenClaw.

OpenClaw itself moves fast. 722 advisories published since 31 January 2026 means updates you can't defer for long, and its security model trusts everyone who can message the agent with everything the agent can do.

If you'd rather not run a box at all

I make Octomind, so weigh this accordingly. It isn't OpenClaw: no iMessage, no ClawHub skills, a different agent runtime. What it removes is the hosting work. Octos are agents that each get their own folder, memory, conversations and routines on a cloud machine we operate, reachable from Telegram, WhatsApp, Slack, Discord, email and GitHub. If you already run OpenClaw, the Import page takes your .openclaw folder and brings the persona, memories, skills, cron jobs and Telegram bot over in one step (how the import works). Each machine runs under sysbox in its own user namespace, so root inside is nobody on the host. Models come through the built-in gateway with no API keys to manage.

The honest limits: an octo sleeps after an hour idle by default and wakes on your next message or a routine, so the first reply after a quiet spell waits for the machine to wake (you can keep a machine always on; idle, it costs only its memory, about $18 a month on Small). Octos on the same machine share a container, so a folder isn't a security wall between them. There's no free cloud tier: Pro is $50 a month, $20 the first month.

Start with Pro — octos on a cloud machine we operate, no VPS to set up.

FAQ

Is OpenClaw safe to self-host?

OpenClaw is safe enough for one trusted operator who keeps the gateway private, requires pairing for DMs, pins and updates the image, and vets skills before installing them. The project had published 722 security advisories by 2 October 2026, so a months-old image is a known risk. It isn't designed as a boundary between users who don't trust each other; those need separate gateways. Run openclaw security audit --deep after every config change.

Does OpenClaw need Docker?

No. OpenClaw's docs call Docker optional and recommend the regular installer (curl -fsSL https://openclaw.ai/install.sh | bash) for your own machine. Docker suits a VPS or a throwaway trial because it isolates the gateway and makes upgrades a tag change. Use the native install on a Mac if you need iMessage, which can't run inside the Linux container.

What are the minimum requirements for an OpenClaw VPS?

OpenClaw's FAQ lists 1 vCPU, 1 GB of RAM and about 500 MB of disk as the floor, with 2 GB or more recommended, on Ubuntu LTS. The pre-built Docker image avoids the 6 GB of RAM a source build needs. A DigitalOcean 2 GB Droplet ($12 a month) or Hostinger's KVM 1 ($6.49 promo, $11.99 on renewal) covers the pre-built image, at prices checked 2 October 2026; Hetzner's $7.09 CX23 was listed as unavailable that day.

Do I need a Mac mini for OpenClaw?

No. OpenClaw runs on Linux, macOS and Windows; a Mac is only required for macOS-only features such as iMessage. Any Mac signed into Messages works, either as the gateway host or reached over SSH from a gateway on a VPS. A Mac mini also gives browser automation a residential IP, which many sites block less than datacenter addresses.

Should I open port 18789 in my firewall?

No. Keep port 18789 closed to the internet and reach the Control UI through an SSH tunnel (ssh -N -L 18789:127.0.0.1:18789 user@host) or Tailscale Serve. With Docker, also publish the port on 127.0.0.1 only, because Docker-published ports bypass ufw. OpenClaw's exposure runbook treats direct public port-forwarding as something to avoid.