Debugging SSH Remote Port Forwarding: Solving “Connection Refused” Errors with GatewayPorts Configuration


8 views

When setting up remote port forwarding with SSH, you might encounter a situation where:

  • The connection establishes successfully
  • Local port forwarding appears to work
  • But remote connections get refused

The key configuration parameters we're dealing with:

# /etc/ssh/sshd_config
GatewayPorts clientspecified

And the SSH command used for forwarding:

ssh -g -R 1234:0.0.0.0:8000 me@my-remote-host

Checking what's actually listening after establishing the connection:

netstat -tupln | grep 1234
tcp        0      0 127.0.0.1:1234          0.0.0.0:*               LISTEN
tcp6       0      0 ::1:1234                :::*                    LISTEN

Notice how it's only binding to localhost (127.0.0.1 and ::1) despite the -g flag and GatewayPorts setting.

The issue stems from a common misunderstanding of how GatewayPorts interacts with -R binding behavior. Even with:

  1. GatewayPorts clientspecified in sshd_config
  2. The -g flag on the client

The binding still defaults to localhost unless explicitly specified in the -R parameter.

The correct SSH command should specify the bind address in the remote portion:

ssh -R *:1234:0.0.0.0:8000 me@my-remote-host

Or for IPv6 support:

ssh -R [::]:1234:0.0.0.0:8000 me@my-remote-host

After establishing the connection, verify with:

ss -ltn | grep 1234
# Should show:
LISTEN 0      128           *:1234         *:*

For permanent solutions, consider adding to your SSH config:

Host my-remote-host
    RemoteForward 1234 0.0.0.0:8000
    GatewayPorts yes

Then simply connect with:

ssh my-remote-host

When exposing ports to public interfaces:

  • Use firewall rules to restrict access
  • Consider using SSH's AllowTcpForwarding in sshd_config
  • Implement authentication on your forwarded service

When setting up SSH remote port forwarding (-R flag), you might encounter a situation where:

  • The tunnel appears to establish successfully
  • Local connections to the forwarded port work
  • Remote connections get "Connection Refused"

From your debug output and configuration:

# Relevant sshd_config setting
GatewayPorts clientspecified

# SSH command used
ssh -g -R 1234:0.0.0.0:8000 me@my-remote-host

# Netstat output showing binding
tcp        0      0 127.0.0.1:1234          0.0.0.0:*               LISTEN
tcp6       0      0 ::1:1234                :::*                    LISTEN

The issue stems from how SSH binds the remote port. Despite using -g (allows remote hosts to connect) and GatewayPorts clientspecified, the port is still binding to loopback addresses (127.0.0.1 and ::1).

Solution 1: Explicit Bind Address

ssh -R *:1234:0.0.0.0:8000 me@my-remote-host

Solution 2: Modify sshd_config

# In /etc/ssh/sshd_config
GatewayPorts yes

Then restart SSH:

sudo systemctl restart sshd
  1. Check the binding after establishing the tunnel:
    sudo netstat -tulnp | grep 1234
    # Should show 0.0.0.0:1234 instead of 127.0.0.1:1234
  2. Test remote connectivity:
    curl -v http://my-remote-host:1234

If the issue persists:

# Check system-level firewall
sudo iptables -L -n -v

# Check TCP wrappers
sudo lsof -i :1234

# Verbose SSH logging
ssh -vvv -R *:1234:0.0.0.0:8000 me@my-remote-host

When opening ports to all interfaces:

  • Consider firewall rules to restrict access
  • Use SSH key authentication exclusively
  • Monitor connection attempts
  • Consider using VPN for sensitive applications

For complex networking scenarios:

# Using autossh for robust tunnels
autossh -M 0 -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" \
-N -R *:1234:localhost:8000 me@my-remote-host