Reverse SSH Tunnel: How to Set Up ssh -R With Examples

Ganesh Velrajan Ganesh Velrajan • 14 Min Read • Updated on Oct 27, 2026
Reverse SSH Tunnel: How to Set Up ssh -R With Examples

A reverse SSH tunnel lets you reach a device behind a NAT router or firewall without opening any inbound ports. The device runs the ssh -R command to open an outbound connection to a public SSH server, and that server forwards connections back to the device through the tunnel.

In this guide, we’ll show you how to set up a reverse SSH tunnel, keep it running and secure it. Finally, we’ll also discuss about a safer alternative for remotely accessing IoT fleets.

Quick Example

On the device, open the SSH tunnel (it runs in the foreground, so keep the terminal open):

$ ssh -NT -R 20022:localhost:22 user@your-public-server

Then, on the public server, connect to the device through it:

$ ssh -p 20022 device-user@localhost

By default, port 20022 listens only on the server’s loopback interface (127.0.0.1), so other internet hosts can’t connect to it unless you change the server configuration (see GatewayPorts). For production use, add key-based authentication and the hardening steps below.

What Is a Reverse SSH Tunnel?

Normally, an SSH client connects to an SSH server. A reverse tunnel flips this around: the server ends up connecting back to the client’s side.

A reverse SSH tunnel, also called remote port forwarding, works in the opposite direction to a normal SSH connection. A device behind NAT or a firewall opens an SSH connection out to a public server and asks that server to listen on a port. Any connection to that port is sent back through the tunnel to the device. Because the device starts the connection, the firewall treats it as normal outbound traffic.

This works even when your device is connected to a 4G/5G cellular or Starlink satellite network that uses CGNAT, as shown in our guide to SSH into NVIDIA Jetson behind CGNAT.

Hint: To better understand a reverse SSH tunnel, imagine two pipes: a small pipe within a large pipe connecting two endpoints, as shown in the diagram below.

SSH reverse tunnel shown as a small pipe inside a large pipe connecting two endpoints
  1. The large pipe: the device opens an SSH connection out to the public SSH server. This connection starts behind the NAT router or firewall and ends at the server in the cloud.
  2. The small pipe: a user logged in to the server opens a second SSH connection to the port the server is listening on. The server carries it inside the large pipe, back to the device. That return direction is why it’s called a reverse tunnel. The public server acts as an SSH reverse tunneling proxy.

The tunnel is encrypted, but encryption doesn’t control who can reach the forwarded port. That depends on authentication, forwarding restrictions and firewall rules, covered in the security section. To learn why NAT blocks inbound connections in the first place, read how NAT routers and firewalls secure devices behind them.

This approach is great for hobbyists and professionals working with IoT boards or home lab servers, but it brings real security challenges for business use.

Tired of Managing Reverse SSH Tunnels Manually?

Skip the port forwarding and security risks. Get a secure tunnel to your IoT devices instead.

ssh -L vs ssh -R: Local vs Reverse Port Forwarding

SSH supports two kinds of port forwarding. The difference is which side opens the listening port.

Local forwarding (-L)Remote/reverse forwarding (-R)
Listening port opens onYour machine (the SSH client)The SSH server
Traffic flowsClient → server → destinationServer → back through tunnel → client side
Typical useReach a service behind a server, e.g. a remote databaseReach a device behind NAT or a firewall
Examplessh -L 8080:localhost:80 user@serverssh -R 20022:localhost:22 user@server

How to create a Reverse SSH Tunnel

Let’s take the following scenario:

You have an SSH server (with public IP: 202.10.135.4) and you want to access a destination device (with local IP 192.168.1.1) behind a NAT router or firewall.

You want to access a service (SSH server or HTTP web server) running on the destination device via the source SSH server.

Source (Public IP: 202.10.135.4) => Internet => NAT => Destination(Local IP: 192.168.1.1)

Reverse SSH tunnel diagram: device behind NAT connects out to a public SSH server, which forwards connections back to the device

Step 1: Create the reverse tunnel from the device

Using an SSH client, create a reverse SSH tunnel from the device (192.168.1.1) to the server (202.10.135.4) using the following command:

$ ssh -fNT -R 20022:localhost:22 server-user@202.10.135.4

This creates a Reverse SSH Tunnel from the device to the server.

