What's Actually Happening
SSH port forwarding (tunneling) lets you forward traffic from a local port through an SSH connection to a remote destination. When it fails, you typically see errors about connection refused or channel open failures.
The Error You'll See
$ ssh -L 8080:localhost:80 user@server
channel 0: open failed: connect failed: Connection refusedOr when trying to use the tunnel:
$ curl http://localhost:8080
curl: (7) Failed to connect to localhost port 8080: Connection refusedWhy This Happens
- 1.Target service not running - The service you're trying to reach through the tunnel isn't listening
- 2.Wrong target host/port - You specified the wrong destination in the -L argument
- 3.GatewayPorts disabled - Server doesn't allow remote port forwarding
- 4.AllowTcpForwarding disabled - Server explicitly disabled port forwarding
- 5.Firewall blocking - Local or remote firewall blocking the connection
Step 1: Understand the Port Forwarding Syntax
ssh -L [local_port]:[target_host]:[target_port] user@ssh_serverFor example:
- -L 8080:localhost:80 - Forward local 8080 to SSH server's port 80
- -L 8080:internal.server:80 - Forward local 8080 to internal.server's port 80 (via SSH server)
Step 2: Verify the Target Service
On the SSH server, check if the target is accessible:
```bash # If forwarding to localhost:80 on the SSH server ssh user@server "curl -I http://localhost:80"
# If forwarding to another internal server ssh user@server "curl -I http://internal.server:80" ```
If this fails, the target service isn't running or accessible.
Step 3: Check Server Port Forwarding Settings
grep -E "AllowTcpForwarding|GatewayPorts" /etc/ssh/sshd_configIf AllowTcpForwarding no, the server has disabled port forwarding. Change it:
sudo sed -i 's/#AllowTcpForwarding yes/AllowTcpForwarding yes/' /etc/ssh/sshd_config
sudo systemctl restart sshdStep 4: Test the Tunnel
Start SSH with verbose output:
ssh -v -L 8080:localhost:80 user@serverLook for:
- debug1: Local connections to LOCALHOST:8080 forwarded to remote address localhost:80
- debug1: channel 0: new [port listener]
Step 5: Check for Port Conflicts
Make sure the local port isn't already in use:
# On your local machine
netstat -tlnp | grep 8080
# Or
lsof -i :8080If something is already listening on port 8080, either stop it or use a different local port.
Step 6: Dynamic Port Forwarding Alternative
For more flexibility, use dynamic port forwarding (SOCKS proxy):
ssh -D 1080 user@serverThen configure your application to use SOCKS proxy at localhost:1080.
Verify the Fix
```bash # Start the tunnel ssh -L 8080:localhost:80 user@server -N -f
# Test the tunnel curl http://localhost:8080
# Should see the target service response ```