You log in over SSH, add -D 1080, and the command succeeds. A SOCKS listener now exists on the phone, and half the apps still go out over mobile data. That is the normal result, not a broken tunnel: ssh -D creates a proxy endpoint, and Android applications only use a proxy if something makes them. Walking the chain step by step shows where each piece of the job actually lives.

Start where the traffic starts

Pick one app that should use the tunnel and check whether it has a proxy setting of its own. A browser with a SOCKS field is the easy case: point it at 127.0.0.1:1080, enable remote DNS if the setting exists, and the request goes through. A chat client, a map app or a game with no such field has no way to use the listener, and nothing you type into the SSH command changes that.

Before involving anything else, prove the listener works from the phone's own shell with a client that speaks SOCKS directly:

ssh -N -D 1080 [email protected]
curl --socks5-hostname 127.0.0.1:1080 https://ifconfig.me

The address that comes back should be the SSH server's, not the phone's. If it is, the proxy half is done and the rest of the work is about coverage. If it is not, fix the SSH side first: key authentication, the server's ability to reach the destination, and the SSH server's own egress.

Add the piece Android needs

Applications without a proxy setting need something to capture their packets and turn them into proxy connections. On a non-root device, that is a VPN-service adapter: an app that takes the virtual interface and forwards selected traffic into the local SOCKS listener. The chain becomes app, adapter, SOCKS listener, SSH connection, destination.

Install the adapter, grant it the VPN permission, and choose the apps or routes it should capture. The key icon in the status bar then represents the adapter, not a separate commercial VPN. Android allows one active VPN-service connection per user profile, so starting a second VPN app does not add a layer on top of the chain; it competes for the same role.

This is also the step where a successful test can mislead you. If the adapter is configured to capture only the browser you already pointed at the proxy, everything works and nothing else is covered. Read the capture list before you conclude the device is tunneled.

Keep the SSH transport outside the capture

The SSH connection itself must not be fed back into the SOCKS tunnel it maintains. If the adapter captures the SSH app's traffic, the tunnel depends on a connection that is waiting for the tunnel, and the result is a loop that stalls or fails as soon as the adapter starts.

Integrated implementations protect their own transport socket. With separate apps you need a supported exclusion: leave the SSH app outside the capture, or exclude the SSH endpoint by address. Both have costs. Excluding a whole terminal app also removes its unrelated network activity from the tunnel, and an address exception breaks when the server's address changes or when the name resolves differently on the next connection.

Check the exclusion from the outside: reconnect the adapter, then confirm the SSH session survives and the proxied request still reports the server's address. A session that works until the adapter starts, then freezes, is the loop.

Follow DNS and UDP to the end of the chain

OpenSSH's dynamic forward carries TCP connections. It is not a UDP-associate or ICMP transport, and an adapter cannot invent UDP forwarding by accepting UDP packets. Anything that insists on UDP, including QUIC and WebRTC media, will either fail or fall back to TCP depending on the app.

DNS needs its own decision. An app that resolves a name locally sends the query through the normal resolver before it connects, so the tunnel carries the connection but not the lookup. A proxy-aware client with a remote-DNS option avoids that; a captured app without one does not. Check which resolver answered rather than assuming the adapter changed it.

Keep the SOCKS listener bound to loopback, verify the SSH server's host key on first use, and leave normal HTTPS validation in place for the final site. SSH protects the phone-to-server segment; it does not encrypt whatever the server does next.

Check the two lifetimes and decide

The adapter and the SSH session have separate lifetimes. If SSH drops while the adapter keeps capturing, apps can hang with no obvious error, because their packets still enter a virtual interface that no longer has a working exit. If the adapter stops, apps either go direct or are blocked, depending on the device's VPN policy.

Test both directions deliberately: kill the SSH session with the adapter running, then stop the adapter while SSH stays up. What the phone does in each case is the policy you are really deploying, whatever the setup instructions claimed.

If the workflow needs whole-device coverage with a predictable failure mode, a real IP VPN, or a maintained adapter designed for this chain, is the honest answer. A shell session left running beside an unrelated capture app is not a maintained device tunnel; it is two components with no agreement about what happens when one of them ends.

Nuŋlɔɖi siwo ku ɖe eŋu