The command tells the SSH server to listen for connections on TCP port 20022 and forward them to the device’s TCP port 22 (SSH server port). The options mean:

  • -f: go to the background after authentication.
  • -N: don’t run a remote command; only forward ports.
  • -T: don’t allocate a pseudo-terminal.
  • -R 20022:localhost:22: listen on port 20022 on the server and forward to localhost: port 22 on the device. By default, the server listens on IP 127.0.0.1 only. So the user needs to login to the server to access the reverse SSH tunnel.

Step 2: Connect to the device through the server

Now, log in to the public SSH server and execute the below command to SSH into the device through the reverse SSH tunnel created in step #1:

$ ssh -p 20022 device-user@localhost

In this scenario, there are two SSH connections between the source and the destination, one within the other. We call this SSH reverse tunneling.

The first SSH connection is opened by the device to the server. The second SSH connection is opened by a user on the server, and it reaches the device through the first SSH connection. All data transmitted over the second SSH connection actually travels through the first one: the inner SSH session is carried, encrypted, inside the outer tunnel.

Note: To connect directly from another machine using the server’s public IP, as in ssh -p 20022 device-user@202.10.135.4, you first need to enable GatewayPorts on the server, as explained in the next section.

Allow External Access with GatewayPorts

By default, the server only listens on 127.0.0.1:20022, so only users logged in to that server can use the tunnel. To accept connections from other machines, edit /etc/ssh/sshd_config on the public server:

GatewayPorts clientspecified

Restart sshd:

$ sudo systemctl restart sshd

Then bind the tunnel explicitly to all interfaces:

$ ssh -fNT -R 0.0.0.0:20022:localhost:22 server-user@202.10.135.4

Now ssh -p 20022 device-user@202.10.135.4 or curl http://202.10.135.4:20022 works from any machine.

Security warning: With GatewayPorts enabled, port 20022 is open to the entire internet. Anyone who finds it can reach your device’s SSH login or web app directly, and SSH encryption doesn’t stop them from trying. Before you enable it, restrict the port to known source IPs with firewall rules, and apply the hardening steps below.

How to create a Reverse SSH tunnel with Port Forwarding?

To explain the concept of Reverse SSH Tunnel with Port Forwarding, let’s use an HTTP web server example.

Let’s say you want to access a NodeJS web application running on a different host (192.168.1.2) in the same local network as the device (192.168.1.1) behind a NAT router or firewall. Let’s assume the web application listens on TCP port 3000.

Let’s use the following simple NodeJS web application for the demo.

$ cat myapp.js
var http = require('http');
//create a server object:
http.createServer(function (req, res) {
 res.writeHead(200, {'Content-Type': 'text/html'});
 res.write("<h2>Hello World!</h2>"); //write a response to the client
 res.end(); //end the response
}).listen(3000); //the server object listens on port 3000

We can use the Reverse SSH Tunnel Port Forwarding feature to access the web application running on any host in the same local network as the device.

Here is how to do it.

Source (Server Public IP: 202.10.135.4, Port: 20022) ==> Internet ==> NAT ==> Destination(Device Local IP: 192.168.1.1) ==> Web App (Host Local IP: 192.168.1.2, Port: 3000)

Step 1: Forward the web app port from the device

Create a reverse SSH tunnel to the source (202.10.135.4) by running the following command on the device (192.168.1.1).

$ ssh -fNT -R 20022:192.168.1.2:3000 server-user@202.10.135.4

The command tells the public SSH server to forward any TCP connections (including HTTP requests) on its port 20022 to the device. The device then forwards the traffic to the neighbouring host 192.168.1.2, port 3000, where the NodeJS web application runs.

Step 2: Access the web app from the server

From the source SSH server, access the NodeJS web application behind the NAT router as follows:

$ curl http://localhost:20022
<h2>Hello World!</h2>

How to Keep a Reverse SSH Tunnel Alive

A plain ssh -R tunnel dies when the network drops or the device reboots. Use one of the following options to bring it back up automatically.

Option 1: autossh

$ autossh -M 0 -fNT -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" \
  -o "ExitOnForwardFailure yes" -R 20022:localhost:22 server-user@202.10.135.4

-M 0 turns off autossh’s own monitoring port and relies on SSH keepalives (ServerAliveInterval) to detect a dead link.

