Status: beta. Firefox for Android needs an Android-specific package and a Tailscale tailnet; report Android issues as bug reports.
Sleeper uses Tailscale Serve as its only mobile-access path. The daemon stays
bound to 127.0.0.1; Tailscale supplies HTTPS/WSS and private routing. The
mobile setup link carries the daemon bearer only in its URL fragment, which is
not sent in the HTTP request; the extension verifies that bearer against the
daemon before saving it.
-
Install Tailscale and sign this computer into your tailnet.
-
Enable MagicDNS and HTTPS certificates for the tailnet.
-
Start the Sleeper daemon normally.
-
Run:
sleeper mobile setup
Sleeper configures two tailnet-only HTTPS listeners:
https://HOSTNAME.ts.net:8790→ daemon HTTP on127.0.0.1:8790wss://HOSTNAME.ts.net:8789/ws→ daemon WebSocket on127.0.0.1:8789/ws
The command prints a setup URL and, when the optional QR renderer is installed, a terminal QR code. The command changes only Tailscale Serve ports 8789 and 8790; it does not reset unrelated Serve routes.
- Install Tailscale on the phone and join the same tailnet.
- Install an AMO-signed Android Sleeper package in Firefox for Android.
The desktop package requests
nativeMessaging, which Android rejects. - Scan the QR code from
sleeper mobile setup, or open its setup URL in Firefox. - Sleeper verifies the daemon and opens its connection settings. When replacing an existing pairing, the current daemon stays connected until you approve the proposed endpoint in those settings.
The setup link is a secret: share it only with the intended browser. The
extension stores the bearer locally and uses it for authenticated /tabs and
WebSocket requests. Tailscale access controls still decide which users and
devices can reach the service.
sleeper mobile status
sleeper mobile disablestatus reports the tailnet hostname and current Serve configuration.
disable removes only Sleeper's HTTPS listeners on ports 8789 and 8790.
If setup reports that Tailscale is not connected, run tailscale up. If it
reports that HTTPS is unavailable, enable MagicDNS and HTTPS certificates in
the Tailscale admin console.
- The daemon must remain loopback-only.
- Only Tailscale Serve may expose the daemon to another device.
- Plain LAN HTTP/WS and direct daemon binding are rejected.
- Setup URLs must use HTTPS, port 8790, and a
.ts.nethostname. - Pairing succeeds only when the endpoint returns an authenticated
/tabsresponse; a.ts.netpage without the setup fragment cannot pair the add-on.
Safety note: web-ext run installs a temporary add-on using the manifest's
same ID. It is not safely coexistent with a persistent Sleeper installation:
the temporary install may replace that add-on and remove itself on exit. The
runner therefore refuses to start unless you explicitly pass
--allow-persistent-replacement after backing up or intentionally uninstalling
the persistent add-on. This workflow reloads source changes only; it is not a
production self-update channel, and add-on storage should be treated as
replaceable during the run.
For extension development, use the runner with Mozilla's supported
web-ext Android target. First enable Firefox Nightly remote debugging and
Android USB or Wi-Fi debugging, then confirm the device is visible to ADB:
npm ci --ignore-scripts
adb devices
scripts/firefox-android-iterate.sh --adb-device SERIAL \
--allow-persistent-replacementThe script runs:
node_modules/.bin/web-ext run --source-dir TEMP_ANDROID_SOURCE --target firefox-android \
--adb-device SERIAL --firefox-apk org.mozilla.fenixThe runner generates a temporary Android source directory from extension/,
omitting the desktop-only nativeMessaging permission. It mirrors runtime
and manifest changes into that directory, which web-ext watches to reload
the add-on. The source manifest retains desktop native messaging. The
temporary directory is removed when the runner exits.
web-ext run installs the add-on temporarily into Firefox for Android's main
browser profile. Because it uses the manifest ID, it can replace the
persistent AMO Sleeper add-on with that same ID; when the run exits, the
temporary add-on may be removed and the persistent add-on may not be restored.
Back up or intentionally uninstall the persistent add-on before using the
explicit replacement acknowledgement above. This workflow does not change
the production version or provide a self-update channel. Browser profile data
outside the add-on is retained, but add-on storage must be treated as
replaceable. Keep the debugger and ADB connection alive until cleanup.
When more than one device is connected, --adb-device is mandatory. The
package defaults to Nightly (org.mozilla.fenix); set FIREFOX_APK or pass
--firefox-apk for another Firefox channel. --dry-run validates device
selection and prints the exact command without installing anything:
scripts/firefox-android-iterate.sh --dry-run --adb-device SERIALFirefox does not treat a locally built unsigned XPI as a production update.
Persistent add-on updates require a signed package and an update manifest (or
distribution through AMO); this repository deliberately has no update_url.
For local iteration, web-ext run and its Gecko remote-debugger install/reload
protocol are the supported mechanism. Build an Android package for inspection:
python3 scripts/build_packages.py firefox-android extension build/sleeper-android.xpiThis unsigned package is for development. Persistent installation requires
AMO signing of the Android package. The existing desktop signing workflow in
firefox-signing.md produces a desktop artifact and
does not establish Android compatibility.
References: Firefox for Android extension development
and the web-ext run command reference.