
Homelab 19: take remote control of your Android phone, no cloud
Your phone is charging on the living-room table and you are at your desk. You want to see its screen, install an app on it, or read its logs. No third-party service is needed: Android already knows how to listen on the network, and on your private network that channel never leaves home. We set all of this up today on a phone running Android 16: every command below was actually executed.
What you gain. The phone's screen in a window on your PC, with your keyboard and mouse acting on it; installing apps and reading logs from the command line, from any network your phone is on. Zero cloud, zero account with a third party: the link is encrypted end to end by your Tailscale private network (see the backbone tutorial).
Prerequisites
- A phone on Android 11 or later: wireless debugging has existed since that version. The screenshots and commands in this chapter come from a device on Android 16.
- The phone and the trusted machine on your private network: each gets a
100.x.y.zaddress and a name, reachable from anywhere (the backbone tutorial covers setup, ten minutes per device). - On the trusted machine:
adb(theandroid-toolspackage on Arch,adbon Debian and Ubuntu) andscrcpy(pacman -S scrcpyorapt install scrcpy).
1. Turn on wireless debugging
Open the developer options (seven taps on "Build number" in the phone's about screen if they are still hidden), then switch on Wireless debugging. Tap its name to open its page: it shows the device name and, most importantly, its IP address and port. That port is the connection port; write it down.
2. Pair once, connect forever
On the wireless debugging page, tap "Pair device with pairing code". The phone shows a six-digit code and a pairing port, different from the connection port and single-use. From the trusted machine:
adb pair 100.x.y.z:<pairing-port> 123456
adb connect 100.x.y.z:<connection-port>
The pairing survives phone reboots. The connection port, however, can change over time: when adb connect fails days later, read the port again on the wireless debugging page and reconnect — the pairing itself is still there.
3. One adb identity on several machines
adb signs each machine with a key, stored in ~/.android/adbkey and ~/.android/adbkey.pub. Copy those two files to your second PC and the phone sees the same authorized machine: no re-pairing. Treat that key like an SSH key: it grants full access to the phone, so keep it in a protected folder, never in an email or on a stray USB stick.
4. See and drive the screen with scrcpy
scrcpy -s 100.x.y.z:<connection-port>
A window shows the phone's screen; your mouse clicks, your keyboard types, the clipboard works both ways. Three options we use all the time:
--no-audio: no sound, handy on a narrow link.--turn-screen-off: the phone's physical screen turns off while you keep seeing and acting — the battery thanks you.--no-window --record session.mkv: record without showing a window, to keep a trace of a diagnosis.
5. What it is for, concretely
- Install or update an app:
adb install -r my-app.apk. That is how we push each new build of our own application (see publishing your APK outside the Play Store) to the test phone without touching it. - Read the logs:
adb logcat. Reading the log remotely is how we found our APK's crash on an audio permission — the kind of bug that stays invisible until you look at what the phone is saying. - Automate the interface:
adb shell input tap 540 1200to tap,input swipeto swipe,uiautomator dumpto read the tree of on-screen elements,screencapfor a screenshot. Enough to let an agent drive the phone while you do something else (see an agent running on a server).
Security, honestly
Wireless debugging listens on all the phone's interfaces. On public Wi-Fi, the port is exposed — behind the pairing key, which refuses any unknown machine, but an open port is still a surface. Two simple rules: switch the toggle off when you do not need it, or only enable it if the phone lives on your private network. Tailscale is what makes this setup reasonable: without a private network, we would not leave it open.
Traps
The pairing code is single-use and expires: close the dialog and the code dies. Keep it open for the duration of the adb pair.
The connection port changes as the phone sleeps and wakes. A failing adb connect does not mean the pairing is lost: read the displayed port again and reconnect.
Screen off, zero frames: if scrcpy shows nothing, first check that the phone is not asleep. (--turn-screen-off is different: scrcpy turns the physical screen off but keeps receiving the display.)
The PIN lock cannot be bypassed — and that is a good thing. adb gives you a lot of power, not the power to unlock a locked or powered-off phone. A stolen phone stays closed.
What we use it for
Managing our app's APK remotely: installing the build of the day, reading the log when a tester reports odd behavior, and leaving the phone head-down in a pocket while an agent drives it for a repetitive task. The test phone has not left its corner of the desk; we have.
Sources
Found this useful? Tell us what to measure next.
Comments
No account, no tracker: a comment is read by a human before it appears.