what I'm trying to do is to enable a Raspberry, physically placed in a client's site, that has internet access via Dynamic IP, to receive SSH commands from the wild without having to manipulate the client's router and firewall. No Inbound connections allowed on that network, plus, the internet address of the Client's site is dynamic.

Edit: to know the solution for this problem, refer to the replies of Kevin_Kinsey and Florin Godard, or scroll to the end of my question to know how I was able to get it working on non-standard SSH port 22.

I've already tried to study and understand what's proposed on ssh to private-ip on Unix Stack Exchange, but I'm really not getting the point.

I do want to connect from my, say, laptop, to the Client's VPS server, and make the VPS server connect to the Raspberry SSH. So:

           ( firewall access allow in+out )
      | =>           VPS Server              \    ( firewall access allow out only )
      |                                      | =>    Raspberry
MY PC /

Here is it a case scenario with given IP adresses, ports and names configurations:

MY PC 
    name: mypc@local.lan

Client VPS Server
    name: remote.null.tld
    IP Address: 98.76.54.32
    SSH Port: 9876

Raspberry
    model: Zero W
    name: raspi1@clientlocal.lan
    IP Address: dynamic IP ( based on Internet Provider )
    SSH Port: 6789
    Raspberry's iptables: empty
    Router's Firewall Restrictions: allow only out
    Internet stability: very low

The Raspberry's external IP is the one assigned from the Internet Provider, and may vary depending on router restarts. Cannot determine it absolutely.

Internet Access on the client's network is really unstable. Radio link or something like that. Anyway, internet connection suffers of very dancing bandwidth.

Plus, the Client's router cannot be manipulated not because of laziness but because of restrictions imposed by the Client's IT dep.

I do have SSH access to the Client's VPS and I'm able to install whatever software on it.

Edit: solution to the problem

On my configuration, ports were non-standard. So, the solution was this one:

On the Raspberry:

# login to username@remote.null.tld is done via private/public key with no passwords
ssh -p 9876 -f -N -T -R 55555:localhost:6789 username@remote.null.tld

On the Raspberry's crontab:

# A re-connect is performed at every 10th minute of every hour to prevent accidental tunnel breakdowns.
10 * * * * ps -ef | grep 'ssh -p 9876 -f -N -T -R' | grep -v grep | awk '{print $2}' | xargs -r kill -9 && sleep 30s && ssh -p 9876 -f -N -T -R 55555:localhost:6789 username@remote.null.tld >/dev/null 2>&1

On the bridge VPS remote.null.tld

ssh -p 55555 raspberry_username@localhost

Or, a more elegant solution via modifying the VPS's ssh config:

Host tunnelToRemoteRaspberry
    Hostname localhost
    User raspberry_username
    Port 55555
  • 1
    I'd take a look at having the RPi run a cronjob that SSH'es out to a known server and port forwards on that known machine (the "-L" switch) ... you could then connect to that port on the server and be inside the RPi. – Kevin_Kinsey Nov 19 at 16:14
  • @Kevin_Kinsey can you please expand on your kind suggestion based on my question's case scenario config? – Maurizio Nov 19 at 17:26
  • Been a long time since I had this working ... I will look & see what I can dig up. – Kevin_Kinsey Nov 19 at 17:31
  • Look up "reverse port forwarding" on A Major Search Engine. I found an entry in the blog at "devolutions dot net" that looks promising. – Kevin_Kinsey Nov 19 at 17:41
  • I've attempted to encapsulate this concept in an answer, below. – Kevin_Kinsey Nov 19 at 17:46
up vote 4 down vote accepted

This is possible. Use "reverse port forwarding". You'll probably need a cronjob set up to check if it's connected. If not, run something like this:

ssh -f -N -T -R 2210:localhost:22 me@example.com

"Example.com" is some server outside the FW that you do have access to. You're forwarding port 22 on the RPi to port 2210 on example.com. You can then SSH into example.com and do:

ssh RaspberryUser@localhost -p 2210

And you'll be connected to the RPi box.

  • 1
    As for what the cronjob/test would look like, there are probably a lot of way to skin that cat. – Kevin_Kinsey Nov 19 at 17:49
  • 1
    I've been able to manage to get it working by merging your reply with the one of Florin Godard. Thank you for your time! – Maurizio Nov 21 at 12:15

I am assuming the user names remote on the VPS and pi on the raspberry.

  1. You choose a free port on the VPS. A random five-digit value below 65000 should work.
  2. On the Raspberry, you run

    ssh -R PORT:localhost:22 remote@vps
    
  3. On the VPS, you connect to the Raspberry with

    ssh -p PORT pi@localhost
    

Replace the PORT with the port you have chosen in the first step.

