Skip to content
DeviceRent
FleetDeviceyAIHow it worksPricingCommunity
Log inOpen app
All posts

August 23, 2026

Remote ADB: connecting adb to a phone that isn't on your desk

adb assumes a USB cable. Here are the four ways people work around that — adb tcpip, SSH forwarding, cloud farms, self-hosted STF — what breaks in each, and what we built instead.

adb was designed for a phone on the end of a USB cable. Everything about it assumes that: the daemon discovers devices on a local USB bus, the client talks to a server on 127.0.0.1:5037, and the transport is a cable you can physically see.

Then people started needing the phone somewhere else. A test rack in another building. A device model nobody on the team owns. A phone that has to stay powered and reachable while CI runs at 3am. And adb grew a set of half-answers to that problem, none of which quite works.

This is a walkthrough of the actual options for driving adb against a phone that isn't on your desk, what breaks in each, and what we ended up building.

The four ways people try to do this

1. adb tcpip plus adb connect

The built-in answer. Put the device's daemon on a TCP port, then connect to it by IP:

adb tcpip 5555
adb connect 192.168.1.44:5555

This works, on a LAN, for about as long as nothing changes. The problems show up immediately after:

  • Port 5555 is unauthenticated in practice. ADB's RSA key handshake protects the first connection from an unknown host, but once a host is authorised the device accepts it, and that authorisation survives reboots. Anyone who can reach that port and has been trusted once has a root-capable shell. This is why internet-exposed 5555 is a well-known botnet target — there are worms whose entire propagation strategy is scanning for it.
  • It does not survive a reboot. adb tcpip resets to USB mode on restart. Any device that reboots — which is any device running tests — drops off the network until someone plugs it back in.
  • It is LAN-only unless you do something reckless. Getting to it from outside means port-forwarding a root shell through your router.

adb tcpip is fine for debugging your own phone across your own desk. It is not a remote-access story.

2. Port-forward it over SSH

The sysadmin answer:

ssh -L 5037:localhost:5037 user@rack-host

Forward the adb server port rather than the device port, and your local client talks to the remote server. This is genuinely better — the transport is authenticated and encrypted, and you are not exposing 5555 to anything.

It also breaks in ways that take an afternoon to diagnose:

  • You get the whole server, not one device. The remote adb server lists every device attached to that host. If the rack has twelve phones, your adb shell targets whichever one it feels like unless every command carries -s <serial>. In a shared rack, you can trivially drive somebody else's device.
  • adb forward doesn't behave. Forwarding binds a port on the remote host, not yours, so anything expecting a local port — which is to say Appium — needs a second tunnel per port, set up in the right order.
  • Version skew is a hard failure. The adb client and server negotiate a protocol version. A client newer than the remote server refuses to talk to it, and helpfully kills your local server to "fix" it.

3. A cloud device farm

BrowserStack, Sauce Labs, AWS Device Farm, Firebase Test Lab. These solve reachability by owning the whole stack, and for a lot of teams that is the correct answer — if what you need is a matrix run across forty device models before a release, buy one of these.

What you give up is the shell. These platforms expose a session, not a device. You upload an app and a test suite; you get results back. The ones that offer interactive access give you a screen and a limited command set. You do not get raw adb, because raw adb is root-capable and their multi-tenancy model cannot allow it — one tenant with a root shell on a shared device is the end of the isolation guarantee.

That constraint is structural, not a product gap. It is why none of them will ever offer you su.

4. Self-host it (OpenSTF / DeviceFarmer)

Run your own. OpenSTF was the standard answer here for years, and DeviceFarmer picked it up after the original project went quiet in 2020. It works, and it gives you real device control.

It also means you now operate a device lab: USB hubs that brown out under load, phones that need physical babysitting when they wedge, an Android version treadmill, and a rack that has to stay powered and networked. That is a real ongoing cost, and it is the reason a lot of self-hosted labs quietly rot.

What actually has to be true

Strip those down and the requirements for remote adb that doesn't fight you are:

  1. The transport is authenticated and encrypted — no naked 5555, ever.
  2. Access is scoped to one device. Not "a server that happens to have your device on it". If a credential can drive a phone that isn't yours, the design is wrong.
  3. Your local tooling sees a normal local device. Appium, Gradle, Espresso, Flutter and every CI script in existence talk to an adb server on a local port. Anything that requires them to be reconfigured will not get adopted.
  4. It survives reboots, because devices under test reboot.

How DeviceRent does it

Two paths, depending on whether a human or a machine is driving.

In the browser, a rental session connects over a Tailscale Funnel to the bridge that owns the phone. The server mints a short-lived HS256 JWT scoped to exactly one device serial — roughly a ten-minute TTL, re-minted before it expires — and the browser passes it in the WebSocket subprotocol rather than the URL, so it never lands in a proxy log. The bridge verifies the token and pins the connection to that serial. A token for your phone is not a token for any other phone, and there is no shared credential anywhere on the customer side.

You do not run Tailscale yourself. The Funnel is a public HTTPS endpoint; the tailnet is ours, and the phone's ADB port is only ever exposed inside it.

For your own tooling, there is a connector: devicerent-connect. It runs a small local adb-server emulator on your machine and tunnels each adb conversation to the device over that same serial-pinned bridge.

npx devicerent-connect --key drauto_... --rental <rental-id>

It prints a port, you export it, and every tool you already have works unchanged:

export ANDROID_ADB_SERVER_PORT=15037
adb devices          # your rented phone, as a local device

The connector implements adb forward itself — binding the listen port on your machine and tunneling each connection through — which is the part that lets Appium reach the UiAutomator2 server on the device. That detail is the difference between "adb works" and "my test suite works".

What this does not do

Being specific about the limits, because finding out mid-pipeline is worse than reading it here:

  • adb reverse is not supported. The connector forwards ports to the device, not back from it. Frameworks that need the phone to dial into your host — Detox is the common one — will not run.
  • Maestro is not supported. It doesn't drive devices through the adb server the connector provides. We don't list it as working until we have proven it end to end, and we haven't.
  • Large APK pushes are slower than USB. Traffic crosses a Funnel. A phone on your own cable will always win on raw throughput; you are trading bandwidth for a device you do not have to own.

Which one you should pick

If the phone is on your desk, use a cable. Nothing here beats a cable.

If you need a forty-device matrix run before every release, buy a device cloud. That is what they are good at, and we are not trying to be that.

If you need a specific real phone, reachable from a script, with a raw ADB shell and no VM in the way — that is the gap the built-in tooling never closed, and it is the one we are aiming at.

One thing we do not offer yet, since this post has been rude about everyone else's limits: root. Every phone in our rack has a locked bootloader, so Magisk and Xposed work is not possible on us today either. It is the most-requested item on our list, and it is not shipped.

All posts
DeviceRent
PricingDeviceyAILog inSign upCommunityBlogFeedbackTermsPrivacyCookiesDevices hosted in the Netherlands · EU© 2026 DeviceRent