How to get an ssh tunnel started every time my Mac boots?
I'm trying to run a script at startup to tunnel to a remote host over a random port.
I want to leave a cookie on the remote machine to say which port I chose.
Something like this:
# to make a record of the tunneling port on the remote host
echo $remoteport > $portfile
scp $portfile [email protected]:
# to actually do the tunnel and go into the background
ssh -n -i /Users/rcook/.ssh/id_rsa -o ExitOnForwardFailure=yes -R $remoteport:localhost:22 [email protected]
# to make a record of the tunneling port on the remote host
# keep checking if ssh is up
while ps -Awwx -o "user pid ppid pcpu pmem comm args" | egrep -v grep | egrep "${remoteport}:localhost"; do
echo found
sleep 30
done
echo finished at $(date)
I then point to it from a plist to run at startup.
I'm having multiple problems here.
- How to run ssh at login?
- How to tell ssh to set up a port and then just hold the port open forever?
- How to check on the ssh connection to make sure it's still up and reestablish if it goes down?
I know my answer is through launchctl and ssh but I just can't get all the pieces to line up.
FWIW, here is my LaunchDaemon. Have no idea if it works, since I can't solve the ssh problems first. This is complicated.
root@Richards-iMac (~ ): cat /Library/LaunchDaemons/Tunneler.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>EnvironmentVariables</key>
<dict>
<key>PATH</key>
<string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/Library/Apple/usr/bin:/usr/local/sbin</string>
</dict>
<key>GroupName</key>
<string>admin</string>
<key>KeepAlive</key>
<dict>
<key>Crashed</key>
<true/>
<key>SuccessfulExit</key>
<true/>
</dict>
<key>Label</key>
<string>Tunneler</string>
<key>ProgramArguments</key>
<array>
<string>/Users/rcook/bin/linode_tunneler.sh</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>UserName</key>
<string>rcook</string>
</dict>
</plist>
Solution 1:
OK, no sooner asked than I figured out the last few pieces.
To get ssh to do what I wanted, here is the shell script to do what I want:
#!/usr/bin/env bash
echo $0 run on $(date)
# Just chose an arbitrary 401 value range of random numbers.
randport=$(/usr/bin/python -S -c "import random; print random.randrange(5555,5955)")
remoteport=$randport # this way we always know what port we are using. Fix other problems later...
portfile=/Users/rcook/.ssh/linode_remote_port.txt
echo $remoteport > $portfile
scp $portfile [email protected]:
ssh -N -n -i /Users/rcook/.ssh/id_rsa -o ExitOnForwardFailure=yes -R $remoteport:localhost:22 [email protected] &
sleep 5
while ps -Awwx -o "user pid ppid pcpu pmem comm args" | egrep -v grep | egrep "${remoteport}:localhost"; do
echo found
sleep 30
done
echo finished at $(date)
I put the launchctl script into /Library/LaunchDaemons/Tunneler.plist. This way it loads at system launch.