We use cookies for keeping user sessions alive and for site usage statistics.
Please accept cookies to continue browsing the site.


(You can decline cookies later navigating to page 'Privacy Policy'.)

Create SSH tunnel to a private network - practical steps

In most cases you do not have public access to your private network. Your router is not public, but a part of an internet provider's network segment, so it is not reachable from outside; you can only make outward requests. Thus, your computers behind the router cannot be accessed from outside, neither directly, nor via some IP address translation which might be configured on the router.

Fortunately SSH (secure shell network protocol, native to Unix/Linux, available for Windows) provides a straightthru mechanism to configure a network tunnel for bypassing above restriction.

Here are the practical steps to do it. Please note that we only provide the backbone operations, without any responsibility for correct functioning in your environment. It also fully your responsibility to estimate and realize all necessary security measures to protect your machines and your data.



At least

  • one host in a private network, with SSH server (sshd)
  • one public host, real or a VPS (virtual private server) at a cloud provider, with SSH server (sshd)


  • one private host in another network, to connect to the other private host (you can do the testing directly from within the public host as well)


Environment used

For testing the applied scheme we have used 

  • a 'Raspberry Pi 4' private network server
  • a 'Centos 8 linux' public virtual server
  • a 'Windows 10' client for testing


Let's make 4 tunnels for 4 services, runing on the private host or in the private nwtwork - SSH, RDP, HTTP and an RTSP IP camera (please check that the services are installed, running and tested).


Step 1A: Enable access to ports on the public server

Allow some freely selected ports through the firewall:

$ firewall-cmd --zone=public --add-port=48800/tcp --permanent
$ firewall-cmd --zone=public --add-port=48801/tcp --permanent
$ firewall-cmd --zone=public --add-port=48802/tcp --permanent
$ firewall-cmd --zone=public --add-port=48803/tcp --permanent

$ firewall-cmd --reload


Step 1B: Allow port forwarding on the public server

Open file /etc/ssh/sshd_config for editing and uncomment and modify (or add) following line

GatewayPorts yes


Step 2: Establish the tunnels on the private host

Supposed the port on which you access your public server via SSH is NNNN (it can be the SSH-native port 22 or some port number your cloud provider has given to you, like 4321).

Supposed the user name you use for connecting to your public server via SSH is serveruser1 and the name of your public server is publicserver1.com.

Supposed locally the services are running on following ports:

  • SSH on port 22 on the private host
  • RDP on port 3389 on the private host
  • HTTP on port 80 on the private host
  • some IP camera has IP address in the local network, listening on the usual RTSP port 554
$ ssh -N -R 48800:localhost:22 serveruser1@publicserver1.com -p NNNN
$ ssh -N -R 48801:localhost:3389 serveruser1@publicserver1.com -p NNNN
$ ssh -N -R 48802:localhost:80 serveruser1@publicserver1.com -p NNNN
$ ssh -N -R 48803: serveruser1@publicserver1.com -p NNNN

Run above commands one by one and do testing according to step 3. You will have to provide the password for your public server. Do not close the terminal after entering the password, never mind there is no answer appearing.


Step 3: Test the tunnels

Now, on the client computer you can try the tunnels, i.e. connect to your private network host and RTSP cameras through the tunnel.

Supposed the user name you use for connecting to the services on the private host/private network/RTSP camera is privatehostuser1.

To try the SSH tunnel, run in a terminal:

    > ssh privatehostuser1@publicserver1.com -p 48800

To try the RDP connection, open an RDP agent to address:


To try the HTTP server page through the tunnel, navigate in a browser to:


To see the camera, use an RTSP capable agent like VLC and open a network stream from:


That's all. If it works you can automate it as per the Optional Step 4.


Optional: Automate the tunnel establishment

Instead of manually establishing the tunnels, you can automate it using the crontab Linux utility for task scheduling.

Install the sshpass tool and add a helper file for each tunnel e.g. under /home/privatehostuser1/remote_conn/ (or combine them in a single file, if you so prefer):

  • /home/privatehostuser1/remote_conn/create-tunnel-ssh.sh
  • /home/privatehostuser1/remote_conn/create-tunnel-rdp.sh
  • /home/privatehostuser1/remote_conn/create-tunnel-http.sh
  • /home/privatehostuser1/remote_conn/create-tunnel-cam.sh

