You turned on the hotspot, connected the VPN, opened a port in the app, and the other device still cannot connect. The missing piece is almost never the port itself. It is the question of which machine owns the listening socket and which address another device is supposed to reach. I walk this from the phone outward, because the screen you are on tells you which of the three entry points you are actually testing.

Start where the service actually runs

Open the app that is supposed to accept the connection and read its own status page. If it says it is listening, note the address it bound to, because that single detail decides most of the cases below. An app bound to 127.0.0.1 is reachable only from the phone itself, and no hotspot client, carrier mapping or VPN exit will change that.

Then confirm which device runs the service. It is either the phone, in which case the socket belongs to that app, or a laptop behind the hotspot, in which case the listener and its firewall belong to the laptop and the phone is only forwarding packets. Those are different designs with different owners, and mixing them is why a port opened in one place does nothing in the other.

On a debuggable build, adb shell can list sockets through /proc/net/tcp, but for most people the app's own status is the honest source. It also avoids the trap of testing a socket that the app opened on an address you did not expect.

Entry point one: another device on the hotspot

This is the local case and the easiest to get right. The other device reaches the phone at the address it sees as its gateway, on the port the app listens on, and nothing outside the hotspot has to be involved. No carrier mapping is needed, and no provider feature has to exist, because the traffic never leaves the local segment.

Two things break it. The app bound to loopback, or the client policy on the phone does not permit the local connection. Test with the application's own protocol rather than a bare TCP connect if the app authenticates, because a listener that accepts and then rejects looks identical to a closed port from a distance.

If the service runs on a tethered laptop instead, the phone's hotspot address is not the destination at all. You need the laptop's address on the hotspot interface and a listener on the laptop, and the phone is no longer the owner of anything except forwarding.

Entry point two: the carrier path

Reaching the phone from the mobile network is a different problem, and most of the time it simply does not work for IPv4. Carriers put handsets behind shared translation, which is why RFC 6598 sets aside a shared address range for exactly that arrangement. An unsolicited inbound connection has no mapping to arrive through, and no amount of local configuration creates one, because the translator is not your device.

Root access does not change that either. It gives you control of the phone's stack, not of the carrier's translator, and recipes that promise otherwise usually assume a public address the carrier never assigned. Where the carrier offers a public IPv6 prefix, an inbound path may exist, but the listener and the phone's firewall still need deliberate authorization before anything answers.

Entry point three: the VPN exit

The address a website reports while the tunnel is up is the exit's address for covered outbound traffic. That is not the same thing as an address that accepts inbound connections on your behalf. Using it inbound requires a feature the provider actually offers, such as a forwarded port or an inbound mapping tied to your account, plus a usable path from the exit to the client.

A local allow rule cannot manufacture that mapping. What it can do is change which path the app's replies take, which matters when the app is excluded from the tunnel: the request and the reply can end up in different network contexts, and the connection fails in a way that looks like a firewall problem.

Test one path end to end, then name the owner

Write the tuple down before testing: intended source, destination address, transport, port, and the machine that owns the listening socket. If any element is a guess, the test will not tell you anything useful, and you will end up changing a second layer to explain the first.

Then test that one authorized path with the application's authentication intact. Avoid publishing a broad listener or disabling unrelated controls just to make an ambiguous public-address check answer, because both changes outlive the test and neither proves the design works.

Android's tethering subsystem forwards downstream traffic on its own path, separate from ordinary application VPN capture, so a working browser on a tethered laptop says nothing about inbound access to a service on the phone. Before you call it working:

  • The listening socket is on an address the intended peer can reach, not loopback.
  • The peer is using the address that belongs to that entry point, not the exit address from a status page.
  • Any mapping on the carrier or provider side is a supported feature, not a rule you added locally.
  • Request and reply travel through the same network context, and the app's authentication still passes.

Akụkọ ndị metụtara ya