Reverse SSH Tunneling

Have you ever wanted to ssh to your Linux box that sits behind NAT? You can to that by using reverse SSH tunneling. This document will show you step by step how to set up reverse SSH tunneling. The reverse SSH tunnel should work fine with any Unix like system.

Setup a Reverse SSH Tunnel

Let's assume that Destination's IP is (Linux box that you want to access).

You want to access from Linux client with IP

Destination ( <- |NAT| <- Source (

1. SSH from the destination to the source (with public IP) using the command below:

ssh -R 19999:localhost:22 [email protected]

* port 19999 can be any unused port.

2. Now you can SSH from source to destination through SSH tunneling:

ssh localhost -p 19999

3. 3rd party servers can also access through Destination (

Destination ( <- |NAT| <- Source ( <- Bob's server

3.1 From Bob's server:

ssh [email protected]

3.2 After the successful login to Source:

ssh localhost -p 19999

* the connection between destination and source must be alive at all time.

Tip: you may run a command (e.g. watch, top) on Destination to keep the connection active.

Share this page:

45 Comment(s)

Add comment

Please register in our forum first to comment.


By: Fred

Step 1

I recommand to use ssh option -f to detach ssh process from the tty and -N to not execute any command over ssh (the connexion is just used for port forwarding)

Using key authentication (option -i) is quite better too and make this command to be run within a boot script (like /etc/rc.local) :

ssh -i /path/to/priv/key/id_rsa -f -N -R 19999:localhost:22 [email protected]

Step 3

In your example, you have to give a shell access to to a foreign user (bob) in order to let him connect to destination.

If bob does not need any shell access to, you can specify the remote port forwarder to listen on one specific interface or any (instead of by default) :

ssh -i /path/to/priv/key/id_rsa -f -N -R *:19999:localhost:22 [email protected]

But take care this last command makes the destination UNIX system being exposed to Internet via IP filtering and/or a knockd daemon are recommanded on if you do not want an internal server being scanned.


Great suggestions, Fred.


By: Anonymous

if the gateway has openssh running, and you have access to it, this works nicely: Host internal.hostname.tld internal User jsmith HostName internal.hostname.tld ProxyCommand ssh [email protected] nc %h %p 2> /dev/null than just `ssh internal' gets you in without need for tcp forwarding, nor reverse ssh port forwarding. it just works.

By: Anonymous


first of all, thanks for this great tutorial. I ran into some trouble first, and I got this "Address family not supported by protocol" when I tried to use the reverse tunnel to go from HOME back into the LABNODE, which is behind the firewall. It's because the LABNODE  didn't know about 'localhost'. I changed it to and now it works.

Here's my setup for user 'labuser' on the LABNODE from which I open the initial (reverse) tunnel to my HOME node.

I'm using a config file which lives in $HOME/.ssh/config - this file is only readable/writeable by the owner itself ( chmod 600 $HOME/.ssh/config ). This is how the file looks - 'babylon' is the username on my HOME computer.

Host myHome
User babylon
RemoteForward 20023

First I open the reverse tunnel on LABNODE :

 ssh myHome
<enter password for babylon on HOME computer>

 Then i drive home, have a coffee and use my HOME computer to reconnect trough the firewall into the LABNODE:

ssh -p20023  [email protected] 

 After entering the password, I am back on my LABNODE. 

 If you get bored of always typing your password, you can generate ssh-keys on LABNODE and HOME. Then you copy the content of the public key files into the authorized_keys files on the other host. Do NOT copy your private key id_rsa file.

[email protected]> ssh-keygen -t rsa
(do not enter a passphrase)
[email protected]> cat $HOME/.ssh/
[email protected]> vi $HOME/.ssh/authorized_keys
(copy-and-paste key into authorized_keys)
[email protected]> chmod 400 $HOME/.ssh/authorized_keys

 Now run this for the other host as well and you're set !

By: Anonymous

I've reversessh working on a openwrt device but now i like to connect to the webbrowser on the remote router.

Situation: I've two routers with openwrt. From router A i already have a reverse ssh connection to router B.

At the router A i can connect to B with the command: ssh -p5014 localhost

How can i connect to a webserver running on router B using the tunnel ? 

By: Samat

This can be combined autossh to make sure the connection is restarted if it ever dies. I run the following from my Debian's /etc/rc.local, called /etc/tunnel/

SSH_OPTIONS="-i /etc/tunnel/$HOSTNAME.key"
# Always assume initial connection will be successful
# Disable echo service, relying on SSH exiting itself

autossh -f -- $SSH_OPTIONS -o 'ControlPath none' -R 19999:localhost:22 [email protected] -fN

By: Beppe

Hi, maybe the is not the default unless you specify the "GatewayPorts yes" options in your /etc/ssh/sshd_config and restart the sshd service.

So if you have only "GatewayPorts no" (even if commented) then the reverse tunnel bind just on even using -R *:19999:localhost:22 [email protected] or nothing like -R 19999:localhost:22 [email protected]

By: Anonymous

Reverse tunneling is very, very useful but only in quite specific cases. Those cases are usual the result of extreme malice and or incompetence of network staff.

By: Anonymous

The only difficult part here is to determine what's the most common attribute of most IT/networking departments: Malice or incompetence. My last IT people had certainly both.


By: Anonymous

Not if you build appliance products which you sell to others which, when you need to support them, will generally be running behind NAT. You need the appliance to, when the customer clicks the button when asked to by support, create a reverse tunnel that allows support to connect in without the customer having to port forward through their firewall reducing their security.

Same for companies moving equipment between buildings that have no on-site IT staff: Rather than punch holes through a firewall to allow anyone to connect and play, it might be more secure to make equipment tunnel back to HQ and remain connected instead of sitting there ready for anyone to connect. At least in this instance, you don't have an open port in your firewall, and the box with reverse tunnel configured won't accept connections from anyone but the host it's reversing for.

This said, there are myriad other ways of achieving security even if you do punch holes in the firewall, eg. Port Knocking, but if you do punch holes through the firewall if it's not properly configured your open ports will be visible to anyone who knows how to use nmap.

By: Anonymous

Nothing to do on the iPhone. Most jailbreaks include OpenSSH or you can download (Cydia) OpenSSH onto your iPhone.

 After joining iPhone to Mac over WiFi on unsecured 40-bit WEP connection. We write down the iPhones IP# (169.254.x.y) and then don't even touch the iPhone again, instead we just reverse proxy a secure (SSH) SOCKS proxy back into the iPhone and gain access to the internet through the now tethered iPhone. (No need for any Apple banned applications from the App Store)...

MacbookPro17$ ssh -ND 9999 [email protected]

I've changed my iPhone root password, but if you have not, the default password is Alpine (change it right away after your first SSH into your phone).

 Now on the MacbookPro17 laptop I just use localhost and port 9999 as the SOCKS proxy and a simple browse in iPhone Safari or checking of Mail will flip the iPhone into accessing the internet which is now wide open for use by the MacbookPro17 laptop to use.

 SSH, freeing the masses everywhere!

By: Anonymous

Make sure you are not in violation of a company security policy when doing this. At the company I work for you can be fired for violating the security policy and I know that is true elsewhere.

By: dietrich

If you add to your /$HOME/.ssh/config the following directive TCPKeepAlive=yes or add an 'o'ption switch on the command line ssh -o TCPKeepAlive=yes

you'll be able to maintain your reverse tunnel connection.

By: Anonymous

Those one liners are OK until multiple ports need to be opened.  A better way is to set it up in your ~/.ssh/config file:

Host remotehost
  User remoteuser
  HostKeyAlias remotehost
  ConnectionAttempts 3
  TCPKeepAlive no
  CheckHostIp no
  RemoteForward 20023 localhost:22
  RemoteForward 2221 lhost1:22
  RemoteForward 2222 lhost2:22
  RemoteForward 2389 lhost3:389
  RemoteForward 2390 lhost4:389
  RemoteForward 2391 lhost5:389
  RemoteForward 20080 lhost6:80
  RemoteForward 20443 lhost6:443
  LocalForward 3001 remotehost:3000
  LocalForward 8001 remotehost:8000
  ForwardAgent yes
  ForwardX11 yes
  Protocol 2

 What we have above is a two way tunneling: 

    - RemoteForward - reverse tunneling from the remote host to the source the tunnel is initiated from

   -  LocalForward - enabling reverse local foward to local system from a system that is behind a firewall we are making connection to.

 SSH tunneling is a blessing and a curse at the same time.  The blessing because I can walk around NAT and firewalls and a curse of all Network admins who want to keep their networks under tight control...



By: Anonymous

 I use this program for a remote printing setup.

I do a config for about 12 localhost ports that cups prints to and they goto the corresponding ip addresses at the branch office. I have multiple configs for each of our branches and its really a cheap way to do remote from server printing with out costly VPN hardware and problems.

Some like this for my dedicated user's $HOMEDIR/.ssh/config

Host remoteofficeprint1
        KeepAlive yes
        User roprint
        IdentityFile    ~roprint/.ssh/specialkey1
        LocalForward    9102
        LocalForward    9103
        LocalForward    9104
        LocalForward    9105
        LocalForward    9106
        LocalForward    9107
        LocalForward    9108
        LocalForward    9109
        LocalForward    9110
        LocalForward    9111
        LocalForward    9120
        LocalForward    9127

Then I use this command from a screen session (as roprint):

        autossh -M 17004 remoteofficeprint1

 of course there has to be a proper setup on the destination to accept the pubkey auth. Autossh keep the connection up, if it can connect and login the tunnel is UP, never down, except when there is a real traffic problem on the internet. Some of our tunnels are between continents, the simplicity of autossh is what makes its so great!

It could just as easily be used for reverse tunnels. And can be configured to run from an init process, so its even possible to do more stuff.

By: Anonymous

Another option that would end up being more scalable would be to just setup a VPN service on your NAT router at home.  If your router can run the dd-wrt firmware, this is pretty easy to setup. Otherwise you could run the VPN service on your linux box, and just forward the ports.

By: Fred Feirtag

I've looked at reverse ssh tunnelling, but I think what most people really want is ppp-over-ssh.  Reverse ssh tunnelling presupposes that the firewalling allows ports like 19999 through.  In many cases it's going to be better to go exclusively through whatever port is being used for ssh, 22 or otherwise.  An example of ppp-over-ssh would be:

 sudo /usr/sbin/pppd updetach pty \
"sudo ssh sudo /usr/sbin/pppd notty"

which provides a ppp0 interface on each of the two machines.

--Fred Feirtag

By: Anonymous

Helpful information, thanks!

By: Anonymous

Thank a lot!!!!

By: Anonymous

Using ports below 1024 for anyone other than root will result in this error:

"remote port forwarding failed for listen port"

By: Anthony

Is there some way to get a linux box (not multi-user) to permit non-root processes to open restricted low ( < 1024) ports? Windows machines have no such restrictions, and it is a silly restriction for private single user linux machines to require root for that task. I know about a kludge-hack involving using a suid program and LD_PRELOAD to fake a library so as to pre-open a restricted port. See 'user_lowport' program creating in this development package... But I am looking for a more general relaxation of the rules.

By: Anonymous

Just wrt point 2 if you keep getting your password refused try changing point 2 to be:

 ssh [email protected] -p 19999

 where you know the root password and enter the password when prompted. Obviously root can be changed to some other username too as long as you know that username's password.

By: Anonymous

I don't get what is supposed to be reverse about this normal plain ssh tunnel.

The name is misleading in my eyes, it is just a vanilla ssh tunnel, port forwarding.


By: Anonymous

This is 'reverse' because most ssh tunneling opens a port on the local machine an forwards connections from that port on the originating machine to somewhere on the other end of the connection.

The 'reverse' connection here opens port(s) on the remote machine, and forwards it to a port on the local machine.

The direction of the connections has been reversed.

By: Anonymous

Should bullet 3. read like this instead?...

3rd party servers can also access through Destination Source (

Destination ( <- |NAT| <- Source ( <- Bob's server

By: fkasmani

what if both source and destination are behind NAT?

By: Jay P

Then you'd have to use another computer/server as an intermediary(aka:middleman). 


-Reverse SSH from the Target PC to the middleman:

ssh -R {PortOnMiddlePC}:localhost:{PortOnTargetPC} {UserOnMiddlePC}@{IPofMiddlePC}

ssh -R 19999:localhost:22 [email protected]


-Now from the Client PC pull the port down from the middleman:

 ssh -L {PortOnClientPC}:localhost:{PortOnMiddlePC} {UserOnMiddlePC}@{IPofMiddlePC}

ssh -L 19999:localhost:19999 [email protected]


-Now you can ssh the Target PC from the Client PC:

ssh localhost -p {PortForwardedFromTargetPC}

ssh localhost -p 19999

By: Anonymous

Does not seem to work unless the Target PC is also running a ssh server.

By: meow

You are kidding, right? Needless to say in any circumstances a sshd is required running on the target PC, that is the whole point.

By: Anonymous

none of this is Linux specific. It will work for FreeBSD as well. please fix the article

By: Miti

Thanks, I really needed it.

By: Valery

thank you for the guide!

What if I don't want to give Bob an access to the Source? is it possible to forward his request via Source's 19999 port to the Destination?..

By: mit

That divine *: was the missing link to get my configuration complete. Many thanks for the hint.

By: yuzhen

Nice explanation , I finally understand how it works after searching on this topic for 2 days ,but is it possible that I can use Windows as my Source platform ?If possible , Which software should I use ?

By: Claus Rabbe

Good and short one! As for me, I am a lazy person, I prefer to use cloudport for tunnels ;)

By: Sam Smith

Great post. Short and sweet. Thanks for sharing.


--Sam SmithTechnology Evangelist and Aspiring Chef.

By: Chris

You need to edit sshd_conf first and set GatewayPorts to yes

By: Dara Adib

If Bob doesn't trust Source, Bob can use ProxyCommand to proxy through Source with end-to-end encryption, see ssh_client_config_example.

I also suggest using SSH keepalives with ServerAliveInterval and ServerAliveCountMax and something to restart ssh. I'm doing this with sidedoor, a Debian/Raspbian/Ubuntu SSH connection daemon, basically a wrapper script.

By: Visitor

I am trying to setup a reverse ssh tunnel for https protocol (well, actually I am using this to host a small intranet web server which I like to use Let's Encrypt certificate). It worked well, but some proxy/firewall did not like that, and they cannot complete the hand-shake because some mystery causes:

~$ curl -s -v https://XXX:4334/

*   Trying PPPP...

* Connected to PPPP (PPPP) port ppp (#0)

* Establish HTTP proxy tunnel to XXX:4334


> Host: XXX:4334

> User-Agent: curl/7.47.0

> Proxy-Connection: Keep-Alive


< HTTP/1.1 200 Connection established


* Proxy replied OK to CONNECT request

* found 149 certificates in /etc/ssl/certs/ca-certificates.crt

* found 602 certificates in /etc/ssl/certs

* ALPN, offering http/1.1

* gnutls_handshake() failed: The TLS connection was non-properly terminated.

* Closing connection 0

Interestingly, squid would not make any mistake by this situation

By: Robert

Is it possible for a private web server running connected to the internet with a SIM 4G? IP is dynamic, it is behind NAT. Thank you

By: joe

is this executed from the destination computer or the source comptuer ?


1. SSH from the destination to the source (with public IP) using the command below:


ssh -R 19999:localhost:22 [email protected]



By: tony

Great great article, thanks very much

By: Nagarjuna Reddy

can you please help me for remote access. i want to connect destination using remote connectivity.



Destination_IP :


and Destination_username: debian.

please help me on how to connect.

By: John terllo

This is a great article!

By: Leo