Option 2: systemd (no extra packages)

Save the following as /etc/systemd/system/reverse-tunnel.service:

[Unit]
Description=Reverse SSH tunnel to 202.10.135.4
After=network-online.target
Wants=network-online.target

[Service]
User=pi
ExecStart=/usr/bin/ssh -NT -o ServerAliveInterval=30 -o ServerAliveCountMax=3 \
  -o ExitOnForwardFailure=yes -i /home/pi/.ssh/tunnel_key \
  -R 20022:localhost:22 server-user@202.10.135.4
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

Enable and start the service:

$ sudo systemctl enable --now reverse-tunnel

Use a passwordless key, and add the server’s host key to the device’s known_hosts first (see hardening), because a service can’t answer the host-key prompt. Leave out -f under systemd, so systemd can track the process.

Troubleshooting Common Reverse SSH Tunnel Errors

“Warning: remote port forwarding failed for listen port 20022”

Cause: the port is already in use on the server, often by a stale session from an earlier tunnel. The server’s AllowTcpForwarding or PermitListen setting may also be blocking it.

Fix: check what holds the port with sudo ss -tlnp | grep 20022 and end the stale session. Set ClientAliveInterval 30 in the server’s sshd_config so dead sessions close on their own.

“Connection refused” from another machine

Cause: the forwarded port is bound to the server’s loopback interface only.

Fix: enable GatewayPorts and bind the tunnel to 0.0.0.0, then restrict the port with firewall rules.

Tunnel drops silently after a while

Cause: an idle connection was dropped by a NAT router or firewall, and SSH didn’t notice.

Fix: add ServerAliveInterval and ServerAliveCountMax, or use autossh or systemd as shown above.

“Permission denied (publickey)”

Cause: the device’s public key is missing from the server’s ~/.ssh/authorized_keys, or the file permissions are too open.

Fix: add the key and run chmod 600 ~/.ssh/authorized_keys and chmod 700 ~/.ssh on the server.

Can’t bind a port below 1024

Cause: only root on the server can listen on privileged ports.

Fix: use a port above 1024, such as 20022.

Limitations of SSH Reverse Tunnels at Scale

The main limitation of this approach is that the source SSH server must be reachable from the internet with a public IP. Otherwise, it is not possible to establish a reverse SSH tunnel from the destination to the source.

What if the source is also behind a NAT and wants to access the destination behind another NAT? What if there are more sources and destinations behind NAT in different places?

Source (Local IP: 10.1.1.1) ==> NAT ==> Internet ==> NAT->Destination (Local IP: 192.168.1.1)

Consider the following example, where a web application runs on a server behind one NAT’ed network and firewall, and the MySQL database runs on a server behind another NAT’ed network and firewall.

SSH reverse tunnels connecting a web application and a MySQL database behind two different NAT routers and firewalls

The web app can talk to the database over the internet using one SSH reverse tunnel with port forwarding.

You can access the web app over the internet using another SSH reverse tunnel with port forwarding.

You need to open two ports on the public SSH server, say port 20021 for accessing the web app and 20022 for accessing the MySQL database.

What if you have many sources and many destinations behind many different NAT’ed networks, like hundreds of thousands of IoT devices deployed at customer sites around the world?

You’d have to open that many ports on the public SSH server and keep track of which port maps to which device.

How to Secure a Reverse SSH Tunnel

SSH encrypts the tunnel, but encryption isn’t access control. Securing a reverse SSH tunnel means controlling who can authenticate, which ports each key can open, and who can reach those ports on the server.

Security risks of SSH reverse tunnels

There are some security challenges to consider when using an SSH reverse tunnel through a public SSH server in a business environment.

One of the main security challenges with SSH reverse tunneling is that it can be used to bypass firewalls. This means that an attacker could use this technique to gain access to a machine that is normally protected by a firewall.

An SSH reverse tunnel has the same security risk as an open port in a router or firewall configured for port forwarding. The only difference is that the open port is now on the public SSH server. In either case, the same technique is used: mapping a specific port on the router or server to a specific port on the device. Port scanners on the internet can still reach your device port via the open server port.

