Even a laptop behind carrier NAT can serve a colleague, as long as the VPN server acts as the meeting point. Two mechanisms get there: the client dials out and asks the server to hold a listening port, or the server publishes a port and translates it into the tunnel. Both solve the same reachability problem and behave differently under failure, supervision and logging. Three conditions decide which one belongs in your setup.

Two shapes, one meeting point

In the first shape the client opens an SSH session outward and asks the server to listen on a chosen port, forwarding each connection back down that session. Nothing is forwarded on the server and no packet translation happens, so the only requirements are an SSH account, a permitted forward and a firewall rule for the port. The service stays bound to loopback on the client, which is usually what you want.

ssh -N -R 8081:127.0.0.1:8080 -o ExitOnForwardFailure=yes -o ServerAliveInterval=30 [email protected]

In the second shape the server owns the public port and rewrites each connection toward the client tunnel address. That needs IP forwarding enabled, a destination translation on the way in and a source translation on the way out, and it keeps working when no SSH session exists. The port belongs to the server rather than to a session, which is the property that decides most real cases.

Neither shape is more secure by construction. Both end up exposing one service port to whoever can reach the server's public address, and both still depend on the service's own authentication.

Condition one: must the port outlive the session

A reverse forward lives exactly as long as the SSH session that created it. When the link drops, the listener disappears and the colleague sees a connection refused rather than a slow path. Supervising the command with a systemd unit and a restart policy fixes that, and ExitOnForwardFailure=yes makes a failed bind visible immediately instead of leaving a session that runs with no forward.

A translated port survives reboots if the rules are persisted, but it depends on the client keeping the same tunnel address. A dynamic pool that hands the laptop a different address after a reconnect silently points the rule at nothing. Reserve the tunnel address first, then write the rule, and treat the two as one change.

If the service has to answer at three in the morning with nobody watching, the server-published port is the shape with fewer moving parts, because the only process that must stay up is the tunnel itself.

Condition two: who owns the firewall and the logs

The reverse shape keeps all policy in two places. sshd decides whether remote forwards are allowed at all through AllowTcpForwarding, and GatewayPorts decides whether the listener binds to loopback or to every address. With the default no, a colleague outside the server cannot reach the port even though the forward succeeded, and that looks like a broken tunnel when it is really a bind address.

sudo ss -ltn '( sport = :8081 )'
sudo grep -E '^(GatewayPorts|AllowTcpForwarding)' /etc/ssh/sshd_config

The translated shape needs forwarding enabled and two rules, and the second rule is where most recipes go wrong. Scoping the source translation with the conntrack DNAT state means only the connections that the destination rule created get rewritten, instead of every packet the server sends into the tunnel.

sudo sysctl -w net.ipv4.ip_forward=1
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 8081 -j DNAT --to-destination 10.88.0.6:8080
sudo iptables -t nat -A POSTROUTING -o tun0 -m conntrack --ctstate DNAT -j SNAT --to-source 10.88.0.1

That rewrite also destroys attribution. After that rewrite the client sees every caller as the server's tunnel address, which collapses any per-address rate limit into one bucket and hides who sent what. If attribution matters, terminate the connection on the server or keep the permit decision there and pass an identity in a header the service trusts. Choosing between those two fixes depends on whether the service reads a proxy header at all.

Condition three: one port or many, and who owns the name

A single service on a single port is the case where the reverse forward wins on effort. You need one command, one account and one firewall rule, and cleanup is killing the session. Multiple services on the same public address push you toward the server-published shape, because each reverse forward needs its own server port and the set grows with every service.

Names complicate it further. A reverse forward can sit behind a TCP proxy that routes by SNI, while a translated port is usually one port per service. If the service terminates TLS itself and needs the original hostname, the proxy approach preserves it and the DNAT approach preserves it only if the service accepts that hostname on that port.

Write down which of the three conditions decided the shape. The next person to add a second service will otherwise re-open the same comparison with less context.

Decide, then test from outside

Test the path from a network that has no route to the laptop, and watch the counters on the server while the request runs. Testing from the server toward its own public address proves nothing here, because the packet is created locally and never reaches the incoming translation hook, so the test can pass while the real path is broken.

sudo iptables -t nat -L PREROUTING -n -v
sudo tcpdump -ni any 'tcp port 8081' -c 20

Counters that stay flat mean the packet never arrived at the rule, which points at the provider or the host firewall. Counters that move while the service refuses point at the client's own firewall or the address the service listens on. A tunnel that carries the packet but returns nothing is a route or reverse-path problem, and none of these three outcomes should be debugged by editing the client adapter. Write down which counter moved before you change anything, because the next test needs that baseline.

Once the shape works, record the port, the owner and the supervision method next to the tunnel configuration. A reachability fix that only exists in someone's shell history is one reboot away from being a repeat incident.

Amanqephe ahlobene