#8261: fix: enable A2UI Canvas on remote gateways
docs
gateway
Cluster:
Gateway Resilience and Configuration
# fix: enable A2UI Canvas on remote gateways
## Summary
Enables A2UI Canvas to work when the gateway runs on a remote server (cloud VM, VPS) and nodes connect via VPN (Tailscale) or over the internet.
**Fixes:** https://github.com/openclaw/openclaw/issues/7143
**Related closed issues:**
- https://github.com/openclaw/openclaw/issues/5540 - Feature request for advertised URL
- https://github.com/openclaw/openclaw/issues/5033 - Similar request for remote canvas access
## The Problem
When a macOS/iOS node connects to a remote gateway, A2UI Canvas fails because:
1. **Gateway advertises `127.0.0.1` URLs** - The gateway sends the canvas host URL based on its local address, which remote nodes cannot reach.
2. **macOS app reloads the page repeatedly** - When `a2ui_push` arrives, the content renders briefly, then `maybeAutoNavigateToA2UI()` triggers a reload even though we're already at the target URL, clearing the just-rendered content.
## The Solution
### 1. Gateway: Add `canvasHost.advertisedUrl` config option
A new optional config allows operators to specify a public URL that remote nodes can reach:
```json
{
"canvasHost": {
"advertisedUrl": "https://gateway.example.com"
}
}
```
When set, this URL is returned to nodes instead of the auto-detected local URL.
**Files changed:**
- `src/config/types.gateway.ts` - Add `advertisedUrl` to `CanvasHostConfig` type
- `src/config/zod-schema.ts` - Add to schema validation
- `src/infra/canvas-host-url.ts` - Use `advertisedUrl` when set
- `src/gateway/server*.ts` - Thread the config through to WebSocket handlers
- `docs/gateway/configuration.md` - Document the new option
### 2. macOS App: Prevent redundant page reloads
Added a guard in `CanvasManager.swift` to skip navigation when already at the target URL:
```swift
if self.lastAutoA2UIUrl == a2uiUrl,
let current = controller.currentTarget?.trimmingCharacters(in: .whitespacesAndNewlines),
current == a2uiUrl
{
Self.logger.debug("canvas auto-nav skipped; already at target URL")
return
}
```
**File changed:**
- `apps/macos/Sources/OpenClaw/CanvasManager.swift`
## Testing
### Setup
1. Gateway running on cloud VM (e.g., Oracle Cloud, Hetzner)
2. macOS app connecting via Tailscale VPN
3. Reverse proxy with HTTPS (Traefik, nginx, Caddy, etc.)
### Gateway config
```json
{
"canvasHost": {
"advertisedUrl": "https://gateway.example.com"
},
"gateway": {
"trustedProxies": ["10.0.0.0/8", "172.16.0.0/12", "100.64.0.0/10"]
}
}
```
Note: `trustedProxies` must include the IP ranges of connecting nodes (e.g., Tailscale CGNAT `100.64.0.0/10`) for WebSocket connections to work.
### Test
```bash
# Push A2UI content to a connected node
docker exec $(docker ps -q -f name=clawdbot-gateway) \
node /app/dist/index.js nodes canvas a2ui push \
--jsonl test.jsonl --node "MacBook"
```
**Before:** Content flashes briefly then disappears (or never appears)
**After:** Content renders and persists
## Who This Helps
- Users running OpenClaw gateway on cloud VMs (Oracle Cloud, Hetzner, AWS, etc.)
- Users connecting to their gateway remotely via Tailscale/VPN
- Anyone with gateway behind a reverse proxy (nginx, Caddy, Traefik)
## Why It's Worth Shipping
A2UI Canvas is a powerful feature, but it's currently broken for the growing segment of users running remote gateways. This is a minimal, non-breaking change:
- **Backward compatible** - `advertisedUrl` is optional; existing local-only setups unchanged
- **Low risk** - Guard clause in Swift is a simple early-return pattern
- **High impact** - Unblocks remote gateway users from using Canvas
- **Documentation included** - New config option is documented
Most Similar PRs
#7852: fix(gateway): use port from Host header for canvasHostUrl (reverse ...
by tonimelisma · 2026-02-03
73.2%
#13321: android/gateway: harden manual connect identity and A2UI UX
by m888m · 2026-02-10
69.5%
#4222: fix: canvas root should respect agents.defaults.workspace
by sanool · 2026-01-29
68.6%
#22361: fix(macos/canvas): prevent A2UI reload loop and add A2UI MIME mapping
by AIflow-Labs · 2026-02-21
67.8%
#11740: fix(gateway): remove IP-based canvas auth fallback
by coygeek · 2026-02-08
67.6%
#19548: fix(android): show scaffold instead of raw JSON on canvas auth errors
by gregmousseau · 2026-02-17
66.7%
#18752: Feat(slack): add Canvas content reading support
by machaltitude · 2026-02-17
65.5%
#6770: fix(gateway): protect host-local transport fields from config.patch
by ryx2 · 2026-02-02
65.2%
#11205: Android: fix gateway connection and canvas URL for Tailscale serve
by emonty · 2026-02-07
64.4%
#6638: fix: make Dockerfile work on container platforms (Render, Railway, ...
by kaizen403 · 2026-02-01
64.4%