Earlier this year I needed to access a non-routed private1 IP subnet from over the Internet. The hosts on this Isolated IP subnet did not have a gateway of last resort defined and could only communicate with other hosts on the same network. What I needed from these hosts on the Isolated IP subnet was their respective VNC remote desktops.

While the Isolated IP subnet could not be directly access from over the Internet, there was a host that was upstream from the Isolated IP subnet that was dual-homed with one interface reachable and the other interface joined with the Isolated IP subnet. We’ll describe this host as the jump host.


Before diving-in the following assumptions are made:

  1. The tcp-service that is needed is already up and running on the destination host and is listening (bound) to the loopback interface. In my case I’m using the service VNC and I’ve setup this service to use tcp-port 5901.
  2. You have login shell access via SSH to the intermediary hosts where necessary.


In the following diagram the jump host for the Isolated IP subnet is shown as “Host C”.

When we make our SSH connections, it will be from “Host A”.

While “Host B” may also be considered a jump host, it is not described in that way to avoid confusion2.


The IP addressing in the following diagram shows:

  • Host A:
    • Our source IP address.
    • Gateway of last resort is connected ISP.
  • Host B:
    • Internet facing IP address.
    • Direct connection with Host C.
    • Gateway of last resort is connected ISP.
  • Host C:
    • Direct connection with Host B.
    • IP address on the Isolated IP subnet.
    • Gateway of last resort is
  • Host 1:
    • The destination IP address of what we want to connect with.
    • NO gateway of last resort, does not know how to reach the any other IP network.

The security posture is comprised of host based firewalls with the following security policies:

  • Host B:
    • Applies restrictions on source IP and destination tcp/udp ports.
    • Permits our source IP to connect with tcp-port 22
  • Host C:
    • Permits only Host B to connect via SSH to itself.

There are three connections that will be made. Each connection is an individual SSH session. Once all three sessions are established the tunnel we be formed and the remote tcp service will be available. In my case, the VNC service will be directly accessible.


The 1st connection from Host A to Host B looks like this:

ssh -4 -t -L 5901:localhost:15901 user1@

After successfully logging in as user1 on Host B we’ll then extend the tunnel to the next host.

The 2nd connection from Host B to Host C looks like this:

ssh -t -L 15901:localhost:15901 user2@

After successfully logging in as user2 on Host C we’ll then extend the tunnel to the finial destination, Host 1.

The 3rd connection from Host C to Host 1 looks like this:

ssh -t -L 15901:localhost:5901 -N user3@

After successfully logging in as user3 on Host 1 we’ll have a tunnel established between Host A tcp-port localhost:5901 and Host 1 tcp-port localhost:5901. We will remain logged in so the SSH tunnel does not disconnect.

Diagram illustrating the tunnel between Host A and Host 1.


Potential drawbacks

The approach described is not without potential drawbacks.

For example:

  • Performance may be impacted. Each connected session, and therefore each host the connection is made with, will add a degree of latency along the data-path. The tcp sessions traversing the tunnel will be variably impacted.
  • There is potential for an SSH forwarding tcp-port to already be in use; there is no warning or automatic selection of a different unused tcp-port. The new connection attempt will fail leaving you to figure it out why?.
  • If any intermediary SSH session is torn-down or broken, then the entire tunnel is torn-down and broken.


Implementing ssh keys will greatly enhance the speed and arguably the security. Couple the ssh keys with the ssh-agent and you have an efficient process. While it can take time to get ssh keys setup correctly, it is in my opinion well worth the effort3.


The SSH protocol allows for chaining these sessions together into one command-line4. For example, the following two command line variations represent the above outlined steps and are identical.

Variation 1:

ssh -4 -t -L 5901:localhost:15901 user1@ ssh -t -L 15901:localhost:15901 user2@ ssh -t -L 15901:localhost:5901 -N user3@

Variation 2:

ssh -4 -t -L 5901:localhost:15901 user1@ \
ssh -t -L 15901:localhost:15901 user2@ \
ssh -t -L 15901:localhost:5901 -N user3@

What this means is that each ssh session does not need to be entered one at a time. All sessions can be placed together as shown above and executed one-time. If ssh keys + ssh-agent are not used, then there will be 3x password prompts for each connected session. If ssh keys + ssh-agent is implemented, then there will be no prompting for a password, assuming the ssh-agent is already populated with the key password.


  1. Address Allocation for Private Internets ↩︎
  2. Potential confusion of having two jump hosts in the same diagram ↩︎
  3. Setting up ssh keys is not covered in this blog entry ↩︎
  4. Reference the man page for details. man ssh ↩︎
Last modified: 12/28/2018


Write a Reply or Comment