This is an old revision of the document!
On Local Host
Create a new user called tunnel. Leave tunnel home folder on root partition (/home/tunnel) to avoid tunnel failure if partitions don't mount. You need also to create an SSH key, and prepare the tunnels config folder /home/tunnel/tunnels and log folder /home/tunnel/logs:
> useradd -m tunnel > su - tunnel > ssh-keygen > mkdir tunnels > mkdir logs
Add tunnels configurations like this under /home/tunnel/tunnels/main:
- main
REMOTE_SERVER=99.99.99.99 # your remote server IP - don't use name, use IP REMOTE_SERVER_SSH_PORT=22 # your remote server SSH port HOME_SERVER_REMOTE_SSH_PORT=5022 # the port your local server SSH will be accessible from remote SSH_IDENTITY=# optional path to private ssh key, leave empty for default REMOTE_USER=tunnel # remote user to login as REMOTE_TO_HOME=\ "127.0.0.1:8080:127.0.0.1:80 "\ "127.0.0.1:8443:127.0.0.1:8443 "\ "0.0.0.0:6022:10.70.43.99:22 "\ "0.0.0.0:12112:127.0.0.1:12112 " # list of ports forwarded from remote to local HOME_TO_REMOTE= # list of ports forwarded from local to remote
Remember to “ssh” manually at least once each host to accept host keys!
You can create as many tunnels as you like. Note that SSH port will always be forwarded anyway, so you want one file for each remote host.
Now create this script under /home/tunnel/tunnel.sh:
#!/bin/bash function log() { echo $(date) - $@ >> $LOG } Add this to .ssh/config for keepalive: <code> Host * ServerAliveInterval 60
cd $HOME TUNNELS=$(ls tunnels)
TUNNEL_PIDS= for i in $TUNNELS do
# Spin a shell for each tunnel
(
NAME=$i
CONFIG=tunnels/$NAME
LOG=logs/tunnel-$NAME
log "Starting operations for tunnel '$NAME'..."
# Iterate forever
while true
do
# Spin up a sub-shell to ensure we reload the config properly each iteration
(log "Reading configuration from '$CONFIG'..."
source $CONFIG
log "Testing if remote server '$REMOTE_SERVER' is reachable..."
if ping -c 10 -W 5 $REMOTE_SERVER &> /dev/null
then
log "Remote server '$REMOTE_SERVER' is reachable!"
LOGIN_IDENTITY=
test ! -z $SSH_IDENTITY && LOGIN_IDENTITY="-i $SSH_IDENTITY"
LOGIN_AS=$USER
test ! -z $REMOTE_USER && LOGIN_AS="-l $REMOTE_USER"
REMOTES="-R0.0.0.0:$HOME_SERVER_REMOTE_SSH_PORT:127.0.0.1:22" # SSH port we always export
LOCALS=
for i in $REMOTE_TO_HOME; do REMOTES="$REMOTES -R$i"; done
for i in $HOME_TO_REMOTE; do LOCALS="$LOCALS -L$i"; done
COMMAND="ssh $LOCALS $REMOTES $LOGIN_IDENTITY $LOGIN_IDENTITY $LOGIN_AS -p $REMOTE_SERVER_SSH_PORT $REMOTE_SERVER -nNT"
log "Run: '$COMMAND'..."
$COMMAND &>> $LOG &
ssh_pid=$!
# Wait a bit to ensure command is running...
sleep 1
# until SSH returns, check network, because SSH might hang for a long time.
while ps -p $ssh_pid &> /dev/null
do
if ping -c 2 -W 2 $REMOTE_SERVER &> /dev/null
then
sleep 30
else
# Network is down? forcing ssh to stop
log "WATCHDOG: Detected '$REMOTE_SERVER' is NOT reachable! Killing command."
kill -9 $ssh_pid
while ps -p $ssh_pid; do sleep 1; done
fi
done
# get return code
wait $ssh_pid
log "Command returned code '$?'. Retrying..."
sleep 10 # after disconnection, wait a bit before retrying
else
log "It seems that '$REMOTE_SERVER' is not reachable. Wait and retry..."
sleep 5 # wait a bit before retry ping
fi
) # close iteration shell
done
)& # close tunnel shell
TUNNEL_PIDS="$TUNNEL_PIDS "$!
done
wait </code>
and set it as executable:
> chmod +x /home/tunnel/tunnel.sh
Now create the startup script /etc/local.d/99-tunnels.start:
- 99-tunnels.start
#!/bin/bash start-stop-daemon -b -m -p /var/run/tunnel.pid -n tunnel -u tunnel /home/tunnel/tunnel.sh
Share tunnel's /home/tunnel/.ssh/id_rsa.pub with remote host, paste it inside authorized_hosts file of remote tunnel user.