Remote Access & Device Pairing
Remote access enables managing automation away from your host machine. Two primary approaches are supported:
| Method | Exposure Profile | Recommended For |
|---|---|---|
| LAN Direct Connection | Internal IP + Port | Devices connected to the same local router |
| Cloudflare Quick Tunnel | Ephemeral Public Domain | Remote mobile management outside local networks |
LAN Direct Connection
- Set
WebuiHostto0.0.0.0inconfig/deploy.yaml(or keep default settings). - Configure a strong password in
WebuiPassword, or supply-kon the command line. - Restart the backend server.
- Open
http://<Local-IP>:25548from another device on the same subnet.
Never Bind to 0.0.0.0 Without Passwords
The WebUI can start/stop tasks, read screenshots, and alter configurations. If bound to public interfaces without credentials, AzurPilot generates an ephemeral key in password.txt, but you should always configure a strong password manually.
Cloudflare Quick Tunnel
Navigate to "Settings → Remote Access", set the mode to cloudflare, configure a WebUI password, toggle Remote Access on, and restart. The engine will:
- Launch an internal
cloudflaredQuick Tunnel to obtain an ephemeral*.trycloudflare.comdomain. - Register the tunnel endpoint with the registry service (default:
https://remote.azurpilot.com) using its hardware-bound key. - Renew the lease every 60 seconds; orphaned leases expire on the server after 180 seconds.
- Expose a persistent URL at
<registry>/d/<device_id>/that returns HTTP 301 redirects to the active tunnel.
Device identities are stored in config/remote-access.json: installation IDs and registration keys persist locally, while pairing credentials store SHA-256 hashes only. Back up this file to retain persistent URLs across migrations, but never commit it to source control.
Quick Tunnel Limitations
Cloudflare offers Quick Tunnels on a best-effort basis, imposing limits on concurrent streams and long-lived connections. They are suited for mobile management and testing. Because the underlying protocol is WebSocket, persistent URLs cannot bypass Cloudflare edge limits. Outbound access to port 7844 is required.
Device Pairing Workflow
Click "Pair" in Remote Access settings. The server requests a 6-digit verification code, a 128-bit scan secret, and a 5-minute validity window from the registry.
- QR Code: Scan the
azurpilot://pair?secret=<secret>QR code. - Manual Entry: Submit the 6-digit pairing code (preserving leading zeros).
Claims are resolved inside an atomic server-side transaction and can only succeed once.
The Android client encrypts the endpoint and token via AES-GCM in the Android Keystore. The client connects over WSS, calling auth.login before signaling readiness.
The host displays active clients under "Authorized Devices", allowing individual client revocations. Revoked devices drop on the next request or 15s heartbeat without modifying the host's WebUI password.
Security Architecture
| Boundary | Design Guarantee |
|---|---|
| Pairing Tokens | 6-digit code + 128-bit secret; expires in 5 minutes; single-use |
| Storage | Registries store token hashes only; clients encrypt secrets in Keystore |
| Revocation | Revocations operate per client without altering main passwords |
| Master Password | The registry never receives or persists the WebUI master password |
| Payload Traffic | The registry does not proxy WebSockets, screenshots, or game data |
Client Access Methods
- Web Browser: Navigate to the tunnel URL directly and authenticate with your WebUI password.
- Android Host App: Connects in Remote Client mode without running local runtimes or requiring Shizuku; see Using as Remote Client.
- MCP Clients: Connects to
/mcp/ssesupplying your WebUI password as a Bearer Token; see MCP Server.
Troubleshooting Connectivity
| Symptom | Cause / Remediation |
|---|---|
Persistent URL returns 302 to /error | Host offline, lease expired, or Tunnel dropped |
| QR code scan fails | Check screen contrast; codes use standard Level M error correction |
| Pairing code expired alert | Code exceeded 5-minute window; generate a new code |
| Infinite connection spinner | WebSocket blocked by upstream network; confirm port 7844 outbound access |
| Tunnel fails after core update | Missing or outdated pyflared dependency inside Runtime |