Forwarding a Service via SSH Tunnels

SSH tunneling (port forwarding) lets you securely forward a network port from a remote server to another machine — all traffic is encrypted and no additional software is required beyond a standard SSH client.

The Concept

SSH tunneling works as a three-part chain. Think of it as routing traffic through a relay — you connect to the middle server, and the middle server transparently forwards your connection to the final destination:

PartRoleExample
NearYour local machine — initiates the tunnelyour laptop / workstation
MiddleAn intermediary server you can SSH into — it exposes the forwarded port209.239.112.134
FarThe final destination — the server running the service you want to reachserver935
Terminal
Near <--> Middle <--> Far

The key advantage is that Far does not need to be publicly reachable. As long as Middle can reach Far and you can reach Middle, the tunnel bridges the gap.

SSH Flags Explained

The tunnel command uses two important SSH flags:

FlagPurpose
-NDo not execute a remote command — keeps the connection open purely for port forwarding without dropping into a shell.
-LLocal port forwarding — binds a port on the middle server and forwards traffic to the far server. Format: bind-address/local-port/remote-host/remote-port
-fOptional — runs SSH in the background. Combine with -N to start the tunnel as a background process.
-vOptional — verbose output, useful for debugging connection issues.

The Command

Generic syntax

Replace the placeholders with your actual server addresses, IP, and port numbers:

Terminal
ssh -N root@middle-server -L middle-IP/middle-port/far-server/far-port

Concrete example

This opens port 110 on the middle server (209.239.112.134) and forwards all connections to port 22 (SSH) on the far server (server935):

Terminal
ssh -N root@server935 -L 209.239.112.134/110/server935/22

Any connection to 209.239.112.134:110 will be transparently forwarded to server935:22 — making the SSH service of the far server reachable via the middle server.

Run the tunnel in the background

Add the -f flag to send the tunnel to the background so your terminal remains free:

Terminal
ssh -fN root@server935 -L 209.239.112.134/110/server935/22

To stop a background tunnel, find its process ID and kill it:

Terminal
ps aux | grep ssh kill <PID>

The tunnel stays active as long as the SSH connection is maintained. If the connection drops, you will need to re-run the command to re-establish it. Consider using a tool like autossh for persistent tunnels that reconnect automatically.

Common Use Cases

Access a firewalled service
Forward a database or admin port that is not publicly exposed, through a server that does have internal network access to it.
Grant temporary access
Expose a service on a specific port to a third party without permanently modifying firewall rules — just close the tunnel when done.
Encrypted forwarding
All traffic through the tunnel is encrypted by SSH — ideal for forwarding services that do not have their own TLS encryption.
Jump host pattern
Use a publicly reachable server as a relay to reach internal servers that are not directly accessible from the internet.

Troubleshooting

ProblemLikely cause & fix
Connection refused on the forwarded portThe middle server's firewall is blocking the port. Open the port in iptables or nftables on the middle server.
Tunnel connects but immediately dropsSSH keepalive may not be configured. Add ServerAliveInterval 30 to your ~/.ssh/config.
Port forwarding is refused by the serverThe middle server may have AllowTcpForwarding no in its /etc/ssh/sshd_config. Set it to yes and restart the SSH service.
Binding to the middle server IP failsBy default, SSH only binds to localhost. Set GatewayPorts yes in /etc/ssh/sshd_config on the middle server to allow binding to its public IP.

Further Documentation

For the full reference of all SSH port forwarding options, refer to the official OpenSSH manual.