Contents

OpenClaw Best Practices

OpenClaw is a personal-assistant trust model, not hostile multi-tenant SaaS. One Gateway maps to one operator boundary. Lock the official install, loopback, pairing, and allowlists first. Upgrades only matter if they can be rolled back.

The hard part is operational: official install path, who can reach the Gateway, whether skills / plugins / browser / nodes expand the blast radius, and whether a change can be validated and rolled back. What follows is the official baseline plus sanitized failures from real deployments.

The Short Version

The one page that matters:

  1. In production, prefer the official install flow plus openclaw onboard --install-daemon. Do not use ad-hoc source builds as the everyday upgrade path.
  2. One Gateway should map to one trust boundary. Personal assistants, team assistants, and public-facing bots should not share one high-privilege runtime.
  3. Keep gateway.bind: "loopback" by default. For remote access, prefer SSH tunnels or Tailscale Serve instead of directly listening on a public or LAN interface.
  4. Use dmPolicy: "pairing" for DMs, requireMention: true for groups, and session.dmScope: "per-channel-peer" when multiple people can message the bot.
  5. Treat skills and plugins as code execution surfaces. Use allowlists where possible, and pin versions when possible.
  6. Prefer openclaw update for upgrades, and always follow with openclaw doctor, openclaw gateway restart, and openclaw health.
  7. Health checks must go beyond “the process is alive.” Validate channel ingress, end-to-end messaging, log redaction, and session/state file permissions.

The Official Deployment Baseline

1. Installation and onboarding: start with the official path

The official docs are clear about the recommended bring-up flow:

curl -fsSL https://openclaw.ai/install.sh | bash
openclaw onboard --install-daemon
openclaw gateway status
openclaw dashboard

Three details matter here:

  1. Node 24 is the preferred runtime. Node 22.16+ is supported, but 24 remains the documented recommendation.
  2. openclaw onboard --install-daemon is the preferred setup path because it wires together models, gateway config, and common auth flows.
  3. A source checkout is much better suited for development and debugging than for routine production upgrades.

If the goal is a stable OpenClaw deployment rather than upstream development, avoid turning “a source build that happens to work” into the long-term operational baseline.

2. Define the trust boundary before scaling to multiple agents

OpenClaw’s official security model is not “hostile multi-tenant SaaS.” It is a personal-assistant model with a single trusted operator boundary.

That means:

  1. One Gateway is best used for one trusted operator boundary.
  2. With a personal assistant, a team assistant, and a public-facing assistant, split them into separate Gateways, or at minimum separate OS users and hosts.
  3. sessionKey, session labels, and channel bindings are routing mechanisms, not authorization boundaries.

This is where many deployments go wrong early. Per-user sessions help with context isolation, but they do not magically isolate high-impact tools, credentials, browser state, or host access.

3. Network exposure: default to loopback, then tunnel

The safest default in the docs is simple: keep the Gateway on loopback and expose it through a tunnel or tailnet, not a public bind.

A reasonable production starting point looks like this:

{
  "gateway": {
    "mode": "local",
    "bind": "loopback",
    "port": 18789,
    "auth": { "mode": "token", "token": "${OPENCLAW_GATEWAY_TOKEN}" }
  },
  "session": {
    "dmScope": "per-channel-peer"
  },
  "channels": {
    "telegram": {
      "dmPolicy": "pairing",
      "groups": {
        "*": { "requireMention": true }
      }
    }
  }
}

The important parts:

  1. gateway.bind: "loopback" is the default hardened posture.
  2. Explicitly set gateway.auth.mode: "token" or "password". Do not assume localhost is enough.
  3. A non-loopback bind also needs real auth and real firewalling.
  4. Behind a reverse proxy, configure gateway.trustedProxies correctly and make sure the proxy overwrites forwarding headers instead of appending untrusted ones.

From another machine, the simplest SSH tunnel remains:

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

Then keep the local CLI or UI pointed at ws://127.0.0.1:18789.

One subtle but important note from the docs: gateway.remote.token and gateway.remote.password are client-side credential sources for connecting to a remote Gateway. They do not configure server-side auth by themselves.

4. DMs, groups, and context isolation: start conservative

If the bot is not exclusively for one operator, resist the urge to start with everything open.

The official guidance is conservative for good reason:

  1. Use dmPolicy: "pairing" by default.
  2. Use requireMention: true by default in groups.
  3. If more than one person can DM the bot, use session.dmScope: "per-channel-peer".
  4. For stricter setups, add allowlists instead of letting trust depend on habit.

This is not only about security. It also improves debuggability. Many “the bot stopped replying” incidents turn out to be pairing, allowlist, or mention-gate behavior doing exactly what it was configured to do.

5. Skills, plugins, browser control, and nodes are all high-impact surfaces

OpenClaw is powerful, and power expands risk.

Several official security conclusions are worth treating as default assumptions:

  1. Skills and plugins should both be treated as code execution surfaces.
  2. Browser control is effectively operator access to whatever that browser profile can reach.
  3. A paired node with system.run is remote execution.
  4. Prompt guardrails are soft. The hard boundary comes from allowlists, tool policy, sandboxing, exec approvals, and host isolation.

