Table of Contents >> Show >> Hide
- What Is an SSH Tunnel?
- Common Types of SSH Tunnels on Linux
- Before You Start: What You Need
- How To Make a Local SSH Tunnel on Linux
- Use -N When You Only Want the Tunnel
- Run an SSH Tunnel in the Background
- How To Tunnel to a Remote Database
- How To Make a Reverse SSH Tunnel
- How To Create a SOCKS Proxy with SSH
- Use an SSH Config File for Cleaner Tunnels
- Useful SSH Tunnel Options
- Testing an SSH Tunnel
- Common SSH Tunnel Problems and Fixes
- Security Best Practices for SSH Tunneling
- Practical SSH Tunnel Examples
- When Should You Use an SSH Tunnel?
- Field Notes: Real-World Experience Making SSH Tunnels on Linux
- Conclusion
An SSH tunnel on Linux is one of those tools that feels like wizardry the first time it works. One minute, a database, admin panel, internal web app, or private server is locked away behind a firewall. The next minute, you open a local port on your laptop andta-dait behaves as if the service is sitting right next to your terminal, sipping coffee. No cape required.
In simple terms, SSH tunneling, also called SSH port forwarding, lets you send network traffic through an encrypted SSH connection. Instead of connecting directly to a service, your Linux machine connects to an SSH server, and that server forwards the traffic to another destination. This is useful for securing unencrypted services, accessing private systems, creating temporary SOCKS proxies, reaching development tools behind firewalls, and avoiding the classic “Can someone open port 5432?” conversation that ruins everyone’s afternoon.
This guide explains how to make an SSH tunnel on Linux using practical commands, real-world examples, troubleshooting tips, and security habits that keep your tunnel helpful instead of horrifying.
What Is an SSH Tunnel?
An SSH tunnel is an encrypted pathway created through the SSH protocol. The SSH client on your Linux machine listens on one port, sends traffic through a secure SSH session, and forwards it to a destination host and port. The destination might be on the remote server itself, on a private network reachable from that server, or even on your local machine when using a reverse tunnel.
Think of it like a sealed tube between your laptop and a remote server. Anything you push into one end travels safely through the tube and comes out where you tell SSH to send it. That “where” depends on the type of tunnel you create.
Common Types of SSH Tunnels on Linux
1. Local Port Forwarding
Local port forwarding is the most common type of SSH tunnel. It opens a port on your local Linux machine and forwards traffic through the SSH server to a target service.
Basic syntax:
Example:
This command opens port 8080 on your local machine. When you visit http://localhost:8080, SSH forwards the request to port 80 on example.com from the remote server’s point of view.
Local forwarding is great for accessing remote dashboards, web apps, databases, Redis instances, internal APIs, and admin tools without exposing them publicly.
2. Remote Port Forwarding
Remote port forwarding works in the opposite direction. It opens a port on the remote SSH server and forwards traffic back to your local Linux machine or another host reachable from your machine.
Basic syntax:
Example:
This makes port 9000 on the remote server forward back to port 3000 on your local machine. It is useful when you are developing a local web app and need a remote system to reach it.
Remote forwarding is often used for temporary demos, support sessions, IoT devices behind NAT, private development servers, and emergency “I need to reach this thing from over there” situations. Use it carefully, because exposing a local service on a remote machine can create security risks if you bind it too broadly.
3. Dynamic Port Forwarding
Dynamic port forwarding creates a SOCKS proxy. Instead of forwarding one specific local port to one specific destination, it lets applications route different connections through the SSH server dynamically.
Basic syntax:
Example:
This starts a SOCKS proxy on localhost:1080. You can configure a browser, terminal tool, or application to use that SOCKS proxy. The traffic then exits from the remote SSH server.
Dynamic forwarding is handy when you need a lightweight, temporary proxy. It is not a full VPN, but it can feel like a tiny pocket-sized VPN that lives in your terminal.
Before You Start: What You Need
To create an SSH tunnel on Linux, you need a few basics:
- A Linux machine with the OpenSSH client installed
- SSH access to a remote server
- A username for the remote server
- A password or SSH key
- The host and port of the service you want to reach
- Permission to forward traffic on the systems involved
Most Linux distributions include the SSH client by default. To check, run:
If SSH is missing, install it with your distribution’s package manager.
On Ubuntu or Debian:
On Fedora:
On Arch Linux:
How To Make a Local SSH Tunnel on Linux
Let’s say you have a remote server named server.example.com. On that server, a web application is listening on localhost:8080, but the firewall blocks public access. You want to open that app from your Linux laptop.
Run:
Now open your browser and visit:
Your browser connects to port 3000 on your laptop. SSH carries the traffic through the encrypted session to server.example.com, then sends it to localhost:8080 from the server’s perspective.
The most important detail is this: target_host is interpreted from the remote SSH server’s point of view. If you use localhost in the middle part of the command, it means “localhost on the SSH server,” not “localhost on my laptop.” This single detail saves hours of forehead-to-keyboard debugging.
Use -N When You Only Want the Tunnel
If you only want the tunnel and do not need an interactive shell, add -N.
The terminal will appear quiet because SSH is not opening a shell. That is normal. The tunnel stays active as long as the SSH command keeps running.
Run an SSH Tunnel in the Background
To send the tunnel to the background, use -f with -N:
This is convenient, but remember that background tunnels can become invisible little gremlins. If you forget they exist, you may wonder why a port is already in use later.
To find SSH tunnel processes:
To find what is listening on port 3000:
Then stop the process with:
How To Tunnel to a Remote Database
SSH tunnels are often used to connect safely to private databases. Suppose PostgreSQL is running on a private server at db.internal on port 5432. The database is not reachable from your laptop, but your SSH server can reach it.
Run:
Then connect your local PostgreSQL client to:
Your local port 5433 forwards to db.internal:5432 through bastion.example.com. Using 5433 locally avoids conflict if you already have PostgreSQL running on your own machine at port 5432.
How To Make a Reverse SSH Tunnel
A reverse SSH tunnel is useful when your local machine is behind a firewall or NAT, but you can SSH out to a public server.
Suppose you have a local development app running at:
You want a remote server to access it through port 9000. Run:
From the remote server, requests to localhost:9000 will be forwarded back to your local app on port 3000.
By default, many SSH servers bind remote forwarded ports to the remote server’s loopback interface only. That means the tunnel may be reachable from the server itself, but not from the public internet. This is usually safer. If you intentionally need outside systems to reach the remote forwarded port, the SSH server may need GatewayPorts configured in sshd_config. Do not enable broad exposure unless you understand the security impact.
How To Create a SOCKS Proxy with SSH
Dynamic forwarding is excellent when you want a browser or command-line tool to send traffic through an SSH server.
Start a SOCKS proxy:
Then configure your browser to use:
For command-line tools, you can test with curl:
The --socks5-hostname option tells curl to resolve DNS through the SOCKS proxy, which can help avoid DNS leaks in some use cases.
Use an SSH Config File for Cleaner Tunnels
If you use the same tunnel often, stop punishing your fingers. Add it to your SSH config file:
Example:
Then start the tunnel with:
This is easier to remember, easier to share with teammates, and less likely to turn into a command-line spaghetti monster.
Useful SSH Tunnel Options
-p: Use a Custom SSH Port
This connects to SSH on port 2222 instead of the default port 22.
-i: Use a Specific SSH Key
This is useful when you manage different keys for different servers.
-v: Debug the Connection
Add more verbosity with -vv or -vvv if the tunnel is being stubborn. SSH will politely overshare, which is exactly what you want during troubleshooting.
ExitOnForwardFailure: Fail Fast
This tells SSH to exit if it cannot establish the forwarding. Without it, you might think your tunnel is working when the forwarding part failed. That is not a tunnel; that is a confidence trick.
Testing an SSH Tunnel
After creating a tunnel, test it locally.
For a web service:
For a database port:
To confirm the local port is listening:
If the command shows a listener on the expected port, the local side is active. If the service still does not respond, the problem may be on the remote side, the target host, the target port, DNS resolution, firewall rules, or application configuration.
Common SSH Tunnel Problems and Fixes
Problem: “Address already in use”
Another process is already using the local port. Choose a different local port or stop the existing process.
Problem: The tunnel connects, but the app does not load
Check whether the target host is correct from the SSH server’s perspective. If you used localhost, remember that it refers to the remote SSH server, not your local laptop.
Problem: Permission denied
SSH authentication failed. Verify your username, server address, key path, key permissions, and whether the server allows your account to log in.
Problem: Remote forwarding does not expose the port publicly
This may be expected. Many SSH servers bind reverse tunnels to 127.0.0.1 by default. If public exposure is required, server-side configuration may be necessary, but review the security risk before changing it.
Problem: The tunnel drops after inactivity
Use keepalive options:
This helps SSH detect broken connections and avoid silently stale tunnels.
Security Best Practices for SSH Tunneling
SSH tunnels are powerful, and powerful tools deserve respect. A tunnel can bypass network boundaries, so treat it like a temporary privileged pathway.
- Bind local tunnels to
127.0.0.1unless other machines truly need access. - Use SSH keys instead of passwords whenever possible.
- Protect private keys with strong passphrases.
- Avoid forwarding sensitive services to public interfaces.
- Use
ExitOnForwardFailure=yesfor production-like workflows. - Close tunnels when you are done.
- Limit forwarding permissions on shared servers.
- Log and monitor tunnel usage where security policy requires it.
The safest SSH tunnel is specific, temporary, and boring. Boring security is underrated. Exciting security usually means someone is having a very bad day.
Practical SSH Tunnel Examples
Access a Remote Web Dashboard
Open http://localhost:8080 in your browser.
Access MySQL Through a Bastion Host
Connect your MySQL client to localhost:3307.
Create a SOCKS Proxy
Configure your application to use localhost:1080 as a SOCKS5 proxy.
Expose a Local Development App to a Remote Server
From the remote server, access localhost:9000.
When Should You Use an SSH Tunnel?
Use an SSH tunnel when you need secure, temporary access to a service that should not be exposed directly to the internet. It is especially useful for developers, system administrators, DevOps engineers, database administrators, security teams, and anyone who has ever looked at a firewall rule request form and whispered, “There has to be a better way.”
Good use cases include private database access, remote admin dashboards, internal APIs, development previews, SOCKS proxy browsing, lab environments, and emergency troubleshooting. Bad use cases include permanent production networking, undocumented access paths, public exposure of sensitive ports, and “I forgot this tunnel was running for three months.” For long-term infrastructure, consider a VPN, private network, zero-trust access tool, or managed bastion solution.
Field Notes: Real-World Experience Making SSH Tunnels on Linux
The most important lesson from using SSH tunnels in real Linux environments is that the command is usually easier than the mental model. People often memorize ssh -L examples, but the real magic happens when you understand the path traffic takes. Your local application connects to a local port. SSH carries that traffic to the remote server. Then the remote server connects to the target host and port. Once that clicks, troubleshooting becomes much less mysterious.
In day-to-day development work, local forwarding is the hero. A common pattern is tunneling into a private database through a bastion host. Instead of opening the database to the internet, you map a harmless local port like 5433 to the private database’s 5432. Your database GUI thinks it is connecting to your own laptop, but the encrypted SSH tunnel quietly handles the journey. This keeps the workflow simple while avoiding risky public database exposure.
Another lesson: always choose local ports intentionally. If PostgreSQL already runs locally on 5432, do not fight it. Use 5433. If a web app uses 8080, try 8081 or 3000. Many “SSH tunnel is broken” moments are really just “something else is already listening on that port” moments wearing a fake mustache.
The -N option is also worth adopting early. When the goal is tunneling, not shell access, -N keeps things clean. Pair it with ExitOnForwardFailure=yes, and you avoid the awkward situation where SSH logs in successfully but the port forwarding silently fails. In professional workflows, that small option can save a surprising amount of confusion.
For longer sessions, keepalive options matter. Coffee shops, hotel Wi-Fi, VPN changes, laptop sleep, and flaky networks can all leave tunnels in weird states. Adding ServerAliveInterval and ServerAliveCountMax helps SSH detect dead connections instead of leaving you with a tunnel that looks alive but behaves like a cardboard cutout.
Reverse tunnels deserve extra caution. They are incredibly useful when you need a remote server to reach something on your laptop, but they can also expose services in surprising ways. Before using -R, ask who can reach the remote port. Is it bound to localhost only? Is it public? Does the local app have authentication? A reverse tunnel can be a lifesaver during troubleshooting, but it should not become an accidental production doorway.
Finally, document your recurring tunnels. A simple entry in ~/.ssh/config is cleaner than a 130-character command pasted from an old chat message named “DO NOT DELETE FINAL REAL ONE.” Give each tunnel a meaningful host alias, store the forwarding rule, and include keepalive settings. Future you will be grateful, and future you is notoriously hard to impress.
Conclusion
Learning how to make an SSH tunnel on Linux gives you a practical, secure way to reach private services without opening unnecessary ports to the world. Local forwarding helps you access remote services from your machine. Remote forwarding lets a remote server reach a local service. Dynamic forwarding creates a SOCKS proxy for flexible traffic routing. Together, these tools make SSH much more than a login command.
The key is to understand direction, destination, and scope. Know where the port listens, where the traffic exits, and who can access it. Use SSH keys, bind carefully, close tunnels when finished, and reach for config files when commands become repetitive. With those habits, SSH tunneling becomes one of the most useful Linux skills in your toolkitsmall enough for a quick fix, strong enough for serious work, and elegant enough to make you look suspiciously competent.
Note: The commands in this article are practical examples. Replace usernames, hostnames, ports, and key paths with values that match your own Linux environment and security policy.