with content respectively:

/usr/bin/sshpass -p password1 /usr/bin/ssh -N -R 48800:localhost:22 remoteuser1@publicserver1.com -p NNNN
/usr/bin/sshpass -p password1 /usr/bin/ssh -N -R 48801:localhost:3389 remoteuser1@publicserver1.com -p NNNN
/usr/bin/sshpass -p password1 /usr/bin/ssh -N -R 48802:localhost:80 remoteuser1@publicserver1.com -p NNNN
/usr/bin/sshpass -p password1 /usr/bin/ssh -N -R 48803: remoteuser1@publicserver1.com -p NNNN

where password1 is the password for that remoteuser1@publicserver1.com. Be careful not to invoke a user with more privileges as required. Plus, rather do not use unencrypted passwords, but make use of some security vault/key ring (not in the scope of this article).


$ crontab -e

and add lines for the tunnel establishment on machine (re)booting like this:

@reboot sleep 45s && /bin/bash /home/privatehostuser1/remote_conn/create-tunnel-ssh.sh
@reboot sleep 45s && /bin/bash /home/privatehostuser1/remote_conn/create-tunnel-rdp.sh
@reboot sleep 45s && /bin/bash /home/privatehostuser1/remote_conn/create-tunnel-http.sh
@reboot sleep 45s && /bin/bash /home/privatehostuser1/remote_conn/create-tunnel-cam.sh


Optional: Cleanup before launching

Before recreating the tunnels it's always a good idea to cleanup, meaning to close old tunnels and free ports on the servers:

On the private host create file:

/home/privatehostuser1/remote_conn/kill-old-tunnels.sh with content

/usr/bin/sshpass -p password1 /usr/bin/ssh remoteuser1@publicserver1.com -p NNNN < /home/privatehostuser1/remote_conn/kill-old-tunnels-script.txt

and file /home/privatehostuser1/remote_conn/kill-old-tunnels-script.txt with content:

for pid in $(ps x | awk '/sshd: remoteuser1$/ {print $1}'); do echo kill $pid; kill $pid; done

Now, if the tunnel establishment is automated by means of crontab, run 'crontab -e' and add following line BEFORE the lines creating tunnels:

@reboot sleep 30s && /bin/bash /home/privatehostuser1/remote_conn/kill-old-tunnels.sh


Optional: Keep SSH sessions alive

In order to prevent session closing on inactivity, just include SSH options -o ServerAliveInterval=60 -o ServerAliveCountMax=10 -o ExitOnForwardFailure=yes, so that the content of the files create-tunnel-ssh.sh, create-tunnel-rdp.sh, create-tunnel-http.sh and create-tunnel-cam.sh becomes, respectively:

/usr/bin/sshpass -p password1 /usr/bin/ssh -o ServerAliveInterval=60 -o ServerAliveCountMax=10 -o ExitOnForwardFailure=yes -N -R 48800:localhost:22 remoteuser1@publicserver1.com -p NNNN
/usr/bin/sshpass -p password1 /usr/bin/ssh -o ServerAliveInterval=60 -o ServerAliveCountMax=10 -o ExitOnForwardFailure=yes -N -R 48801:localhost:3389 remoteuser1@publicserver1.com -p NNNN
/usr/bin/sshpass -p password1 /usr/bin/ssh -o ServerAliveInterval=60 -o ServerAliveCountMax=10 -o ExitOnForwardFailure=yes -N -R 48802:localhost:80 remoteuser1@publicserver1.com -p NNNN
/usr/bin/sshpass -p password1 /usr/bin/ssh -o ServerAliveInterval=60 -o ServerAliveCountMax=10 -o ExitOnForwardFailure=yes -N -R 48803: remoteuser1@publicserver1.com -p NNNN


Don't forget to replace the indicative host names, user names and passwords with those of your convenience.

Happy remoting!




Back to List