adb (Android platform-tools) and the Tailscale client, and both devices on the same tailnet.100.x.y.z Tailscale IP.
Before touching the phone, understand the three moving parts. Tailscale is a mesh VPN built on WireGuard that gives every device a stable private IP in the 100.64.0.0/10 range, so your laptop can reach the phone from a café without port forwarding. Termux is a terminal emulator that ships a real Linux userland (APT-style pkg package manager) without root. ADB (Android Debug Bridge) is the official debugging channel that talks to adbd on the phone and gives you shell, screencap, pm, am and settings commands.
The data flow is:
1. Tailscale app on the phone joins your tailnet and gets 100.x.y.z.
2. Termux runs sshd on a local port; inbound connections arrive over the Tailscale interface.
3. adbd on the phone listens on a TCP port; the laptop connects to it over the same tailnet.
4. Laptop authenticates with an SSH password/key or an ADB RSA fingerprint.
What you need installed and checked:
adb from Android platform-tools, an SSH client, and the Tailscale client signed into the same account.adb tcpip.Values you will need, and where to read them:
| Item | Example value | Where to get it |
|---|---|---|
| Tailscale IP of the phone | `100.101.102.103` | Tailscale admin console, or `tailscale ip -4` on the laptop for other nodes |
| MagicDNS name | `<phone-name>.<your-tailnet>.ts.net` | Tailscale admin console (if MagicDNS is on) |
| Termux SSH user | `u0_a123` | run `whoami` inside Termux |
| SSH port | `8022` | Termux `sshd` default — confirm in Termux docs |
| ADB connect port | `37xxx` | the "IP address & Port" line on the Wireless debugging screen |
Checklist before you start:
pkg update finishes without errorsadb version workingIf you also want a full Linux userland on the phone (Debian inside Termux), the setup is described in How to Run Linux on Android Without Root: Termux, PRoot, and AI Tools; this guide stops at SSH + ADB.
What to do: Install Termux, update its packages, keep the CPU awake, then install and enable Tailscale.
pkg update && pkg upgrade -y
pkg install openssh -y
termux-wake-lock
whoami
termux-wake-lock holds a wake lock so Android does not freeze the Termux session when the screen goes off — without it sshd dies silently after a few minutes. Then open the Tailscale app, sign in, and toggle the VPN switch on. Go to Android Settings → Apps → Termux → Battery → set to *Unrestricted* (the exact wording differs per vendor).
Why: the Tailscale app is a VPN service; it owns the 100.x.y.z address and forwards inbound traffic to local sockets. Termux's sshd binds to all interfaces, so it becomes reachable at that address. Root is not involved anywhere — both apps run as ordinary user apps.
How to check: on the laptop, run:
tailscale status | grep <phone-name>
tailscale ping <phone-name>
You should see the phone listed with its 100.x.y.z address, and tailscale ping should print a line starting with pong from <phone-name>. If you only see timeout or a DERP-relayed path that never resolves, the phone's VPN switch is off or the app is being killed by battery optimisation.
Example: phone named oldpixel → tailscale ping oldpixel → pong from oldpixel (100.101.102.103). From that moment 100.101.102.103 is a usable address in every command below.
What to do: Part A — start the SSH daemon and set a password in Termux:
passwd
sshd
passwd asks for a new password twice; it sets the password for the Termux user printed by whoami. sshd starts the daemon in the background on port 8022 (Termux default — verify against Termux docs if you changed it).
Why: Termux is not rooted, so it cannot use the system sshd; it ships its own OpenSSH build that runs entirely in app space. The username is *not* root or admin — it is the generated Android UID name, for example u0_a123.
How to check (Part A): from the laptop:
ssh -p 8022 u0_a123@100.101.102.103
Expected: a password prompt, then a Termux shell where uname -a prints an aarch64 Android kernel line. ssh: connect to host ... port 8022: Connection refused means sshd is not running.
What to do: Part B — enable ADB over TCP. On Android 11 or newer: Settings → System → Developer options → *Wireless debugging* → on → *Pair device with pairing code*. The screen shows an IP:port and a 6-digit code. On the laptop:
adb pair 100.101.102.103:<pairing-port>
# enter the 6-digit code when prompted
adb connect 100.101.102.103:<connect-port>
On Android 10 or older: connect the phone by USB once, then:
adb devices # phone must appear as "device"
adb tcpip 5555 # restart adbd in TCP mode on port 5555
adb disconnect
adb connect 100.101.102.103:5555
Why: adb tcpip tells the on-device daemon to stop listening only on the USB endpoint and start listening on TCP so the laptop can reach it over the tailnet. The pairing flow on Android 11+ does the same thing but replaces the cable with an RSA key exchange — pairing port and connect port are two different numbers, and the connect port changes every time Wireless debugging is toggled.
How to check (Part B):
adb devices
Expected output — the phone listed with state device:
List of devices attached
100.101.102.103:37xxx device
Anything else (offline, unauthorized, empty list) is covered in Troubleshooting. Generic ADB command syntax and desktop-side fixes are covered in How to Connect Android to Windows via ADB: Commands and Fixes.

