I often find myself having to create long running SSH tunnels from one machine to another to maintain whatever service or access needs.
The following script is heavily based on this article by Brandon Checketts (the general script structure and the auth setup required for this to work) and this Stack Exchange answer by Chuss (checking the tunnel itself instead of relying on an additional SSH connection).
in my use case I wanted to maintain tunnels from my development box sitting at home to DBs in the office, both an Oracle and a MySQL connection. I also preferred to be able to duplicate this for whatever other tunnel I might need without having to edit the script.
#!/bin/bash
LOCAL_TUNNEL_PORT=$1
REMOTE_TUNNEL_PORT=$2
REMOTE_TUNNEL_SERVER=$3
SSH_SERVER=$4
SSH_USER=$5
createTunnel() {
/usr/bin/ssh -f -N -L$LOCAL_TUNNEL_PORT:$REMOTE_TUNNEL_SERVER:$REMOTE_TUNNEL_PORT $SSH_USER@$SSH_SERVER
if [[ $? -eq 0 ]]; then
# echo Tunnel to hostb created successfully
exit
else
echo An error occurred creating a tunnel to $REMOTE_TUNNEL_SERVER. RC was $?
fi
}
## check if tunnel is active. If it returns non-zero, then create a new connection
r=$(bash -c 'exec 3<> /dev/tcp/'localhost'/'$LOCAL_TUNNEL_PORT';echo $?' 2>/dev/null)
if [ "$r" = "0" ]; then
exit
else
echo Creating new tunnel connection
createTunnel
fi
In my crontab I added the following lines:
* * * * * /usr/local/scripts/maintain_ssh_tunnel.sh 1521 1521 oracle-db.my-office.com ssh-server.my-office.com root
* * * * * /usr/local/scripts/maintain_ssh_tunnel.sh 3306 3306 mysql-db.my-office.com ssh-server.my-office.com root
These will re-run every minute to check if the tunnel is still up and try to reconnect otherwise.