In step 2, you create a reverse tunnel from the PORT on the VPS to port 22 on the Raspberry, which is where the Raspberry's SSH server listens. In step 3, you connect to the PORT on the VPS and get transferred to the port 22 on the Raspberry.

You can then configure a connection inside the VPS' ~/.ssh/config such as:

Host raspberryTunnel
  Hostname localhost
  User pi
  Port PORT

If that works reliably, you can replace the single SSH connection on the Raspberry with autossh, which will automatically recreate the connection when it goes down.

autossh -R PORT:localhost:22 remote@vps
  • Thank you Florin, I've tried to simulate what you suggest by: On the Raspberry: ssh -p 9876 -R 63876:localhost:9876 myuser@remote.null.tld On the VPS: ssh raspberryTunnel ( after editing the .ssh/config file ) On the Raspi side, I'm able to make an SSH connection to the VPS. On the VPS side, while trying to connect, i get: myuser@localhost's password: Providing the myuser's password gives a "Permission denied, please try again.". Unfortunately I'm not understanding what's happening under the hood :( – Maurizio Nov 19 at 17:34
  • @Maurizio note that if the username is not same on VPS and rpi, you will have to specify it... for example step2 would be ssh -R PORT:localhost:22 vpsuser@vps and step3 ssh -p PORT raspi1@localhost. Also you must enter vps password in step2, and raspberryPi password in step3. – Matija Nalis Nov 19 at 20:37
  • 1
    Admittedly, it is a bit confusing. What happens is that the SSH command from the raspberry open a reverse tunnel from PORT on the VPS to port 22 on the Raspberry. So when you connect to the PORT on the VPS, you get actually connected to port 22 on the Raspberry, where the SSH server listens. So, as Matija said, you need to set the correct users, I'll update the answer. – Florin Godard Nov 19 at 21:16
  • @FlorinGodard I've been able to manage to get it working by merging your reply with the one of Kevin_Kinsey. Thank you for your time! – Maurizio Nov 21 at 12:14

What you're trying to do exactly as you ask is impossible:

No Inbound connections allowed on that network

However, you can easily:

  • have the Pi make an outbound connection to your laptop using reverse SSH that you schedule
  • ssh from your laptop to the VPS server and from the VPS server ssh again to the Pi
  • Thank you Fabby, would you try and give me an advice on how to for the two methods you suggested? – Maurizio Nov 19 at 12:38
  • 5
    If @Maurizio has outbound access, he can create a reverse SSH tunnel to a machine on the Internet and then connect back to the PI through that SSH connection. It is not impossible, it is only impossible to initiate the connection from the outside to the inside. – number9 Nov 19 at 13:33
  • @Maurizio Clarified answer. (Prego.... ;-) ) – Fabby Nov 19 at 19:24
  • @number9 Clarified answer. – Fabby Nov 19 at 19:24
  • 1
    This. We had pretty much the same scenario and the device would just be set up to "dial home" every hour or so (could be configured) to pick up any new instructions. Where feasible it would maintain a VPN connection to home, and with that in play you could SSH using its IP on the VPN. It was flaky but that's literally the best you can do. – Lightness Races in Orbit Nov 19 at 20:04

Essentially, you can reach your goal only with maintenance connections from the device to a server you maintain.

What exactly these connections consist of can be different:

  • connect, fetch tasks to execute and proceed with them.
  • connect to a VPN and be part of that, allowing to be connected to
  • connect via SSH and establish a tunnel connection

Usable protocols

  • VPN (uses several ports)
  • SSH
  • HTTPS
  • even UUCP, although a little bit outdated

Depending on what the customer allows inside their network, you can even implement several of these methods to then choose from.

Each method has its pros and cons.

  • SSH:

    • +: only one port needed
    • -: maybe not every network allows outbound SSH connections
  • VPN:

    • +: easiest integration into server's network
    • -: several ports needed
    • -: maybe not every network allows outbound SSH connections
  • HTTPS:

    • +: probably supported
    • -: no real command line, only "work packages" are sendable
    • -: big effort needed to set up
  • UUCP:

    • +: allows batches to be sent
    • -: outdated protocol
  • what do you suggest is the best approach based on my question's case scenario config? – Maurizio Nov 19 at 17:28
  • @Maurizio As said, that depends on what the customer allows. – glglgl Nov 20 at 7:51

If Pi firewall doesn't allow incoming connections then there is no way to establish connection. Your only way is to punch a hole through a firewall by using established connections.

I'd check out ZeroTier: it lets you set up a virtual network with the rules you want, e.g., that any node can directly connect to any other node. They handle all kinds of connectivity issues under the hood, including relaying traffic through their servers if needed.

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.