What to do: Turn off the laptop's Wi-Fi and connect it to a phone hotspot or a mobile connection — a different network from the one the old phone uses. Then run both channels.
ssh -p 8022 u0_a123@100.101.102.103 'uname -a; pkg list-installed | head -5'
adb -s 100.101.102.103:37xxx shell getprop ro.build.version.release
adb -s 100.101.102.103:37xxx shell screencap -p /sdcard/shot.png
adb -s 100.101.102.103:37xxx pull /sdcard/shot.png ./shot.png
Why: this is the real test. If both commands succeed while the laptop is on a foreign network, the traffic is going through the tailnet and not through your home router, which is the whole point of the setup.
How to check: the SSH command prints the kernel line (for example Linux localhost 4.x ... aarch64 Toybox), the getprop command prints the Android release number, and pull prints a transfer line ending with 1 file pulled. The file ./shot.png opens as a screenshot of the phone.
Success looks like this:
tailscale ping <phone-name> returns pong fromssh -p 8022 u0_a123@100.101.102.103 gives a Termux shell from a foreign networkadb devices shows the 100.x.y.z:port entry in state deviceadb shell screencap + adb pull produces a readable PNG on the laptopNote what does not survive a reboot: the Termux sshd process and the adb tcpip mode are runtime state. After a restart you re-open Termux, run sshd, and re-run adb connect (or re-pair). Tailscale itself reconnects automatically once the app starts.
Problem. SSH asks for a password forever, then refuses.
u0_a123@100.101.102.103: Permission denied (publickey,password).root, admin or termux), or no password was ever set with passwd, so the account has no password to check against.whoami and copy the exact string, then passwd to set one. Retry with ssh -p 8022 $(whoami)@100.101.102.103. If you want key auth instead: ssh-keygen -t ed25519 on the laptop, then ssh-copy-id -p 8022 u0_a123@100.101.102.103.Problem. SSH worked yesterday, today the port is closed.
ssh: connect to host 100.101.102.103 port 8022: Connection refusedtermux-wake-lock then sshd, and set Termux's battery usage to *Unrestricted* in Android Settings. Confirm with pgrep -l sshd inside Termux — it should print a PID and sshd.Problem. ADB sees the device but cannot talk to it.
adb: device offline or failed to connect to '100.101.102.103:37xxx': Connection refusedadbd fell back to USB-only mode, or the Wireless debugging toggle was switched off (which rotates the port).adb disconnect && adb connect 100.101.102.103:<new-port>. On Android 10 and older re-run adb tcpip 5555 over USB. If the phone shows an "Allow USB debugging?" dialog, tick *Always allow* and accept — that is what clears the unauthorized state.You now have two independent remote channels into a non-rooted Android phone — a Termux SSH shell and an ADB shell — both addressed by a stable Tailscale IP that works from any network. Next, harden the setup with SSH keys, and check how long the phone will keep receiving Android updates using How to Check Your Android Phone's Update Lifespan and Find 7-Year Support Models.
Do I need root for any of this?
No. Termux installs as a normal app, the Tailscale app uses Android's VPN service API, and adb tcpip is an official developer setting. Nothing writes to /system, and su is never called.
Why is my SSH username something like u0_a123 instead of root?
Because Android assigns every app a unique Linux UID, and Termux runs under that UID. whoami inside Termux prints the only valid login name for sshd.
Does the connection survive a phone reboot?
Tailscale reconnects on its own once the app starts, but Termux's sshd and the adb tcpip mode do not persist — re-run sshd and adb connect after each restart.
Can I use the phone's normal Wi-Fi IP instead of the Tailscale IP?
Only on the same LAN. The 192.168.x.x address is not routable from the internet, so the whole point of running Tailscale is to use the 100.x.y.z address in every ssh and adb command.