What's Actually Happening

You've set up an SSH reverse tunnel to expose a local service through a remote server, but when you try to connect to the tunnel from another machine, the connection fails. The tunnel appears to be running, but external connections are rejected or simply don't reach your local service.

The Error You'll See

When testing from another machine:

bash
$ nc -zv remote-server.com 8080
nc: connect to remote-server.com port 8080 (tcp) failed: Connection refused

Or when checking on the remote server itself:

bash
$ ss -tlnp | grep 8080
127.0.0.1:8080    LISTEN    1234/sshd

Notice the tunnel is only listening on localhost (127.0.0.1), not on all interfaces.

Why This Happens

SSH reverse tunnels bind to localhost by default for security reasons. The GatewayPorts option in sshd_config controls whether tunnels can listen on all interfaces. When GatewayPorts no is set (the default), your tunnel only accepts connections from the remote server itself, not from external hosts.

Step 1: Check Current Tunnel Status

On the remote server, verify where your tunnel is listening:

bash
ss -tlnp | grep <port>

If you see 127.0.0.1:<port>, the tunnel is not accessible externally. You can also check active SSH tunnels:

bash
netstat -tlnp | grep sshd

Step 2: Enable GatewayPorts on the Server

Edit the SSH daemon configuration on the remote server:

bash
sudo nano /etc/ssh/sshd_config

Add or modify this line:

bash
GatewayPorts clientspecified

This allows clients to specify binding addresses. Then restart SSH:

bash
sudo systemctl restart sshd

Step 3: Create the Tunnel with Proper Binding

When establishing the reverse tunnel, specify that it should bind to all interfaces:

bash
ssh -R 0.0.0.0:8080:localhost:3000 user@remote-server.com

The 0.0.0.0: prefix tells SSH to bind to all network interfaces, not just localhost.

Step 4: Verify the Tunnel Binding

On the remote server, check that the tunnel now listens on all interfaces:

bash
ss -tlnp | grep 8080

You should now see:

bash
0.0.0.0:8080    LISTEN    1234/sshd

Step 5: Test from External Host

From a different machine, test the connection:

bash
curl http://remote-server.com:8080

Or use netcat:

bash
nc -zv remote-server.com 8080

Verify the Fix

The tunnel is working correctly when:

  1. 1.ss -tlnp shows 0.0.0.0:<port> or :::<port> as the listening address
  2. 2.External hosts can connect to the remote server on the forwarded port
  3. 3.Your local service receives the traffic

If you still have issues, check firewall rules on the remote server:

bash
sudo iptables -L -n | grep 8080
sudo ufw status

Add firewall rules if needed:

bash
sudo ufw allow 8080/tcp