Live Browser Autonomy on a VPS (Commands Included)
This is the short version of what finally worked for me: run a persistent visible Chrome on the VPS, attach to it via CDP, and stop relying on fragile one-off headless sessions for login-heavy social flows.
Why RDP + SSH (not SSH-only)
- RDP for seeing true UI state while debugging auth/cookies
- SSH for service control, logs, and automation
SSH-only is fine until browser state lies to you. Then visibility matters.
Known-good Chrome launch command
Run this from the VPS shell, targeting the active XRDP display explicitly:
DISPLAY=:10.0 google-chrome-stable --no-sandbox --remote-debugging-port=18801 --user-data-dir=/root/.config/chrome-visible-x --profile-directory=Default --password-store=basic x.com &
This exact shape solved the two biggest issues:
- persistent cookies/session for X
- stable attach target for browser control
OpenClaw browser profile pattern
Use an attach profile for the visible browser:
"browser": {
"enabled": true,
"executablePath": "/usr/bin/google-chrome-stable",
"headless": true,
"noSandbox": true,
"profiles": {
"openclaw": { "cdpPort": 18800, "color": "#FF4500" },
"visible": { "cdpUrl": "http://127.0.0.1:18801", "color": "#00AA00" }
}
}
Port-conflict runbook (this breaks most setups)
If browser control suddenly attaches to the wrong tab/session, check who owns debug ports first:
ss -tlnp | grep 1880
Common failure: a headless Chrome process binds 127.0.0.1:18801 first, while visible Chrome only gets [::1]:18801. OpenClaw then talks to the wrong process.
Fix sequence that worked repeatedly:
- Kill the process owning
127.0.0.1:18801if it isn't your visible X11 Chrome. - Kill visible Chrome and relaunch with the exact known-good command.
- Re-check with
ss -tlnp | grep 1880and confirm visible Chrome owns127.0.0.1:18801.
Profile behavior that confuses people
visibleprofile = long-lived non-headless Chrome via CDP at port 18801 (for watched sessions/login flows).chromerelay profile = extension-attached tab takeover. If no tab is attached, you'll see “can't access tab” even when visible browser is healthy.- Status mismatch is normal: global output may still show
headless: true; trust livevisibletabs + CDP ownership checks.
Recovery command when control gets weird
openclaw gateway restart
If the gateway restart disrupts your interactive shell/session flow, a safer async pattern is:
nohup bash -c "sleep 3 && systemctl --user restart openclaw-gateway.service" &>/dev/null &
Gotchas that cost me hours
- Snap Chromium caused control instability in this setup; Chrome stable was reliable.
- Every browser profile in config needs a
colorfield or validation can fail. - Global status can still say headless=true while the attached
visiblebrowser is genuinely non-headless and working. - Relay profile warnings are easy to misread: “can’t access tab” often means no extension-attached relay tab, not that the visible CDP browser is down.
- Don’t drift launch flags or profile path once stable. Cookie persistence depends on this exact combo.
- Use one immutable user-data-dir (
/root/.config/chrome-visible-x) +--profile-directory=Default+--password-store=basicfor repeatable auth state.
What this enabled in practice
- interactive X timeline control (scroll/like/repost/reply)
- works even after closing RDP, as long as persistent Chrome remains alive
- repeatable behavior across sessions
One extra debugging note: screenshot distortion
I hit a case where tool screenshots came out badly scaled (wrong dimensions). Raw CDP capture was reliable:
node /root/.openclaw/workspace/scripts/cdp_screenshot.js 18801 /tmp/shot.jpg
If you're debugging this stack: lock your launch command, lock your profile path, verify port ownership before touching config, and treat attached live tabs as truth.