LoginSignup
3
2

More than 5 years have passed since last update.

ルーターの向こう側のLinuxマシンにssh接続してメンテナンスする

Last updated at Posted at 2017-08-28

課題:実家に設置したRaspberyPiをリモートでメンテナンスする

実家に置いたLinuxサーバーを管理したいけど、固定IPじゃないしルーターの向こう側なので、外からアクセスするのはVPNでも使わないと無理。そこで、実家のLinuxサーバーから固定IPのレンタルサーバーにssh接続して reverse port forwarding でトンネルを掘ることにしました。

概略

実家に置いたRaspberyPi(リモート側)から借りているレンタルサーバー(ローカル側)にssh接続して、reverse port forwardingを行い、レンタルサーバーから実家のRaspberyPiに接続できるようにする。
レンタルサーバーのアドレスは仮にlocal.server.com、reverse port forwarding に使うポートは仮に 99922 とする。

ローカル側の設定

インターネットの切断などでsshが途切れてしまうとポートが占有されたままになってしまう事があり、そういう場合には残ったプロセスを殺す必要がある。そこでリバースポートフォワーディングを受け入れるローカル側に以下のようなスクリプトを仕込む。

killZombieConnection.sh
#!/bin/bash
# reverse port forwarding に使いたいポートが使われていたらそのプロセスを殺してOKを返すプログラム
# インターネット回線が途中で途切れたりするとプロセスが残っていたりするのでこの工程は必須
pid=`sudo lsof -i:99922 | grep 99922 | sed "s/  */\t/g" | cut -f 2`
if [ "$pid" = "" ]
then
    echo OK
else
    kill $pid
    if [ $? -eq 0 ]
    then
        echo OK
    fi
fi

リモート側からこのプロセスをキックするために RAPPORT_KEY と紐づけられているauthorized_keys の中身に以下を追記する。

authorized_keys
command="/home/user/program/killZombieConnection.sh" ssh-rsa AAAAB3............. user@remote.com

リモート側の設定

実家側のRaspberyPiには起動したらcrontabを使ってreverse_ssh_forwarding.sh を実行させる。
そうするとインターネット接続ができるようになるのを待ってから私が管理するサーバーへreverse port forwardingを行う。

実家に設置したRaspberyPiはLEDとスピーカーが付いているので、インターネット接続が確立出来たらLEDを点灯させ、ポートフォワーディングが張れたらLEDを消灯することにする。また、IPアドレスを実家のJSAYにしゃべらせる。

reverse_ssh_forwarding.sh
#!/bin/bash
LOG="/home/pi/log/sshlog.txt"
SSH_KEY="/path/to/ssh/key" # reverse port forwarding 用の秘密鍵
RAPPORT_KEY="/path/to/ssh/rapport/key" # 接続したら同じポートを使っているプロセスを殺してOKを返してすぐに接続を切るスクリプトと紐付けた秘密鍵
SERVER="local.server.com" # 母艦となるサーバーのアドレス
USER="user" # ユーザー名
PORT="99922:127.0.0.1:22" # 99922 は任意のポート番号
LED=16 # LED につながっているGPIOのピン番号
JSAY="/home/pi/programs/talking/jsay.sh" # jsay へのパス
gpio -g mode $LED out

rm -f $LOG

# 試しに母艦にssh接続してみる。つながるようになったら reverse port forwarding を張るステップに進む
rapport=0
while [ "$rapport" != "1" ]
do
    sleep 2
#    echo "checking"
    gpio -g write $LED 0
    rapport=`ssh -i $RAPPORT_KEY -l $USER $SERVER 2>&1 | grep -c OK`
    gpio -g write $LED 1
done

ADDRESS=""
times=0
while [ "$ADDRESS" = "" ]
do
    echo "Checking address"
    ADDRESS=`/sbin/ifconfig | grep "inet addr" | tail -1 | sed "s/.*addr://" | sed "s/ .*//"`
    times=`expr $times + 1`
    if [ $times -gt 5 ]
    then
        break
    fi
    sleep 1
done
echo "IPアドレスは $ADDRESSです。IPアドレスは $ADDRESSです。" | $JSAY

message="Connecting"
while [ true ]
do
    sleep 5
    #echo "$message"
    echo "接続します" | $JSAY
    gpio -g write $LED 0
    # start reverse port forwarding 
    ssh -v -o ExitOnForwardFailure=yes -o ServerAliveInterval=60 -o ConnectTimeout=5 \
        -o TCPKeepAlive=no \
        -N -i $SSH_KEY -l $USER -R $PORT $SERVER >> $LOG 2>&1
    wait
    # ssh 接続が切れたら少し待ってまた接続しに行く
    gpio -g write $LED 1
    message="Re-connecting"
done

追記

帰省した時に話を聞いてみると、ルーターを再起動したときにはこのスクリプトでも再接続できない場合があるようです。Reverse port forwarding をする直前にも
rapport=ssh -i $RAPPORT_KEY -l $USER $SERVER 2>&1 | grep -c OK
を呼び出して残ったプロセスを殺す必要があるようです。
スクリプトが完成したらまた更新します。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2