An application that speaks only SOCKS has nothing to talk to on a plain VPN, because the tunnel carries packets and the app wants a proxy endpoint. OpenSSH can supply that endpoint when the access owner permits it, since dynamic forwarding turns one SSH session into a local proxy. Then there are two hops to keep straight: the tunnel that reaches the SSH host, and the connection that host makes onward. Separating them explains both why the arrangement works and what it will never do.

What the SSH listener does and does not become

Dynamic forwarding makes the SSH client listen locally and speak SOCKS4 or SOCKS5 to whatever connects. Each request names a destination and the SSH server opens the onward connection, which is why the destination lookup can happen on the far side. That is application-level TCP forwarding, not a whole-device VPN. It carries no UDP associate, no ICMP, and nothing for applications that ignore proxy settings entirely. The hop from the SSH server to the application is also not inside your tunnel, which matters when the destination accepts traffic only from known networks.

The prerequisites are real: a route to the SSH host, an authorized account, a verified server host key, and permission to forward. None of them is created by the proxy, and the last one is usually the first to be missing. Confirm all four before debugging anything else, because the failure looks identical from the client whichever one is absent.

Start it on loopback with an explicit port

Pick an unused local port and bind it explicitly to loopback rather than leaving the address off. The three options below exist for one reason each.

ssh -D 127.0.0.1:1080 -NT -o ControlPath=none -o ExitOnForwardFailure=yes \
  [email protected]

-N skips the remote command and -T skips the pseudo-terminal, so the session exists only to forward. ExitOnForwardFailure makes the client exit when the listener cannot be created, instead of running without the forwarding you asked for. ControlPath=none keeps the session out of an existing multiplexed connection that might add its own forwardings. Loopback keeps the listener off the LAN, but it is not an authorization boundary on a shared machine, because other local processes can reach it too. The OpenSSH client reference documents all of these flags, and the loopback warning follows from what a listening socket is.

Send names through the proxy, not around it

A SOCKS5 client can resolve the destination itself or ask the proxy to do it, and that choice decides which resolver answers. With socks5h, curl sends the hostname through the proxy, so the lookup happens on the SSH server. With plain socks5, the laptop resolves first and only the connection travels, which quietly defeats the point when the name is internal. The request below also clears the no-proxy list, so an inherited NO_PROXY value cannot route it around the proxy.

curl -sS --noproxy '' --proxy socks5h://127.0.0.1:1080 https://app.corp.example/health

Certificate validation and the application's own login still apply, because the proxy replaces neither. Two lookups remain: the laptop must reach the SSH host through the permitted VPN and DNS path, and the SSH server must resolve the application name itself. The second one is testable on its own before any traffic is proxied.

ssh [email protected] getent hosts app.corp.example

Prove one allowed destination, then shut the session down

Test a destination the policy allows and one it should refuse, because a working forward proves that the listener works and nothing more. The application sees the source address the SSH server chooses, which is not your laptop's tunnel address. Where the far end logs connections by source, that difference is the first thing to check when a request is rejected.

Stop the session through the process that owns it rather than by killing an unrelated shell. Then confirm the listener is gone, because a port that still answers is a session you have not actually closed. Remove only the proxy setting this exercise introduced, and leave the rest of the application configuration alone. An unattended terminal holding a forwarding rule is not a service, and a permanent proxy needs an approved lifecycle rather than a forgotten window.

ss -ltn | grep 1080

Failures this arrangement cannot fix

Some symptoms point straight at the limits above, and recognising them early saves an afternoon of proxy debugging. The table maps what you observe to what it usually means. Anything in the last column is a design question rather than a configuration mistake.

What you seeWhat it usually meansWhere to look
The app connects and nothing followsIt ignores proxy settings entirelyIts own network settings, not the SSH session
A name resolution error for the destinationThe SSH server cannot resolve itServer resolver and search domains
A UDP-only application failsDynamic forwarding carries TCP onlyThis arrangement cannot serve it
curl works, the browser does notThe browser is not using the socks5h endpointBrowser proxy configuration
The listener answers after the session endedAnother process owns port 1080The ss output, then the owning process

The first three rows are the ones people misdiagnose, because each produces a connection attempt rather than an error about the proxy itself. A name that resolves on the laptop says nothing about the server's resolver, and the failure reads as a certificate or timeout problem instead. UDP-only applications sit outside the design rather than broken inside it, and no extra ssh option changes that. The browser row is the ordinary reminder that proxy settings are per application. The last row is why the shutdown check exists: a port that still listens means something else owns it now.

ဆက်စပ်ဆောင်းပါးများ