AWS
SSH
RaspberryPi

自宅に置いたラズパイに外出先からログインする

自宅に置いたラズパイ(つまり、NATの内側にあるのでインターネット側からは直接は見えないところにある。)を外からsshでログインできるようにしてみました。いろいろと応用できそうなので、ここに記録を残します。

概要

外からsshでログインできるクラウドの仮想マシンを用意して、それを経由してラズパイにアクセスできるようにします。
ラズパイが起動したら、そのクラウドの仮想マシンにSSHのトンネルを作るようにしておきます。
これで、いつでもクラウドの仮想マシンからラズパイにsshでログインできるようになります。

(気が向いたら図を描く)

準備

今回はクラウドの仮想マシンとしてAWSを使いました。
pemファイルでログインできるようにしておき、そのpemファイルをラズパイに置きます。
また、その仮想マシンのパブリックのIPアドレスは固定になるように設定しました。

ここではその仮想マシンをaws001と呼ぶことにします。
アクセスに使用するpemファイルを aws001.pem とします。
IPアドレスは18.217.14.xxとします。

ラズパイ側ではユーザー pi のパスワードをpasswdコマンドを使用してデフォルトのものから変更しておきます。
aws001.pem はパーミッションが適切でないとsshコマンドがエラーになるので、以下を実行しておきます。

chmod 400 aws001.pem

ラズパイ側に置くスクリプト

/root/ssh_tunnel/ssh_tunnel
#!/bin/sh

KEYFILE=aws001.pem
USER=ubuntu
HOST=18.217.14.xx
REMOTE_PORT=2022

[ -r $KEYFILE ] || exit 1

SSH_CONFIG="\
 -o ServerAliveInterval=20 \
 -o ServerAliveCountMax=2 \
 -o ConnectTimeout=10 \
 -o ExitOnForwardFailure=yes \
 -o StrictHostKeyChecking=no \
 -o UserKnownHostsFile=/dev/null \
"

while :; do
    sleep 10
    echo "Make ssh tunnel" |logger -t ssh_tunnel
    ssh -i $KEYFILE $USER@$HOST -R $REMOTE_PORT:127.0.0.1:22 -N $SSH_CONFIG
    echo "Disconnected ssh tunnel. Exit code:" $? |logger -t ssh_tunnel
done

logger はsyslogにメッセージを出すコマンドです。
sshのタイムアウトの時間などは必要に応じて調整してください。
このスクリプトを起動時に実行するために、/etc/rc.local に以下を追加します。

[ -x /root/ssh_tunnel/ssh_tunnel ] && (cd /root/ssh_tunnel; ./ssh_tunnel )&

AWSのVMからラズパイにログインする

ssh -p 2022 pi@localhost

多段ssh

~/.ssh/config
Host         aws001
User         ubuntu
IdentityFile ~/.ssh/aws001.pem

Host         rpi
HostName     localhost
Port         2022
User         pi
ProxyCommand ssh -W %h:%p aws001

このように ~/.ssh/config に書いておけば、AWSを経由してラズパイにログインするのがコマンド一発でできます。

ssh rpi

同様にしてsftpやscpも使えるのでファイルのコピーも楽になります。

補足

最初はautosshコマンドでできるかと思ったのですが、うまくいかないケースがありました。

sshでログインしている最中に、ラズパイの電源を落として再起動させたときに、まだsshのコネクションが切れていない状態で新たにsshトンネルを作ろうとするとautosshコマンドが終了してしまうようでした。そのためautosshコマンドを繰り返し実行するようにしたのですが、それなら単純にsshコマンドを繰り返すのとたいして変わらないということになり、今のかたちになりました。