Another security challenge with SSH reverse tunneling is operationalizing it. SSH reverse tunnels are not associated with an employee ID in the IAM (Identity and Access Management) database. An IT team cannot easily track, manage and control all SSH reverse tunnels set up on a public SSH server. There is no centralized dashboard to track which port maps to what and who set it up. Let’s say an employee quits the organization and their IAM entry gets deleted, but the SSH reverse tunnel on the SSH server doesn’t get deleted automatically. The former employee could still connect to the open port on the SSH server and tunnel malicious traffic into the network.

Hardening checklist

If you use SSH reverse tunnels in a business environment, apply these security measures:

  • Use a dedicated tunnel user with no shell. Lock it down in the server’s /etc/ssh/sshd_config:
Match User tunnel
    AllowTcpForwarding remote
    PermitListen 20022
    PermitTTY no
    X11Forwarding no
    ForceCommand /bin/false
  • Restrict each device’s key in the tunnel user’s ~/.ssh/authorized_keys, so it can only open its own port:
restrict,port-forwarding,permitlisten="20022" ssh-ed25519 AAAA... device-01
  • Turn off password logins and use SSH keys or short-lived SSH certificates.
  • Pin the server’s host key on each device instead of accepting it blindly on first connect. Add the server’s key to the device’s ~/.ssh/known_hosts ahead of time and connect with StrictHostKeyChecking yes, so a device never opens a tunnel to an impostor server:
$ ssh-keyscan -t ed25519 202.10.135.4 >> ~/.ssh/known_hosts
$ ssh-keygen -lf ~/.ssh/known_hosts

Compare the fingerprint with the one shown on the server by ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub before you trust it.

  • Firewall the server so forwarded ports only accept connections from known source IPs.
  • Log and monitor tunnel activity. Set LogLevel VERBOSE in the server’s sshd_config to record which key fingerprint opened each session, and review the logs with journalctl -u ssh (the unit is sshd on some distributions). Follow the SSH security best practices for the rest.

PermitListen and permitlisten require OpenSSH 7.8 or newer.

Reverse SSH Tunnel Alternative for IoT Fleets

Reverse SSH tunnels work well for a few devices. With hundreds or thousands, you end up with one public port per device, a growing port-to-device map, keys to rotate, and tunnels that nobody remembers setting up.

SocketXP avoids this. Each device runs a lightweight agent that opens an outbound SSL/TLS tunnel to the SocketXP cloud gateway. The gateway joins your connection to the device’s tunnel only after it has verified who you are. No ports are opened on the device’s router or on a public server.

SocketXP IoT remote SSH architecture: devices connect out to the SocketXP cloud gateway over secure TLS tunnels

Self-hosted reverse SSH tunnel vs SocketXP

Self-hosted reverse SSH tunnelSocketXP
Server to runYou run, patch and protect a public VMNone. SocketXP runs the cloud gateway
Port exposureOne port per device on the server; public if GatewayPorts is onNo public ports on the device or a server
Who can connectAnyone who can reach the port and log in to the deviceOnly users verified with an auth token or SSO + MFA (Zero Trust)
Reconnect after drops or rebootsYou configure autossh or systemdAgent reconnects to the gateway automatically
Finding a deviceKeep your own port-to-device mapDashboard lists devices by name, with browser terminal
Revoking accessEdit authorized_keys and firewall rules on the serverRemove the user or device in the portal
ProtocolsAny TCP serviceAny TCP service (SSH, HTTP, VNC, RDP, MQTT)
AutomationYour own scriptsAPIs for fleet automation

A self-hosted tunnel costs nothing beyond the server and suits a few devices you manage yourself. SocketXP is built for fleets, where tracking ports, keys and access by hand stops being practical.

For step-by-step setup, see How to Securely Remote Access IoT Devices via SSH.

Conclusion

A reverse SSH tunnel is a quick, built-in way to reach a device behind NAT or a firewall: run ssh -R on the device, keep it alive with autossh or systemd, and lock down the server it connects to. For a handful of devices, that’s often enough. For IoT fleets or IT servers, the open ports and manual tracking become a security and operations problem, and a managed solution like SocketXP IoT Remote Access is the safer choice.

