Port Forwarding (Tunnels)
Mathematical and architectural guide to SSH Tunnels
SSH Port Forwarding (Tunneling) is often misunderstood as "magic". It is actually a robust way to map network sockets from one machine to another over an encrypted stream.
Netcatty provides a GUI Tunnel Manager that makes these ephemeral connections persistent, visible, and manageable.
The Three Forwarding Modes
Understanding the "Direction" of the tunnel is the hardest part. Let's break it down.
1. Local Forwarding (-L)
"Pull Remote to Local"
You want to access a service running on the remote server (or a machine reachable by the remote server) as if it were running on your laptop.
- Architecture:
- Netcatty opens a listener on Your Laptop (e.g.,
localhost:9000). - When you connect to
localhost:9000, Netcatty forwards the bytes to the SSH Server. - The SSH Server opens a connection to the Target (e.g.,
db-prod:5432).
- Netcatty opens a listener on Your Laptop (e.g.,
- Scenario: RDS Access
- Goal: Connect TablePlus to an AWS RDS instance (
mydb.aws.com) that is inside a VPC. - Config:
- SSH Host: Your EC2 Bastion.
- Type: Local.
- Local Port:
54320(Arbitrary free port). - Remote Host:
mydb.aws.com(DNS handled by the Bastion!). - Remote Port:
5432.
- Usage: TablePlus connects to
127.0.0.1port54320.
- Goal: Connect TablePlus to an AWS RDS instance (
2. Remote Forwarding (-R)
"Push Local to Remote"
You want to allow the remote server (or anyone who can reach it) to access a service running on your laptop.
- Architecture:
- The SSH Server opens a listener on its interfaces (e.g.,
0.0.0.0:8080). - When someone hits
http://remote-server:8080, bytes flow back down the tunnel to Netcatty. - Netcatty connects to your local service (e.g.,
localhost:3000).
- The SSH Server opens a listener on its interfaces (e.g.,
- Scenario: Webhook Testing
- Goal: Stripe needs to hit a webhook URL, but your code is on
localhost:3000. You don't want to deploy yet. - Config:
- Type: Remote.
- Remote Port:
9000. - Local Host:
127.0.0.1. - Local Port:
3000.
- Usage: Tell Stripe to send webhooks to
http://your-server-ip:9000.
- Goal: Stripe needs to hit a webhook URL, but your code is on
GatewayPorts
For Remote Forwarding to accept connections from other computers (not just the server itself), the server's sshd_config must have GatewayPorts yes. Otherwise, it only binds to loopback (127.0.0.1).
3. Dynamic Forwarding (-D)
"The Swiss Army Knife / SOCKS Proxy"
Instead of mapping one specific port, Netcatty acts as a SOCKS5 proxy server. It determines the destination on the fly based on the traffic you send it.
- Architecture:
- Netcatty opens a SOCKS listener (e.g.,
localhost:1080). - You configure Chrome/Firefox to use this proxy.
- When you type
http://internal-hr-portal/in Chrome, the browser asks Netcatty to fetch it. - Netcatty tunnels the request; the SSH server performs the lookup and fetch.
- Netcatty opens a SOCKS listener (e.g.,
- Result: You browse the web with the IP address of the server. Great for bypassing IP-whitelisted firewalls.
Troubleshooting
"Address already in use"
- Cause: You chose a Local Port (e.g., 8080) that is already taken by another app (like Docker or Node.js).
- Fix: Pick a random high port, like
54321.
"Connection Refused" (Target side)
- Cause: The Remote Host (e.g.,
mydb.aws.com) is blocking the Bastion's IP. - Check: Verify the Security Group / Firewall rules on the Target allow port 5432 from the Bastion's Security Group.
"Privileged Ports"
- You cannot bind to ports < 1024 (like port 80 or 443) unless you run Netcatty as root (Not recommended). Use ports > 1024.