Forwarding a Service via SSH Tunnels
This guide explains how to make a service on a remote Linux server reachable through an intermediary server using SSH port forwarding (ssh -L). The traffic is encrypted and you only need a standard OpenSSH 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:
| Part | Role | Example |
|---|---|---|
| Near | The client that wants to use the service — connects to the forwarded port on Middle | your laptop / workstation |
| Middle | The intermediary server on which you run the ssh command — it opens the forwarded port | 209.239.112.134 |
| Far | The final destination — the server running the service; Middle connects to it via SSH | server935 |
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:
| Flag | Purpose |
|---|---|
| -N | Do not execute a remote command — keeps the connection open purely for port forwarding without dropping into a shell. |
| -L | Local port forwarding — opens a port on the machine where you run ssh (here: the middle server) and forwards traffic through the SSH connection to the far server. Format: bind-address/local-port/remote-host/remote-port |
| -f | Optional — runs SSH in the background. Combine with -N to start the tunnel as a background process. |
| -v | Optional — verbose output, useful for debugging connection issues. |
The Command
Generic syntax
Run the command on the middle server and replace the placeholders with your actual server addresses, IP and port numbers:
Concrete example
Run on the middle server, this command opens port 110 on its IP 209.239.112.134 and forwards all connections to port 22 (SSH) on the far server (server935):
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:
To stop a background tunnel, find its process ID and kill it:
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
Troubleshooting
| Problem | Likely cause & fix |
|---|---|
| Connection refused on the forwarded port | The tunnel is not running, or the middle server's firewall is blocking the port. Check the ssh process and open the port in iptables or nftables on the middle server. |
| Tunnel connects but immediately drops | SSH keepalive may not be configured. Add ServerAliveInterval 30 to your ~/.ssh/config. |
| Port forwarding is refused by the server | The SSH server you connect to (the far 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 fails | Ports below 1024 (such as 110) can only be opened by root, and the port must not already be in use. Also check that the bind address is an IP of the middle server. Without an explicit bind address, SSH only binds to localhost. |
Further Documentation
For the full reference of all SSH port forwarding options, refer to the official OpenSSH manual.