Remote teleop is sensitive to latency. Tailscale usually connects two devices directly (peer-to-peer); on networks where that isn’t possible it falls back to a relay, which adds latency. Expect the best results on connections with low round-trip time.
Sideload Tailscale on the Quest
Tailscale isn’t available on the Meta Quest Store, so you can’t install it the normal way. Since the Quest runs Horizon OS (an Android-based system), the workaround is to sideload Tailscale’s Android APK.1
Enable Developer Mode on the Quest
- Open the Meta Quest mobile app on your phone, with your headset connected.
- Go to Menu → Devices → select your headset → Headset Settings → Developer Mode, and toggle it on. You may be prompted to create a free Meta “organization” first (takes a minute).
- Restart the headset.
2
Download the Tailscale APK
Download the Android APK from Tailscale’s package server at pkgs.tailscale.com/stable/#android onto your computer.
3
Sideload it with SideQuest
The easiest tool is SideQuest:
- Install SideQuest on your computer from sidequestvr.com.
- Connect the Quest to your computer with a USB-C cable.
- Put the headset on and accept the Allow USB debugging? prompt (check Always allow from this computer).
- In SideQuest, use the Install APK from folder button and select the Tailscale APK.
adb install tailscale.apk.4
Launch and log in
Tailscale won’t appear in your normal app grid — it lives under the Unknown Sources section of your Quest app library (the folder icon with a ”?”). Open it, sign in to your tailnet, and approve the VPN connection prompt.
Tailscale on the Quest gets no auto-updates this way, so you’ll periodically re-sideload a newer APK.
Connect the robot machine to the same tailnet
On the robot machine, install Tailscale and bring it up (see Tailscale’s Linux install docs):100.x.y.z IP or its MagicDNS name (tailscale ip -4, or check the Tailscale admin console).
Drive the robot
With both devices on the tailnet, remote teleop is just teleoperation pointed at the Tailscale address instead of the LAN one:1
Start teleop on the robot machine
Start it from the control panel or the CLI (
axol teleop), exactly as for local teleop.2
Make sure Tailscale is connected in the headset
Open the sideloaded Tailscale app on the Quest and confirm the VPN is active.
3
Enter the Tailscale address in the VR app
Open the VR app at axol.almond.bot on the headset and enter the robot machine’s Tailscale IP or MagicDNS name in the Connect field (instead of its LAN IP). Press Connect, then Start.
4
Authorize the certificate
As with local teleop, approve the self-signed certificate once — tap Authorize certificate when prompted, or visit
https://<tailscale-address>:8000 in the headset browser and proceed past the warning. See Authorize the TLS certificate.Drive from outside your tailnet (Funnel + TURN)
The flow above assumes the operator can join your tailnet. To let someone drive without installing Tailscale — reaching the robot over the raw public internet — expose it with Tailscale Funnel. This needs two pieces, because a tunnel only forwards the control connection, not the camera video.1. Expose the control connection with Funnel
Funnel only publishes on ports 443 / 8443 / 10000, and it terminates TLS itself, so point it at the VR server’s own HTTPS port and tell it to skip the self-signed cert check:https://<your-machine>.tailXXXX.ts.net/ on 443 (check with tailscale serve status). Older Tailscale builds split this into two commands: tailscale serve --bg --https=443 https+insecure://localhost:8000 then tailscale funnel --bg 443 on.
2. Add a TURN server for camera video
Camera video is WebRTC, whose media is a separate peer-to-peer UDP stream — it does not travel through the Funnel. With both peers off each other’s network, they need a publicly reachable TURN relay to bridge the media. Use a hosted TURN provider, or self-host coturn on a box with a public IP. The repo ships a ready-to-deploy coturn config for Fly.io underdeploy/turn/ — Fly supports the raw UDP that TURN needs (unlike most PaaS hosts), and the config handles the dedicated-IPv4 and external-ip gotchas for you. Follow deploy/turn/README.md to launch your own relay in a few flyctl commands, then point Axol at it with the env vars below.
Set these env vars on the machine running teleop before starting it (the VR server and its video relay read them at connect time):
AXOL_TURN_URL is a comma-separated list of ICE URLs (turn:, turns:, or stun:). Without these, control still works over the Funnel but the camera feed stays blank for an off-tailnet operator. On a LAN or plain tailnet, leave them unset — the direct path is used as before.
3. Connect from the headset
In the VR app’s Connect field, enter the Funnel endpoint as anhttps:// URL (or with an explicit :443) so the app targets the public port instead of the LAN default of 8000:
Next steps
Teleoperation
The full teleop flow and controller layout.
VR Interface
The WebXR app, camera views, and connection details.
