6

I am a beginner user of linux, and also quite newbie at ssh and tunnels.

Anyway, my goal is to maintain a ssh tunnel open in background.

In order to do that, I wrote the following batch that I then added into crontab (the batch is automatically processed every 5 minutes during workdays and from 8am to 9pm). I read in some other thread in stackoverflow that one should use autossh that will ensure the ssh will always be ok through a recurrent check. So did I....

#!/bin/bash
LOGFILE="/root/Tunnel/logBatchRestart.log"
NOW="$(date +%d/%m/%Y' - '%H:%M)" # date & time of log

if ! ps ax | grep ssh | grep tunnelToto &> /dev/null
then
    echo "[$NOW] ssh tunnel not running : restarting it" >> $LOGFILE
    autossh -f -N -L pppp:tunnelToto:nnnnn nom-prenom@193.xxx.yyy.zzz -p qqqq
    if ! ps ax | grep ssh | grep toto &> /dev/null
    then
            echo "[$NOW] failed starting tunnel" >> $LOGFILE
    else
            echo "[$NOW] restart successfull" >> $LOGFILE
    fi
fi

My problem is that sometimes the tunnel stops working, although every thing looks ok (ps ax | grep ssh > the result shows the two expected tasks : autossh main task and the ssh tunnel itself). I actually know about the problem cause the tunnel is used by a third party software that triggers an error as soon as the tunnel is no more responding.

SO I am wondering how I should improve my batch in order It will be able to check the tunnel and restart it if it happens to be dead. I saw some ideas in there, but it was concluded by the "autossh" hint... which I already use. Thus, I am out of ideas... If any of you have, I'd gladly have a look at them!

Thanks for taking interest in my question, and for your (maybe) suggestions!

Community
  • 1
  • 1
Marvin
  • 1,514
  • 4
  • 16
  • 40
  • I think you should have a look at serverfault.com. Search for `ssh` or `autossh` Example: http://serverfault.com/questions/159766/bash-script-with-permanent-ssh-connection – powerMicha Jul 20 '11 at 08:46

2 Answers2

12

Instead of checking the ssh process with ps you can do the following trick

create script, that does the following and add it to your crontab via crontab -e

#!/bin/sh

REMOTEUSER=username
REMOTEHOST=remotehost 

SSH_REMOTEPORT=22
SSH_LOCALPORT=10022

TUNNEL_REMOTEPORT=8080
TUNNEL_LOCALPORT=8080

createTunnel() {
    /usr/bin/ssh -f -N  -L$SSH_LOCALPORT:$REMOTEHOST:SSH_REMOTEPORT -L$TUNNEL_LOCALPORT:$REMOTEHOST:TUNNEL_REMOTEPORT $REMOTEUSER@$REMOTEHOST
    if [[ $? -eq 0 ]]; then
        echo Tunnel to $REMOTEHOST created successfully
    else
        echo An error occurred creating a tunnel to $REMOTEHOST RC was $?
    fi
}

## Run the 'ls' command remotely.  If it returns non-zero, then create a new connection
/usr/bin/ssh -p $SSH_LOCALPORT $REMOTEUSER@localhost ls >/dev/null 2>&1
if [[ $? -ne 0 ]]; then
    echo Creating new tunnel connection
    createTunnel
fi

In fact, this script will open two ports

  • port 22 which will be used to check if the tunnel is still alive
  • port 8080 which is the port you might want to use

Please check and send me further questions via comments

powerMicha
  • 2,673
  • 1
  • 22
  • 29
  • Hi Marvin, if my answer helped you to solve the problem, vote on it and accept this answer - This will raise your and my reputation in stackoverflow. – powerMicha Jul 25 '11 at 08:51
  • I tried but encountered some problems: *I am confused about ports; shouldn't the remote port be the same, whatevever the local one may be? *also about the port : I have this option '-p $SOME_PORT' in the ssh command I used to use; does this override the $REMOTE_PORT or is this some additionnal port , and did you avoid to mention it on purpose? Eventually, I get this on return from the (fixed) batch : ssh: Could not resolve hostname [MyHostName]: Name or service not known. the hostname is correct, but it looks like it was unable to do the tunnel listener on port 22): Is there stg I miss? – Marvin Jul 25 '11 at 08:51
  • Once again, I clicked too fast. And yes, it was helpfull since I am now a little less ignorant on this subject thanks to you! – Marvin Jul 25 '11 at 08:52
  • The option `-p $SOME_PORT` is used to establish the ssh connection. Usually this is port 22 but with this option, you can change it. The statements like this `-L$SSH_LOCALPORT:$REMOTEHOST:SSH_REMOTEPORT` are responsible for the tunneled ports, which must not be the same on local and remote side. So `-L10022:localhost:22` will tunnel the port 22 of your remote system to 10022 of your local machine. After that, you can access the server as well with `ssh localhost -p 10022` assuming that port 22 is the ssh port. – powerMicha Jul 25 '11 at 09:00
1

(I add this as an answer since there is not enough room for it un a comment)

Ok, I managed to make the batch run to launch the ssh tunnel (I had to specify my hostname instead of localhost in order it could be triggered) :

#!/bin/bash

LOGFILE="/root/Tunnel/logBatchRedemarrage.log"
NOW="$(date +%d/%m/%Y' - '%H:%M)" # date et heure du log


REMOTEUSER=username
REMOTEHOST=remoteHost

SSH_REMOTEPORT=22
SSH_LOCALPORT=10022

TUNNEL_REMOTEPORT=12081
TUNNEL_SPECIFIC_REMOTE_PORT=22223
TUNNEL_LOCALPORT=8082

createTunnel() {
    /usr/bin/ssh -f -N  -L$SSH_LOCALPORT:$REMOTEHOST:$SSH_REMOTEPORT -L$TUNNEL_LOCALPORT:$REMOTEHOST:$TUNNEL_REMOTEPORT $REMOTEUSER@193.abc.def.ghi -p $TUNNEL_SPECIFIC_REMOTE_PORT
    if [[ $? -eq 0 ]]; then
        echo [$NOW] Tunnel to $REMOTEHOST created successfully >> $LOGFILE
    else
        echo [$NOW] An error occurred creating a tunnel to $REMOTEHOST RC was $? >> $LOGFILE
    fi
    }

## Run the 'ls' command remotely.  If it returns non-zero, then create a new connection
/usr/bin/ssh -p $SSH_LOCALPORT $REMOTEUSER@193.abc.def.ghi ls >/dev/null 2>&1
if [[ $? -ne 0 ]]; then
    echo [$NOW] Creating new tunnel connection >> $LOGFILE
    createTunnel
fi

However, I got some immediate message (below) when the tunnel is running and when cron tries to lauch the batch again... sounds like it cannot listen to it. Also since I need some time to get a proof , I can't say yet it will successfully restart if the tunnel is out.

Here's the response to the second start of the batch.

bind: Address already in use channel_setup_fwd_listener: cannot listen to port: 10022 bind: Address already in use channel_setup_fwd_listener: cannot listen to port: 8082 Could not request local forwarding.

Marvin
  • 1,514
  • 4
  • 16
  • 40
  • the address in use message you get is because you removed from your script the part that checks if your tunnel is already running. `pgrep -fl $SSH_LOCALPORT:$REMOTEHOST:$SSH_REMOTEPORT` would reveal that the ssh from the first run is still running. – Superole Apr 15 '13 at 13:05