Frequently Asked Questions

  1. What is a reverse SSH tunnel?

    A reverse SSH tunnel is an SSH connection that starts from a device behind a NAT router or firewall and goes out to a public SSH server. The public server can then send connections back to the device through that tunnel. Firewalls usually allow outbound connections, so you can reach the device without opening any inbound ports on its network.

  2. What is the difference between ssh -L and ssh -R?

    'ssh -L' (local forwarding) opens a listening port on your own machine and forwards traffic through the SSH server to a destination. 'ssh -R' (remote or reverse forwarding) opens a listening port on the SSH server and forwards traffic back to your machine or its local network. Use 'ssh -R' when the machine you want to reach is behind NAT or a firewall.

  3. What do the -f, -N, -T and -R options mean in a reverse SSH command?

    '-f' sends SSH to the background after it authenticates. '-N' tells SSH not to run a remote command, so the connection only does port forwarding. '-T' turns off pseudo-terminal allocation. '-R 20022:localhost:22' tells the remote server to listen on port 20022 and forward those connections to port 22 on the device.

  4. Why can't I reach the reverse SSH tunnel port from another machine?

    By default, OpenSSH binds the reverse-forwarded port to the server's loopback address (127.0.0.1). Only users logged in to that server can use it. To accept connections from other hosts, set 'GatewayPorts yes' (or 'clientspecified') in the server's /etc/ssh/sshd_config and restart sshd. Doing this exposes the port to the internet, so restrict it with firewall rules.

  5. How do I keep a reverse SSH tunnel alive after a disconnect or reboot?

    Use autossh, or run plain ssh as a systemd service with 'Restart=always'. Add 'ServerAliveInterval=30', 'ServerAliveCountMax=3' and 'ExitOnForwardFailure=yes' so SSH notices a dead link and exits cleanly, and systemd then restarts it. Use key-based authentication so the tunnel can come back up without anyone typing a password.

  6. Is a reverse SSH tunnel secure?

    The traffic is encrypted, but the forwarded port on the public server works like an open port that internet scanners can find. The risks are stolen keys, forgotten tunnels, and no central record of who owns which port. To reduce them, use SSH keys or certificates instead of passwords, give the tunnel account no shell, firewall the server, and monitor its logs.

  7. Can I use a reverse SSH tunnel to access a Raspberry Pi behind CGNAT?

    Yes. CGNAT blocks inbound connections, but it treats the Pi's outbound SSH connection to a public VPS as normal traffic. Run 'ssh -R 2222:localhost:22 user@vps' on the Pi, then connect to the VPS on port 2222. You need a VPS with a static public IP, or a managed relay service like SocketXP.

  8. Do I need a public IP address or port forwarding on my router for a reverse SSH tunnel?

    You don't need port forwarding on the device's router. The relay SSH server, however, must have a public IP address that the device can reach. If both sides are behind NAT, both connect outward to the same public server, or to a cloud gateway such as SocketXP, which joins the two connections.

  9. How do I manage reverse SSH tunnels for hundreds of IoT devices?

    Each device needs its own port on the public SSH server. At scale, keeping track of which port belongs to which device, rotating keys, and revoking access becomes hard to manage and widens the attack surface. An IoT remote access platform like SocketXP gives you a central device dashboard, per-user access control and no publicly exposed ports.

  10. Can I forward other services, like a web app or database, over a reverse SSH tunnel?

    Yes. A reverse tunnel can carry any TCP service, such as HTTP, MySQL, VNC or RDP, and it can reach other hosts on the device's local network. For example, 'ssh -R 20022:192.168.1.2:3000 user@server' exposes a web app running on a neighbouring host. A reverse SSH tunnel cannot carry UDP traffic.

  11. What is the alternative to a reverse SSH tunnel for IoT remote access?

    Managed tunneling services such as SocketXP create an outbound SSL/TLS tunnel from the device to a cloud gateway. You don't run your own SSH server or expose ports publicly. Access is checked with authentication tokens or SSO plus MFA before anyone can reach the device.

  12. What port does a reverse SSH tunnel use?

    The device connects out to the server's SSH port, usually 22. You can use 443 if outbound port 22 is blocked. The forwarded listening port, such as 20022, can be any free port above 1024 unless you are root on the server. Each device needs its own unique listening port.

SocketXP IoT Remote Access and Device Management Platform

Remotely access, manage, and update your IoT & AIoT edge fleet with SocketXP's secure and scalable platform.

Start Your Free Trial Now!

Join thousands of satisfied users who trust SocketXP for a secure, reliable, and scalable IoT Edge device management solution. Start your free trial now.