Bash script to set up a temporary SSH tunnel

Viewed 75352

On Cygwin, I want a Bash script to:

  1. Create an SSH tunnel to a remote server.
  2. Do some work locally that uses the tunnel.
  3. Then shut down the tunnel.

The shutdown part has me perplexed.

Currently, I have a lame solution. In one shell I run the following to create a tunnel:

# Create the tunnel - this works! It runs forever, until the shell is quit.
ssh -nNT -L 50000:localhost:3306 jm@sampledomain.com

Then, in another shell window, I do my work:

# Do some MySQL stuff over local port 50000 (which goes to remote port 3306)

Finally, when I am done, I close the first shell window to kill the tunnel.

I'd like to do this all in one script like:

# Create tunnel
# Do work
# Kill tunnel

How do I keep track of the tunnel process, so I know which one to kill?

7 Answers
  • You can tell ssh to go into background with & and not create a shell on the other side (just open the tunnel) with a command line flag (I see you already did this with -N).
  • Save the PID with PID=$!
  • Do your stuff
  • kill $PID

EDIT: Fixed $? to $! and added the &

I prefer to launch a new shell for separate tasks and I often use the following command combination:

  $ sudo bash; exit

or sometimes:

  $ : > sensitive-temporary-data.txt; bash; rm -f sensitive-temporary-data.txt; exit

These commands create a nested shell where I can do all my work; when I'm finished I hit CTRL-D and the parent shell cleans up and exits as well. You could easily throw bash; into your ssh tunnel script just before the kill part so that when you log out of the nested shell your tunnel will be closed:

#!/bin/bash
ssh -nNT ... &
PID=$!
bash
kill $PID

You could launch the ssh with a & a the end, to put it in the background and grab its id when doing. Then you just have to do a kill of that id when you're done.

A simple bash script to solve your problem.

# Download then put in $PATH
wget https://raw.githubusercontent.com/ijortengab/bash/master/commands/command-keep-alive.sh
mv command-keep-alive.sh -t /usr/local/bin

# open tunnel, put script in background
command-keep-alive.sh "ssh -fN -o ServerAliveInterval=10 -o ServerAliveCountMax=2 -L 33306:localhost:3306 myserver" /tmp/my.pid &
# do something
mysql --port 33306
# close tunnel
kill $(cat /tmp/my.pid)

https://github.com/aronpc/remina-ssh-tunnel

#!/usr/bin/env sh

scriptname="$(basename $0)"
actionname="$1"
tunnelname=$(echo "$2" | iconv -t ascii//TRANSLIT | sed -E 's/[^a-zA-Z0-9-]+/-/g' | sed -E 's/^-+|-+$//g' | tr A-Z a-z)
remotedata="$3"
tunnelssh="$4"

if [ $# -lt 4 ] 
 then
    echo "Usage: $scriptname start | stop LOCAL_PORT:RDP_IP:RDP_PORT SSH_NODE_IP"
    exit
fi

case "$actionname" in

start)

  echo "Starting tunnel to $tunnelssh"
  ssh -M -S ~/.ssh/sockets/$tunnelname.control -fnNT -L $remotedata $tunnelssh
  ssh -S ~/.ssh/sockets/$tunnelname.control -O check $tunnelssh
  ;;

stop)
  echo "Stopping tunnel to $tunnelssh"
  ssh -S ~/.ssh/sockets/$tunnelname.control -O exit $tunnelssh 
 ;;

*)
  echo "Did not understand your argument, please use start|stop"
  ;;

esac

usage example

Edit or create new remmina server connection

schema

~/.ssh/rdp-tunnel.sh ACTION TUNNELNAME LOCAL_PORT:REMOTE_SERVER:REMOTE_PORT TUNNEL_PROXY

name description
ACTION start|stop
TUNNELNAME "string identify socket" slugify to create socket file into ~/.ssh/sockets/string-identify-socket.control
LOCAL_PORT the door that will be exposed locally if we use the same port for two connections it will crash
REMOTE_SERVER the ip of the server that you would access if you had it on the proxy server that will be used
REMOTE_PORT the service port that runs on the server
TUNNEL_PROXY the connection you are going to use as a proxy, it needs to be in your ~/.ssh/config preferably using the access keys

I use the combination (% g-% p) of the remmina group name and connection name to be my TUNNELNAME (this needs to be unique, it will see the socket name)

pre-command

~/.ssh/rdp-tunnel.sh start "%g-%p" 63394:192.168.8.176:3389 tunnel-name-1

post-command

~/.ssh/rdp-tunnel.sh stop "%g-%p" 63394:192.168.8.176:3389 tunnel-name-1

image

you can and should use this script to access anything, I use it constantly to access systems and services that do not have a public ip going through 1,2,3,4,5 or more ssh proxies

see more into :

  1. ssh config
  2. ssh mach
  3. ssh jump hosts
  4. sshuttle python ssh

Refs:

  1. https://remmina.org/remmina-rdp-ssh-tunnel/
  2. https://kgibran.wordpress.com/2019/03/13/remmina-rdp-ssh-tunnel-with-pre-and-post-scripts/
  3. Bash script to set up a temporary SSH tunnel
  4. https://gist.github.com/oneohthree/f528c7ae1e701ad990e6
Related