{"id":6140,"date":"2026-09-03T22:20:51","date_gmt":"2026-09-03T13:20:51","guid":{"rendered":"https:\/\/eternalsphere.net\/echoes\/?p=6140"},"modified":"2026-09-12T17:17:13","modified_gmt":"2026-09-12T08:17:13","slug":"f5b3wbx1yqnk651","status":"publish","type":"post","link":"https:\/\/blog.eternalsphere.net\/index.php\/2026\/09\/03\/f5b3wbx1yqnk651\/","title":{"rendered":"Upgrading OpenClaw Safely: Capability Consent, systemd User Services, Loopback Binding, and FRP Reverse Proxying"},"content":{"rendered":"\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><strong>Privacy note:<\/strong> All hostnames, usernames, IP addresses, ports, domain names, paths, plugin deployment details, and other potentially identifying information in this article have been replaced with fictional examples. Values such as <code>Orion<\/code>, <code>Proxy-A<\/code>, <code>192.168.50.25<\/code>, <code>example.net<\/code>, and port <code>28473<\/code> do not correspond to any real environment.<\/p>\n<\/blockquote>\n\n\n\n<h2 class=\"wp-block-heading\">Introduction<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">An OpenClaw upgrade can look deceptively simple:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>openclaw update\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">In practice, however, a major or feature-heavy release may touch far more than the npm package itself. Depending on the installation, an upgrade can involve:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>package replacement;<\/li>\n\n\n\n<li>configuration migration;<\/li>\n\n\n\n<li>state database migration;<\/li>\n\n\n\n<li>plugin updates;<\/li>\n\n\n\n<li>plugin capability approval;<\/li>\n\n\n\n<li>systemd service management;<\/li>\n\n\n\n<li>Gateway restart and validation;<\/li>\n\n\n\n<li>security diagnostics;<\/li>\n\n\n\n<li>automation compatibility checks;<\/li>\n\n\n\n<li>network exposure warnings.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">A real upgrade from an older stable release to a newer 2026.8.x release provides a useful example of how these pieces interact.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The deployment discussed here uses an ARM64 Ubuntu server running OpenClaw Gateway, with public access provided through FRP and a separate Nginx reverse proxy.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The final architecture is intentionally designed so that OpenClaw itself listens only on localhost.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Internet\n   \u2502\n   \u2502 HTTPS\n   \u25bc\nNginx reverse proxy\n   \u2502\n   \u25bc\nFRPS\n   \u2502\n   \u2502 FRP tunnel\n   \u25bc\nFRPC\n   \u2502\n   \u25bc\n127.0.0.1:28473\n   \u2502\n   \u25bc\nOpenClaw Gateway\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This setup becomes particularly relevant when interpreting OpenClaw Doctor warnings after the upgrade.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">1. Checking the Update Before Installing It<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The existing installation was managed through npm rather than a Git checkout.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The update status can be checked with:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>openclaw update status\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">A typical result may resemble:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Install  npm\nChannel  stable\nUpdate   available \u00b7 npm \u00b7 npm update 2026.8.2\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The existing version in this example was an earlier 2026.7.x build, while the stable channel offered 2026.8.2.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For an npm-managed OpenClaw installation, the preferred upgrade command is:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>openclaw update\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This is preferable to manually replacing the global npm package because the OpenClaw updater performs application-specific work around the package update.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Conceptually, the upgrade workflow is closer to:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Stop Gateway\n      \u2502\n      \u25bc\nUpdate package\n      \u2502\n      \u25bc\nMigrate configuration\n      \u2502\n      \u25bc\nMigrate state\n      \u2502\n      \u25bc\nUpdate plugins\n      \u2502\n      \u25bc\nRun Doctor checks\n      \u2502\n      \u25bc\nRestart Gateway\n      \u2502\n      \u25bc\nVerify Gateway health\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The updater therefore acts as an application migration mechanism, not merely a wrapper around npm.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">2. Confirming That the Core Upgrade Succeeded<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A successful upgrade should explicitly report a successful result.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Typical output includes:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Updating OpenClaw...\n\nStopping managed gateway service before package update...\n\n\u2713 Updating via package manager\n\u2713 Running doctor checks\n\nUpdate Result: OK\nBefore: 2026.7.x\nAfter:  2026.8.2\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">At the end of the process, the updater should also restore the Gateway:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Restarting service...\nGateway: restarted and verified.\nDaemon restart completed.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">These lines are much more important than incidental Doctor warnings.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">They establish that:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>the target package was installed;<\/li>\n\n\n\n<li>the application migration phase completed;<\/li>\n\n\n\n<li>the managed Gateway restarted;<\/li>\n\n\n\n<li>OpenClaw verified that the Gateway came back online.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">An upgrade can therefore be successful even if Doctor subsequently reports configuration recommendations.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">3. The Unexpected Part: Plugin Capability Consent<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The most interesting issue during this upgrade involved plugins.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Some plugins produced prompts similar to:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Plugin capabilities require approval\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">OpenClaw then displayed information such as:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Tools:\n  tool_a\n  tool_b\n\nContracts:\n  tools\n  webSearchProviders\n  migrationProviders\n\nPrompt injection: allowed\nConversation access: denied\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">followed by:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Accept these capabilities and update \"plugin-name\"? &#091;y\/N]\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This is the <strong>Capability Consent<\/strong> system.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It is important to understand what this means, because it can initially look as though OpenClaw has unexpectedly disabled an existing plugin.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">4. What Capability Consent Actually Means<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Capability Consent is an OpenClaw-level plugin security mechanism.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It is not the same thing as Linux permissions such as:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>chmod\nsudo\nsudoers\nsetcap\nPOSIX capabilities\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Instead, it concerns what an OpenClaw plugin declares that it can provide or interact with.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Depending on the plugin, capabilities may include:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>registering tools;<\/li>\n\n\n\n<li>providing model backends;<\/li>\n\n\n\n<li>implementing web search;<\/li>\n\n\n\n<li>integrating with messaging systems;<\/li>\n\n\n\n<li>participating in migration workflows;<\/li>\n\n\n\n<li>handling media;<\/li>\n\n\n\n<li>exposing plugin-specific commands.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Conceptually:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Plugin package\n     \u2502\n     \u25bc\nPlugin manifest\n     \u2502\n     \u25bc\nDeclared capability surface\n     \u2502\n     \u25bc\nAdministrator approval\n     \u2502\n     \u25bc\nConsent record\n     \u2502\n     \u25bc\nPlugin can operate with those capabilities\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The important distinction is that <strong>plugin activation and capability approval are separate concepts<\/strong>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">5. Why an Existing Enabled Plugin May Suddenly Require Consent<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Suppose a plugin was already enabled in the older release.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Its historical state might have looked roughly like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>plugin.enabled = true\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">but the older OpenClaw version may not have stored the newer form of capability-consent metadata.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">After upgrading, the state can effectively become:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>plugin.enabled = true\ncapability consent = missing or outdated\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Doctor may then report:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>WARN plugin-name:\nPlugin requires capability consent\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This does <strong>not automatically mean the plugin had previously been disabled<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It can simply mean that the plugin is configured and installed, but the newer OpenClaw release expects an explicit approval record that the older installation did not contain.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This distinction is important:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Enabled state\n     \u2260\nCapability approval state\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">6. Why the Repair Command Still Says <code>plugins enable<\/code><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Doctor may recommend:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>openclaw plugins enable model-provider-plugin --accept-capabilities\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">or:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>openclaw plugins enable messaging-plugin --accept-capabilities\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The command name can be misleading when the plugin was already enabled.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For an existing plugin, the effective operation may be:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Keep plugin enabled\n        +\nRecord capability consent\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">rather than:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Disabled\n   \u2193\nEnabled\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The CLI may still print:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Enabled plugin \"plugin-name\".\nRestart the gateway to apply.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">That output reflects the command being executed; it does not prove the plugin was disabled before the command ran.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">7. Why Capability Consent Should Not Be Blindly Permanent<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">This mechanism exists for a good security reason.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Consider a plugin that originally requested:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Capability A\nCapability B\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">An administrator approves those capabilities.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A later version could request:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Capability A\nCapability B\nCapability C\nCapability D\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If OpenClaw treated historical trust in the plugin name as permanent approval for every future version, the plugin could silently expand its access after an update.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A safer model is:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Previously approved capabilities\n            \u2502\n            \u25bc\n        Plugin update\n            \u2502\n            \u25bc\nCompare declared capabilities\n            \u2502\n        \u250c\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2510\n        \u2502        \u2502\n   unchanged   expanded\n        \u2502        \u2502\n        \u25bc        \u25bc\n reuse old    request\n consent      approval\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Capability Consent therefore represents approval of the plugin&#8217;s <strong>current declared capability surface<\/strong>, not unconditional trust in all future versions.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This is also why capability prompts during an upgrade should be read rather than accepted mechanically.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">8. Restarting the Gateway After Plugin Approval<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">After accepting capabilities, OpenClaw may say:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Enabled plugin \"model-provider-plugin\".\nRestart the gateway to apply.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The approval has been stored, but the running Gateway process still has the previous plugin state loaded.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The expected sequence is:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Write plugin consent\n       \u2502\n       \u25bc\nRestart Gateway\n       \u2502\n       \u25bc\nReload OpenClaw configuration\n       \u2502\n       \u25bc\nReload plugin registry\n       \u2502\n       \u25bc\nPlugin becomes active under approved capabilities\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">At this stage, a common systemd-related mistake can occur.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">9. <code>systemctl<\/code> Reports That the Gateway Service Does Not Exist<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A natural command is:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>systemctl restart openclaw-gateway.service\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">but the result may be:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Failed to restart openclaw-gateway.service:\nUnit openclaw-gateway.service not found.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The immediate assumption might be that the upgrade deleted the service.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That assumption can be wrong.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The real issue may be that OpenClaw Gateway is installed as a <strong>systemd user service<\/strong>, not a system-wide service.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">10. systemd System Services and User Services Are Different<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A standard system service is commonly managed with:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>systemctl status service-name\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">and is often defined under locations such as:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/etc\/systemd\/system\/\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">A user service is commonly defined under:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>~\/.config\/systemd\/user\/\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">and managed with:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>systemctl --user status service-name\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">For this OpenClaw installation, the correct commands are:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>systemctl --user restart openclaw-gateway.service\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">and:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>systemctl --user status openclaw-gateway.service\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">A healthy status should contain something similar to:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Loaded: loaded\nActive: active (running)\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This explains why plain <code>systemctl<\/code> can report that the service does not exist while OpenClaw itself successfully stops and restarts the Gateway during an upgrade.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The commands are querying different systemd namespaces.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>systemctl\n    \u2502\n    \u2514\u2500\u2500 system services\n\nsystemctl --user\n    \u2502\n    \u2514\u2500\u2500 per-user services\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">11. Do Not Create a Second Gateway Service<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">One particularly dangerous response to:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Unit openclaw-gateway.service not found\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">would be to manually create a new system-wide unit under:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/etc\/systemd\/system\/openclaw-gateway.service\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">without first checking whether a user service already exists.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That could result in:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>system-level Gateway\n        +\nuser-level Gateway\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Both processes might attempt to use the same listening port.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Possible results include:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Address already in use\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">or a much more confusing situation where:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>systemctl restart openclaw-gateway\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">controls one process while:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>systemctl --user restart openclaw-gateway\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">controls another.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The safer diagnostic order is:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>systemctl --user status openclaw-gateway.service\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">before creating any replacement service.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">12. Re-running Doctor After the Restart<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Once capability consent has been accepted and the correct Gateway service has restarted, Doctor should be run again:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>openclaw doctor\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This second run is important because several migrations may only complete during or after a successful Gateway startup.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In this case, warnings related to plugin capability approval disappeared after restart.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Some legacy state warnings also disappeared automatically.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That is exactly the behavior expected from a migration-aware upgrade process.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">13. Legacy State Migration Should Be Allowed to Finish Automatically<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">During the first Doctor run after a major upgrade, messages such as these may appear:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Auto-migrated legacy state\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">or:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Legacy device pairing store has not been imported yet\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The temptation may be to manually move, delete, or rewrite the old files.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That should generally be avoided initially.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If OpenClaw explicitly says the Gateway will import the state at startup, the preferred process is:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Leave legacy state untouched\n         \u2502\n         \u25bc\nRestart Gateway normally\n         \u2502\n         \u25bc\nAllow migration code to run\n         \u2502\n         \u25bc\nRun Doctor again\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If the warning disappears, the migration succeeded.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A useful rule is:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">When an application provides an official state-migration path, allow that mechanism to run before manually editing legacy state.<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Manual SQLite modification, file deletion, or forced cleanup should be a later troubleshooting step, not the first response.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">14. The Loopback Warning<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">After the upgrade, Doctor may still report:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Gateway is only bound to loopback.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">and recommend something such as:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Set gateway.bind=lan\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">In isolation, that warning can suggest that external access will not work.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">However, the deployment architecture matters.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">OpenClaw in this example is intentionally listening only on:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>127.0.0.1:28473\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Yet the public HTTPS domain remains fully accessible.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">There is no contradiction because FRPC runs locally on the same machine.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">15. How a Loopback-Only Gateway Can Still Be Publicly Accessible<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A process listening on:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>127.0.0.1:28473\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">cannot normally be reached directly from another LAN machine using:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>192.168.50.25:28473\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">But a local FRPC process can connect to:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>127.0.0.1:28473\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">because FRPC is running on the same host.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">FRPC then carries that connection through its outbound FRP tunnel.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The effective request path is:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Internet\n   \u2502\n   \u2502 HTTPS\n   \u25bc\nNginx\n   \u2502\n   \u25bc\nFRPS\n   \u2502\n   \u2502 FRP tunnel\n   \u25bc\nFRPC\n   \u2502\n   \u2502 localhost connection\n   \u25bc\nOpenClaw Gateway\n127.0.0.1:28473\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The remote reverse-proxy machine therefore does not directly connect to the private server&#8217;s LAN address.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Instead, traffic reaches OpenClaw through the tunnel established by FRPC.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">16. Why Loopback Binding Can Be Preferable<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In this architecture, changing OpenClaw from:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>127.0.0.1\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">to:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>0.0.0.0\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">merely to silence Doctor would provide little benefit and could increase exposure.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The existing arrangement limits direct access:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>OpenClaw Gateway\n      \u2502\n      \u2502 localhost only\n      \u25bc\n     FRPC\n      \u2502\n      \u25bc\n  FRP tunnel\n      \u2502\n      \u25bc\n     FRPS\n      \u2502\n      \u25bc\n    Nginx\n      \u2502\n      \u25bc\n   Internet\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Other LAN hosts do not need direct access to the Gateway port.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This creates a useful isolation boundary.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The Doctor warning is therefore better interpreted as:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">OpenClaw observes that the Gateway is not listening on a LAN-facing interface.<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">It does <strong>not<\/strong> necessarily mean:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">External access is broken.<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">OpenClaw&#8217;s diagnostic tool cannot automatically know every external tunneling architecture surrounding the process.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">17. The Role of FRP and Nginx<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">FRP and Nginx perform different functions.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">FRP<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">FRP provides transport between an internal service and a remote reachable endpoint.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Private service\n     \u2502\n     \u25bc\nFRPC\n     \u2502\n     \u25bc\nFRP tunnel\n     \u2502\n     \u25bc\nFRPS\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Nginx<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Nginx handles the public HTTP layer:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>TLS termination;<\/li>\n\n\n\n<li>HTTPS;<\/li>\n\n\n\n<li>domain names;<\/li>\n\n\n\n<li>HTTP proxying;<\/li>\n\n\n\n<li>WebSocket forwarding;<\/li>\n\n\n\n<li>request headers;<\/li>\n\n\n\n<li>certificate management.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The complete architecture therefore becomes:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Browser\n   \u2502\n   \u2502 HTTPS\n   \u25bc\nNginx\n   \u2502\n   \u2502 HTTP \/ WebSocket\n   \u25bc\nFRPS\n   \u2502\n   \u2502 FRP\n   \u25bc\nFRPC\n   \u2502\n   \u2502 localhost\n   \u25bc\nOpenClaw Gateway\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This separates responsibilities cleanly:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>OpenClaw runs the application;<\/li>\n\n\n\n<li>FRP provides transport;<\/li>\n\n\n\n<li>Nginx provides the public HTTPS endpoint.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">18. Not Every Doctor Warning Is a Fault<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">One of the most important lessons from this upgrade is that Doctor should not be treated as a list in which every warning must be eliminated.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">OpenClaw Doctor acts more like a combination of:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Health checker\nConfiguration auditor\nMigration advisor\nSecurity advisor\nPerformance advisor\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Some findings are real errors.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Others merely describe the current architecture.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">19. Startup Optimization Recommendations<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">On a small ARM server, Doctor may report:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>NODE_COMPILE_CACHE is not set\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">or:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>OPENCLAW_NO_RESPAWN is not set to 1\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">These are performance recommendations.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">They may be useful on:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Raspberry Pi-class devices;<\/li>\n\n\n\n<li>ARM SBCs;<\/li>\n\n\n\n<li>small VMs;<\/li>\n\n\n\n<li>systems with relatively slow storage.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">However, they are not indications that the OpenClaw upgrade failed.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If the Gateway remains responsive and the machine has healthy CPU, memory, storage, and thermal conditions, these settings can be reviewed separately rather than changed during the upgrade itself.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">20. State Stored on SD or eMMC<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Doctor may also detect that OpenClaw state resides on SD or eMMC storage.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">OpenClaw state may contain:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SQLite databases\nSession data\nAgent state\nPlugin state\nAutomation state\nLogs\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">These workloads may involve frequent small writes and random I\/O.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For long-term deployments, storage such as:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SSD\nNVMe\nUSB SSD\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">may provide better performance and durability.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Still, this is a storage recommendation rather than an update failure.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The distinction matters:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Durability recommendation\n          \u2260\nApplication malfunction\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">21. OpenClaw Backup Warnings<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Doctor may report:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>No successful backup is recorded.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This specifically refers to OpenClaw&#8217;s own backup subsystem.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It should not automatically be interpreted as:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">This server has no backup.<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">The system may already be protected through:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>full disk images;<\/li>\n\n\n\n<li>filesystem snapshots;<\/li>\n\n\n\n<li>ZFS or Btrfs snapshots;<\/li>\n\n\n\n<li>rsync;<\/li>\n\n\n\n<li>external backup software;<\/li>\n\n\n\n<li>VM or hypervisor backups.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Application-level backup status and infrastructure-level backup status are separate concepts.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">22. Command Owner Configuration<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Another possible Doctor message is:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>No command owner is configured.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">A command owner is the account allowed to perform privileged OpenClaw actions through supported messaging channels.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Examples may include:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/diagnostics\n\/export-session\n\/export-trajectory\n\/config\nexec approvals\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This does not mean ordinary conversations are broken.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It means OpenClaw has not been explicitly told which external messaging identity should be considered the privileged operator.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If administrative commands are not being issued through chat integrations, this warning may not require immediate action.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">23. Messaging Pairing Is Separate From Plugin Capability Consent<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A messaging integration may separately report:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>DM policy = pairing\nNo admitted senders\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This is unrelated to plugin Capability Consent.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The two security relationships are different.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Plugin Capability Consent:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Administrator\n      \u2502\n      \u25bc\nPlugin capabilities\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Messaging pairing:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>External sender\n      \u2502\n      \u25bc\nBot access\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The first controls what the plugin may do inside OpenClaw.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The second controls which users may communicate with the messaging integration.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Confusing these two layers can lead to unnecessary configuration changes.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">24. Browser Relay Legacy Authentication<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Doctor may also report that legacy Browser Relay authentication remains enabled.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A configuration may contain something conceptually similar to:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>allowLegacyAuth=true\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">while the newer release recommends Authentication v2.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The safe migration order is:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Upgrade browser extension \/ CDP clients\n              \u2502\n              \u25bc\nConfirm Authentication v2 support\n              \u2502\n              \u25bc\nTest all existing clients\n              \u2502\n              \u25bc\nDisable legacy authentication\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Disabling compatibility mode before clients have migrated can break otherwise working integrations.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Again, the correct objective is not simply to remove the warning.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The objective is to migrate without causing a service interruption.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">25. Legacy Automation Warnings<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Existing automation jobs may retain older authorization semantics after an upgrade.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Doctor may describe them as using:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>legacy sender-policy resolution\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">while also saying that they:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>keep running as-is\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">or that the finding is:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>informational only\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This means the automation is not necessarily broken.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It simply has not yet been migrated to a newer authorization model.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A safer maintenance strategy is:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Upgrade OpenClaw\n      \u2502\n      \u25bc\nVerify Gateway stability\n      \u2502\n      \u25bc\nObserve existing automations\n      \u2502\n      \u25bc\nMigrate legacy automation policies separately\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Combining an application upgrade, plugin migration, security-policy redesign, automation rewrite, storage migration, and network redesign into one maintenance window makes troubleshooting unnecessarily difficult.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">26. Final Upgrade Verification<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The upgrade should not be considered complete based solely on the absence of an error during <code>openclaw update<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A useful final verification sequence is:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>openclaw --version\nopenclaw update status\nsystemctl --user is-active openclaw-gateway.service\nsystemctl --user is-enabled openclaw-gateway.service\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">A healthy result should conceptually show:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>OpenClaw 2026.8.2\n\nUpdate:\nnpm \u00b7 up to date \u00b7 npm latest 2026.8.2\n\nactive\n\nenabled\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Then run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>openclaw doctor\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The important question is not whether Doctor contains zero warnings.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The important questions are:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Did Doctor complete?<\/li>\n\n\n\n<li>Are there any fatal errors?<\/li>\n\n\n\n<li>Is Gateway running?<\/li>\n\n\n\n<li>Are required plugins loading?<\/li>\n\n\n\n<li>Did migration warnings disappear after restart?<\/li>\n\n\n\n<li>Is the public application still reachable?<\/li>\n\n\n\n<li>Are existing automations still operational?<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">If those checks succeed, the upgrade can reasonably be considered complete.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">27. A Recommended OpenClaw Upgrade Workflow<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A disciplined upgrade process can be summarized as follows.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 1: Record the current version<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>openclaw --version\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Step 2: Check the stable channel<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>openclaw update status\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Step 3: Perform the managed update<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>openclaw update\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Step 4: Review plugin capability prompts<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Before answering <code>y<\/code>, examine:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Tools\nContracts\nConversation access\nPrompt injection\nNew capabilities\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Step 5: Run Doctor<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>openclaw doctor\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Step 6: Resolve missing capability consent only where appropriate<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">For example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>openclaw plugins enable example-plugin --accept-capabilities\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Step 7: Restart the correct systemd service<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">For a user-level OpenClaw installation:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>systemctl --user restart openclaw-gateway.service\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Step 8: Run Doctor again<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>openclaw doctor\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This allows startup-time migrations to complete.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 9: Perform final verification<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>openclaw --version\nopenclaw update status\nsystemctl --user is-active openclaw-gateway.service\nsystemctl --user is-enabled openclaw-gateway.service\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">28. What Should Not Be Done Merely to Silence Doctor<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Several changes should not be made solely because Doctor displays a warning.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Do not expose Gateway to the LAN without a reason<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">If the architecture intentionally uses:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>OpenClaw\n   \u2502\nlocalhost\n   \u2502\nFRPC\n   \u2502\nFRPS\n   \u2502\nNginx\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">then loopback binding may be preferable.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Do not enable unused features<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">If Host Desktop is disabled because the server is headless, there is no reason to enable it merely to make diagnostics quieter.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Do not enable Memory Search unless it is actually wanted<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">An explicit:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>enabled: false\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">is a configuration choice, not a malfunction.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Do not create a system-level Gateway service before checking user services<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">A duplicate service can cause port conflicts and difficult-to-debug process management.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Do not delete legacy state before allowing automatic migration<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The first post-upgrade warning may disappear naturally after the next Gateway startup.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Do not disable legacy authentication until every client supports the replacement<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Compatibility warnings often describe a migration path, not an emergency.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">29. Key Lessons<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">This upgrade provides several reusable operational lessons.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Plugin activation and plugin consent are different<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>Enabled\n   \u2260\nApproved capability surface\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"><code>plugins enable --accept-capabilities<\/code> does not prove a plugin was previously disabled<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">For an existing plugin it may simply:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>retain enabled state\n+\nrecord required consent\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">systemd scope matters<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>systemctl\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">and:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>systemctl --user\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">do not manage the same units.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Loopback does not mean inaccessible from the Internet<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Local tunnel clients such as FRPC can expose a loopback-bound application without requiring the application itself to listen on the LAN.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Diagnostic warnings require architectural context<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">A diagnostic tool can observe application configuration, but it cannot always infer the complete external topology.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Automatic migration should generally be given the first opportunity to work<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>Restart\n   \u2193\nDoctor\n   \u2193\nObserve\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">is often safer than:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Delete\nMove\nRewrite database\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Maintenance changes should be separated where practical<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">A successful platform upgrade should not automatically become a simultaneous network redesign, storage migration, permission redesign, and automation rewrite.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">30. Final Architecture<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">After the upgrade, the deployment can remain structured like this:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> <code>                   Internet\n                       \u2502\n                       \u2502 HTTPS\n                       \u25bc\n              \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n              \u2502     Nginx      \u2502\n              \u2502 Reverse Proxy  \u2502\n              \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                      \u2502\n                      \u25bc\n              \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n              \u2502      FRPS      \u2502\n              \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                      \u2502\n                      \u2502 FRP Tunnel\n                      \u2502\n              \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25bc\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n              \u2502      FRPC      \u2502\n              \u2502 ARM Linux Host \u2502\n              \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                      \u2502\n                      \u2502 localhost\n                      \u25bc\n              \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n              \u2502    OpenClaw    \u2502\n              \u2502    Gateway     \u2502\n              \u2502 Loopback Only  \u2502\n              \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The Gateway remains managed as a systemd user service.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Public TLS termination remains on the reverse-proxy machine.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">OpenClaw itself remains isolated from direct LAN and Internet exposure.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">An OpenClaw upgrade is not simply an npm package replacement.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A modern upgrade can involve:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Package update\n      \u2502\n      \u251c\u2500\u2500 Configuration migration\n      \u251c\u2500\u2500 State migration\n      \u251c\u2500\u2500 Plugin updates\n      \u251c\u2500\u2500 Capability Consent\n      \u251c\u2500\u2500 systemd service management\n      \u251c\u2500\u2500 Gateway restart\n      \u251c\u2500\u2500 Security checks\n      \u251c\u2500\u2500 Automation compatibility\n      \u2514\u2500\u2500 Network architecture diagnostics\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The central maintenance principle is not to eliminate every warning.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Each message must first be classified:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Fatal error\nMigration notice\nSecurity policy\nCompatibility warning\nPerformance recommendation\nArchitecture difference\nInformational notice\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">A system may be completely healthy while Doctor still reports several recommendations.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For a deployment built around <strong>Loopback + FRP + Nginx HTTPS<\/strong>, a loopback-only Gateway can be an intentional security property rather than a configuration defect.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Similarly, an existing plugin requesting Capability Consent after an upgrade does not necessarily mean that the plugin was previously disabled. It may simply indicate that the newer OpenClaw release requires explicit approval metadata for a capability model that did not exist, or was not stored in the same form, under the older release.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The safest overall strategy is therefore:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><strong>Let the updater perform the application migration, let Doctor identify the resulting state, and interpret each warning according to the actual deployment architecture before changing anything.<\/strong><\/p>\n<\/blockquote>\n","protected":false},"excerpt":{"rendered":"<p>Privacy note: All hostnames, usernames, IP addresses, ports, domain names, paths, plugin deployment details, and other potentially identifying information in this article have been replaced with fictional examples. Values such as Orion, Proxy-A, 192.168.50.25, example.net, and port 28473 do not correspond to any real environment. Introduction An OpenClaw upgrade can &hellip;<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[88],"tags":[337,267,335],"class_list":["post-6140","post","type-post","status-publish","format-standard","hentry","category-4brz75t44cdxjqe","tag-openclaw","tag-systemd","tag-tunneling"],"_links":{"self":[{"href":"https:\/\/blog.eternalsphere.net\/index.php\/wp-json\/wp\/v2\/posts\/6140","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.eternalsphere.net\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.eternalsphere.net\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.eternalsphere.net\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.eternalsphere.net\/index.php\/wp-json\/wp\/v2\/comments?post=6140"}],"version-history":[{"count":1,"href":"https:\/\/blog.eternalsphere.net\/index.php\/wp-json\/wp\/v2\/posts\/6140\/revisions"}],"predecessor-version":[{"id":6141,"href":"https:\/\/blog.eternalsphere.net\/index.php\/wp-json\/wp\/v2\/posts\/6140\/revisions\/6141"}],"wp:attachment":[{"href":"https:\/\/blog.eternalsphere.net\/index.php\/wp-json\/wp\/v2\/media?parent=6140"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.eternalsphere.net\/index.php\/wp-json\/wp\/v2\/categories?post=6140"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.eternalsphere.net\/index.php\/wp-json\/wp\/v2\/tags?post=6140"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}