SSH Tunneling Explained: Securely Accessing Remote Services
Use SSH tunneling to reach private databases, web apps, and remote services with local, remote, and dynamic forwarding.
SSH Tunneling Explained: Securely Accessing Remote Services
SSH tunneling helps you reach remote services without opening those services to the internet. If your database, admin dashboard, or development server is only reachable from a bastion host, an SSH tunnel can give your local tools a safe path to it.
The main patterns are local forwarding, remote forwarding, and dynamic forwarding. Each one answers a different question: do you need to reach something remote, expose something local, or create a SOCKS proxy?
What is SSH Tunneling?
SSH tunneling wraps application traffic inside an SSH connection. Instead of connecting directly to a service, you connect to a local or remote forwarded port. SSH carries that traffic through the encrypted session and connects to the final destination from the correct side of the tunnel.
The tunnel encrypts traffic between your SSH client and the SSH server. If the final destination is beyond the SSH server, that last leg uses whatever security the destination service provides. For sensitive services, keep TLS or native encryption enabled even when you tunnel.
Types of SSH Tunnels
SSH offers three main types of port forwarding, each serving a different purpose:
1. Local Port Forwarding (-L)
Local port forwarding is the most common type. It allows you to forward traffic from a port on your local machine to a port on a remote machine (or a machine accessible from the remote SSH server). This is ideal for accessing services running on a remote server's internal network or on the server itself, which are not directly accessible from your local network.
How it works: The SSH client listens on your machine. The SSH server connects to the destination.
Use case: Accessing a MySQL database on port 3306 that only the bastion host can reach.
Command Syntax:
ssh -L [LOCAL_PORT]:[DESTINATION_HOST]:[DESTINATION_PORT] [SSH_USER]@[SSH_SERVER]
Example:
Suppose you have a MySQL database running on db.internal.example.com (port 3306) and you can only SSH into bastion.example.com. To access the database from your local machine on port 8888:
ssh -L 8888:db.internal.example.com:3306 [email protected]
After running this command, you can open your local MySQL client and connect to localhost:8888. The traffic will be securely tunneled through bastion.example.com to db.internal.example.com:3306.
Use -N when you do not need a remote shell:
ssh -N -L 8888:db.internal.example.com:3306 [email protected]
For scripts, add -o ExitOnForwardFailure=yes so SSH exits if the local listener cannot be created.
2. Remote Port Forwarding (-R)
Remote port forwarding does the opposite of local forwarding. It allows you to forward traffic from a port on the remote SSH server to a port on your local machine or a machine accessible from your local machine. This is useful for exposing a service running on your local machine (or a machine on your local network) to the remote server or its network.
How it works: The SSH server listens on a remote port. Your SSH client connects to the destination from your side of the tunnel.
Use Case: Allowing a remote colleague to access a web development server running on your local machine (e.g., a Flask app on port 5000) without exposing your local machine directly to the internet.
Command Syntax:
ssh -R [REMOTE_PORT]:[DESTINATION_HOST]:[DESTINATION_PORT] [SSH_USER]@[SSH_SERVER]
Example:
Suppose you are running a web application on your local machine at localhost:5000. You want to allow a user on remote.example.com to access it by connecting to port 9000 on remote.example.com.
ssh -R 9000:localhost:5000 [email protected]
In typical OpenSSH configurations, the remote listener is available only on the SSH server's loopback interface. That means users on the remote host can test localhost:9000, but other machines cannot necessarily reach remote.example.com:9000.
To expose the listener to other machines, you usually need a bind address such as 0.0.0.0 in the command and a server-side GatewayPorts setting such as clientspecified or yes. Be cautious: remote forwarding can expose services on your laptop or local network to the remote network.
3. Dynamic Port Forwarding (-D)
Dynamic port forwarding creates a SOCKS proxy on your local machine. Instead of forwarding traffic to a specific destination, it allows applications configured to use this SOCKS proxy to connect to any host and port accessible from the SSH server. This effectively turns your SSH connection into a versatile proxy server.
How it works: Your SSH client listens as a SOCKS proxy. Applications that support SOCKS send requests to that local proxy, and the SSH server makes the outbound connection.
Use Case: Securely browsing the web from a public Wi-Fi network by routing all your browser traffic through an SSH server at home or in your office. This encrypts your browsing activity.
Command Syntax:
ssh -D [LOCAL_PORT] [SSH_USER]@[SSH_SERVER]
Example:
To create a SOCKS proxy on your local machine listening on port 1080:
ssh -D 1080 [email protected]
After running this command, configure your browser or other application to use a SOCKS proxy at localhost:1080. If the application supports remote DNS over SOCKS5, enable it when DNS privacy matters.
Practical Applications and Benefits
SSH tunneling offers a wide range of practical applications:
- Secure Database Access: Accessing databases (like PostgreSQL, MySQL, or MongoDB) that are only accessible from a specific server in a private network, without exposing the database port directly to the internet.
- Accessing Internal Web Services: Connecting to internal web applications, administrative interfaces, or monitoring dashboards that are not publicly exposed.
- Securing Unencrypted Protocols: Wrapping insecure protocols like VNC, FTP, or plain HTTP within an encrypted SSH tunnel, providing confidentiality and integrity.
- Working through network restrictions: Accessing services through a server that is allowed to reach them. Only do this when it complies with your organization's network policy.
- Secure Remote Development: Providing secure access to development environments or tools running on remote servers.
Takeaway
Use local forwarding when your laptop needs access to a private remote service. Use remote forwarding when a remote host needs temporary access to a service near you. Use dynamic forwarding when you need a SOCKS proxy through a trusted SSH server. Keep the tunnel as narrow as possible, and close it when the job is done.