In multi-agent deployments, it is worth explicitly assigning different access levels by agent:

  1. Personal high-privilege agent: private only, sandbox optional if the full trust boundary is owned.
  2. Team or family agent: sandboxed, read-only workspace, reduced tools.
  3. Public-facing agent: no filesystem, no shell, no browser, no cron, no gateway tool.

6. Config management: strict validation is a feature

OpenClaw config is schema-validated strictly. Unknown keys, wrong types, and invalid values can prevent the Gateway from starting.

Operationally, this is a good thing. It prevents “config was saved but only half of it actually worked.”

Recommended habits:

  1. When adding new config, check the official Configuration docs and schema.
  2. Run openclaw doctor after config changes.
  3. Know which changes hot-apply and which changes restart the Gateway. The default reload mode is currently hybrid.
  4. Avoid spreading long-lived configuration across ad-hoc shell flags.

Sanitized Lessons from Real Deployments

The following issues all came from real deployments, but only the reusable parts are preserved here.

1. Do not confuse the published bundle with the source tree

This was one of the most expensive mistakes operationally.

The pattern usually looks like this:

  1. A published release has a runtime bug.
  2. The source tree is inspected and the fix looks obvious.
  3. A local source build is pushed or tarball into production, and now there is new bundle-layout drift, missing runtime dependencies, or behavior that no longer matches the published release.

The root cause is simple: production runs the published artifact, not the working source tree. Bundle names, packaging boundaries, embedded dependencies, and plugin layout can differ.

The safer pattern is:

  1. If the issue is local to a published bundle, patch the working published artifact minimally, reversibly, and with a clear record.
  2. Move back to the official upgrade path once an upstream release contains the fix.
  3. Only adopt a source-checkout workflow if that machine is intentionally maintained as a self-managed build channel.

In short: when fixing production, target what production is actually running, not the most convenient source directory on a laptop.

2. A slash command can register successfully and still fail at runtime

Another recurring failure mode is when a skill appears in the slash-command surface, but executing it behaves as if the skill were missing.

The most common cause is a mismatch between command visibility and model visibility:

  1. user-invocable: true exposes the skill as a slash command.
  2. disable-model-invocation: true removes it from the model prompt.

If the command still depends on the model reading the SKILL.md instructions, the command is visible but unreliable.

The more stable approaches are:

  1. If the command is really a direct tool invocation, use command-dispatch: tool.
  2. If it still needs the model to read the skill instructions, do not hide it from the model prompt.
  3. Add end-to-end smoke tests for critical slash commands instead of only verifying that they appear in the command list.

3. A workspace skill being discovered does not mean the model received the full instructions

There is a second-order version of the same problem in some versions or custom runtimes: the skill is visible in the registry, but the runtime only gives the model a weak hint such as “use this skill,” instead of reliably injecting the actual SKILL.md body.

At that point, execution quality depends too heavily on model improvisation.

The practical lessons:

  1. Do not rely too much on “the model will probably read it later” for critical skills.
  2. If a skill must be deterministic, either dispatch directly to a tool or ensure the runtime really injects the skill content into the prompt.
  3. After changing a skill, prefer a new session or at least a reset instead of assuming the active session always picked up the new snapshot.

The official docs mention session snapshots and skill watchers. Hot reload exists, but for critical paths, “open a new session and verify once” is still the safer habit.

4. Containerized deployments drift quietly

A container starting successfully is only step one. The harder problem is configuration and runtime drift.

Typical issues:

  1. Host-fallback scenarios and sandbox scenarios get mixed into one compose file until it becomes impossible to reason about.
  2. Plugin paths point at source directories instead of compiled output directories, creating duplicate dependency or runtime conflicts.
  3. Bootstrap scripts do not pin the default model explicitly, so a stale .env or .env.example ends up winning.

The more stable pattern is:

  1. Keep the base docker-compose.yml as generic and sandbox-compatible as possible.
  2. Put host-specific differences into separate override files.
  3. In containers, point bundled plugins at compiled output, not source trees.
  4. Explicitly write critical defaults such as agents.defaults.model.primary instead of assuming template env files are always current.

5. Skill dependencies must be verified on both the host and the sandbox

The official Skills documentation contains an important nuance: requires.bins is evaluated on the host at load time, but if the agent actually runs inside a sandbox, the same binary must also exist inside the container.

That means:

  1. “The host has the command” does not mean “the sandboxed skill will work.”
  2. Missing container binaries often show up as skills that are visible but fail at execution time.
  3. The stable fix is to install required binaries through setupCommand or a custom sandbox image.

If a skill depends on both external binaries and network access, also validate sandbox network policy, filesystem writeability, and runtime user permissions.

6. Health checks cannot stop at “the Gateway process is alive”

This is another common misdiagnosis.

Seeing a green health endpoint, a healthy container, or a running daemon only proves one thing: the Gateway process exists.

For OpenClaw, a more trustworthy health model has four layers:

  1. Process layer: openclaw gateway status.
  2. Config layer: openclaw doctor.
  3. Channel layer: openclaw channels status --probe or the equivalent probe path.
  4. Business layer: send a real test message through a real channel and confirm routing plus reply path end to end.

Doing only the first two misses the failures that matter most in practice: expired tokens, broken channel sessions, allowlist mistakes, or mention-gate mistakes.

7. Logs, sessions, and state directories should all be treated as sensitive

The official docs are very explicit here: ~/.openclaw/ contains much more than “just config.” It may include auth profiles, pairing allowlists, session transcripts, channel credentials, secrets payloads, and sandbox workspaces.

At minimum:

  1. Keep ~/.openclaw at 700.
  2. Keep ~/.openclaw/openclaw.json at 600.
  3. Keep logging.redactSensitive: "tools" enabled.
  4. When sharing diagnostics, prefer sanitized outputs such as openclaw status --all instead of raw logs.
  5. On a shared machine, give OpenClaw its own OS user whenever possible.

Long-Term Skills and Plugin Maintenance

This is the layer most likely to devolve into chaos over time.

Be explicit about skill locations and precedence

The current official skill precedence is:

  1. <workspace>/skills
  2. <workspace>/.agents/skills
  3. ~/.agents/skills
  4. ~/.openclaw/skills
  5. bundled skills
  6. skills.load.extraDirs

Recommendation:

  1. Put project-specific skills in <workspace>/skills.
  2. Put machine-wide shared skills in ~/.agents/skills or ~/.openclaw/skills, but avoid duplicating the same skill name across both.
  3. Maintain clear ownership for critical skills so “same name, different copy” does not become an investigation nightmare.

Use agent allowlists to control visibility

A skill being discoverable is different from a skill being available to a given agent.

For public-facing or lower-trust agents, use explicit skill allowlists instead of letting them inherit everything by default.

Plugins deserve more caution than skills

Plugins have a larger blast radius than ordinary skills because they run in-process with the Gateway.

At minimum:

  1. Install only from trusted sources.
  2. Prefer exact version pinning over drifting ranges.
  3. Restart the Gateway after plugin installs or upgrades.
  4. Run openclaw security audit periodically to review plugin scanning and allowlist posture.

Upgrades, Rollbacks, and Change Management

The currently recommended upgrade path is:

openclaw update

It attempts to detect the install type, update accordingly, and run post-update checks. A more explicit human-driven workflow can be:

openclaw update --dry-run
openclaw update
openclaw doctor
openclaw gateway restart
openclaw health

Useful details:

  1. --dry-run is worth using to inspect the change before applying it.
  2. --channel beta and --tag beta are not the same. The former is a channel preference, the latter is closer to forcing a specific dist-tag.
  3. Auto-update is off by default. Whether to enable it in production depends on how tightly maintenance windows are controlled.

Plan rollback before it is needed

For an npm install, the official rollback path is straightforward:

npm i -g openclaw@<version>
openclaw doctor
openclaw gateway restart

Pinning to a source commit is something to keep for source-checkout deployments. In practice that means:

  1. npm or install-script deployments are a better fit for stable production plus version rollback.
  2. Source-checkout deployments are a better fit for self-managed development channels.
  3. Avoid switching back and forth between those two models on the same production host.

An Operations Checklist

A checklist that holds up:

Before launch

  1. Confirm the install path is officially supported, not an improvised source build.
  2. Confirm gateway.bind is still loopback, or that token/password auth, firewalling, and trusted proxy settings are correct.
  3. Confirm DMs are not wide open and group mention gating is enabled.
  4. Confirm skill and plugin sources are known and critical skills have smoke tests.
  5. Confirm browser automation uses a dedicated profile, not the personal daily browser.
  6. Run openclaw security audit.

After every update

  1. Run openclaw doctor.
  2. Run openclaw gateway restart.
  3. Run openclaw health.
  4. Run a channel probe.
  5. Send a real message through a real chat surface and verify the full round trip.

When something breaks

  1. Decide whether this is a process problem, config problem, channel problem, or application-logic problem.
  2. Do not blindly overwrite the live runtime. First diagnose the actual artifact that production is running.
  3. Use sanitized outputs when sharing diagnostics. Do not paste raw transcripts or credential paths by default.
  4. If exposure is suspected, return to loopback, tighten DM/group policy, and only then continue the investigation.

For a long-lived OpenClaw install, these official references are worth bookmarking:

  1. Getting Started
  2. Configuration
  3. Remote Access
  4. Security
  5. Skills
  6. Updating
  7. OpenClaw GitHub README

The real value of OpenClaw is not just that it connects an LLM to Telegram or WhatsApp. It is that it brings models, tools, channels, state, and automation into a runtime under local control.

That is also why it must be operated like a long-lived system instead of a toy chat integration:

  1. Hold the official install and update path steady.
  2. Hold the hard boundaries steady: loopback, pairing, mention gating, tool policy.
  3. Then expand into higher-capability surfaces such as skills, plugins, browser control, and nodes.

Those three layers make OpenClaw feel like a dependable self-hosted agent platform rather than an impressive but fragile experiment.