Tag Archives: tunnel

Access to device over 3g mobile internet or NAT

The problem is to present access to your device (pc, raspberry etc) which has usb-dongle (or wifi) connected to mobile internet provider.
So, in this case you have no public (white) IP address and this is the challenge!

The solution i advice is to use SSH tunnel. For this you need public SSH server accessible from the world. If has one go ahead!

Part 1. Configure public SSH server!
Add to “/etc/ssh/sshd_config”:

PermitTunnel yes
ClientAliveInterval 60
GatewayPorts yes

Restart service:

sudo systemctl restart sshd.service

And that’s it for changes on public side. All other is related to your private (local, intranet, etc) machine.

Part 2. Make public-private key pair!
Install SSH client. For Ubuntu use:

sudo apt install openssh-client

To connect to our public SSH server we’ll use key-based authorization.


Attention! Set empty passphrase for key pair!

Copy public SSH key to public SSH server

ssh-copy-id -i ~/.ssh/mykey @

Start SSH agent and load your new key:

eval `ssh-agent -s`
ssh-add ~/.ssh/mykey

Now you’ve successfully logged in to you public SSH server:

ssh -i ~/.ssh/mykey @

If not, check all steps in this part.

Part 3. Make robust SSH tunnel through 3g/4g/etc channel!
You know if you have no dedicated IP in your internet service provider the IP address will change unpredictable. And this is the problem for creating SSH tunnels. Even you read anywhere about autossh that’s doesn’t help. So, let’s build our system will recreate SSH tunnel each time when public IP address is changed.

Install SSH server. For Ubuntu use:

sudo apt install openssh-server

For the next step we need to create a few files:
The main one is “~/tun_manager.sh”


echo [ $(date +%Y-%m-%d\ %H:%M:%S,%3N) ]

# Settings

# Init log
if [ ! -f $IP_LOG ]; then
  echo "" > $IP_LOG

# Start SSH tunnel if not exists
if [ -n "$PID" ]; then
  echo "SSH tunnel is already created"
  ~/tun_start.sh &
  sleep 3
echo "Pid: $PID"

echo "Check new public IP..."

# Get current IP
CURRENT_IP=$(dig +short myip.opendns.com @resolver1.opendns.com)
echo "Current IP: $CURRENT_IP"

if [ -z "$CURRENT_IP" ]; then
  echo "Current IP is empty. Exit."
  exit 0

# Get last IP
LAST_IP=$(tail -n 1 $IP_LOG)
echo "Last IP:    $LAST_IP"

if [ "$CURRENT_IP" != "$LAST_IP" ]; then
  # Save current IP
  echo $CURRENT_IP >> $IP_LOG

  echo "Restarting SSH tunnel - started"
  ~/tun_start.sh &
  sleep 3
  echo "Restarting SSH tunnel - finished"
  echo "IP is not changed. Exit."

File “~/tun_pid.sh”


echo $(ps aux | grep -i "ssh -v -N" | grep -v grep | awk '{print $2}')

File “~/tun_start.sh”


echo "Creating SSH tunnel..."
while true
  ssh -v -N -C \
    -o ServerAliveInterval=60 \
    -o ExitOnForwardFailure=yes \
    -i ~/.ssh/mykey \
    -R @ \
    -E ~/ssh.log
  echo "Recreating SSH tunnel..."
  sleep 5

File “~/tun_stop.sh”


killall tun_start.sh

for i in `ps aux | grep -i "ssh -v -N" | grep -v grep | awk '{print $2}'`; do
  kill -9 $i

The last step is to run our tunnel manager by cron task. So, edit cron file:

sudo mcedit /etc/crontab

Or any other method you like and add the task:

*/5 * * * *  /home//tun_manager.sh >> /home//tm.log

So, each 5 minutes you’ll check the system and recreate SSH tunnel.

Part 4. Testing!
Now we ready for connection to our private SSH server from the world:

ssh @ -p22222

See also,