Consider the following scenario:

On my local desktop I am using docker to do some testing with a Mongo database. My router doesn't expose the Mongo port. A friend at work needs to access my awesome and suuuuper important data in Mongo but he's also behind a firewall.

In other words:

  • I cannot directly connect to my friend's work computer
  • My friend cannot directly connect to my work computer

The solution is to use an intermediate host (a cheap VPS :)) so that both can connect there and exchange data.

Here's what the diagram of this looks like:

Reverse SSH tunnel that forwards    +----------------------------+     SSH tunnel that forwards 127.0.0.1:36531
127.0.0.1:36531 to the internet     |                            |     to the local 127.0.0.1:27017.
accessible server +---------------> | internet accessible server | <-----------------+This is initiated by my
at 127.0.0.1:36531|                 | with SSH listening on      |                   |friend at work.
This is initiated |                 | non-standard port 22222    |                   |
on my desktop.    |                 |                            |                   |
                  |                 | No other ports are open.   |                   |
                  |                 +----------------------------+                   |
                  |                                                                  |
                  |                                                                  |
                  |                                                                  |
                  |                                                                  |
                  |                                                                  |
                  +                                                                  +
              +---------------------+                            +-----------------------+
              |                     |                            |                       |
              | My desktop - it's   |                            | Friend at work who is |
              | not accessible from |                            | behind a firewall and |
              | the internet and    |                            | wants access to my    |
              | Mongo is listening  |                            | Mongo installation    |
              | on 127.0.0.1 on a   |                            |                       |
              | non-standard port   |                            |                       |
              | 36531               |                            |                       |
              +---------------------+                            +-----------------------+

On the internet-accessible server:

(It is assumed you have already created an instance/VPS/droplet (whatever your provider calls it)) :

1. SSH into the instance

2. Install net-tools so you can get netstat

yum install net-tools -y

3. Edit /etc/ssh/sshd_config, find the line with:

#Port 22

and change it to:

Port 22222

4. Restart the SSH daemon:

systemctl restart sshd

5. Confirm that SSH is listening on port 22222 using netstat -ntlp | grep sshd:

netstat -ntlp | grep sshd
tcp 0 0 0.0.0.0:22222 0.0.0.0:* LISTEN 980/sshd 
tcp6 0 0 :::22222 :::* LISTEN 980/sshd 

6. Add a user:

useradd lampros

7. Set some password:

This will prompt you for your password twice:

passwd lampros

8. Now I'll add a user for my friend at work - this user won't have shell access and no home directory:

useradd --no-create-home --no-user-group --shell /sbin/nologin friend-at-work

9. Set a password for him:

This will prompt you for your password twice:

passwd friend-at-work

On my desktop:

1. Use docker to start Mongo 3.6 and set it to listen to 127.0.0.1:36531:

docker run -dt --name mongo -p 127.0.0.1:36531:27017 mongo:3.6

2. Confirm that Mongo is listening on 127.0.0.1:36531 by using netstat -ntlp | grep 36531:

lampros@portable-goat:~$ netstat -ntlp | grep 36531
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
tcp 0 0 127.0.0.1:36531 0.0.0.0:* LISTEN -

3. Sanity check - try to access Mongo's port using curl - you should get a response:

curl 127.0.0.1:36531
It looks like you are trying to access MongoDB over HTTP on the native driver port.

4. Forward 127.0.0.1:36531 to the internet-accessible server over port 22222 to 127.0.0.1:36531 - you'll be prompted for the password you set earlier

ssh -p22222 -nN -R 36531:127.0.0.1:36531 lampros@104.245.32.196

5. Back on the internet-accessible server - confirm that the port is forwarded:

netstat -ntlp | grep 36531
tcp 0 0 127.0.0.1:36531 0.0.0.0:* LISTEN 1012/sshd: lampros 
tcp6 0 0 ::1:36531 :::* LISTEN 1012/sshd: lampros

6. And once again check with curl:

curl 127.0.0.1:36531
It looks like you are trying to access MongoDB over HTTP on the native driver port.

Now my friend at work needs to do the following:

1. Forward port 36531 from the internet-accessible server to 127.0.0.1:27017:

ssh -4 -p22222 -N -L 27017:127.0.0.1:36531 friend-at-work@104.245.zzz.yyy

2. Test that it works:

curl 127.0.0.1:27017
It looks like you are trying to access MongoDB over HTTP on the native driver port.

Yay!

Sources: