2020/9/17 画像を追加するなどして、全面的に説明を刷新しました。
せっかく自宅のRaspberry Piで素晴らしいサービスを作っても、おうちの中でしか使えないと不便です😞
自宅の回線がグローバルIPアドレスであれば、ルーターのポート開放機能とダイナミックDNSなどを使ってアクセスできます。しかし、回線によってはそうもいきません。そこで、インターネット上に中継サーバーを用意し、そこを経由してアクセスしてみたいと思います。
この方法なら、外出先から自宅へ直接インターネットアクセスできない場合でも、「自宅から中継サーバー」、「外出先から中継サーバー」がそれぞれアクセスできれば、「外出先から自宅」へアクセスできます。
便利ですね🥰早速やってみましょう。
中継のやり方はいくつかありますが、いちばん一般的と思われるSSHポートフォワードを使用します。トンネリングとも呼ばれます
※インターネットにサーバーを公開する場合はセキュリティに十分ご注意ください。犯罪活動などに悪用される危険性があります。
しくみ
SSHのポートフォワード機能を使うと、自分のポートへのアクセスを他のマシンのポートへ転送できます。
Raspberry PiのSSHはデフォルトでTCP22番ポートで動いていますが、これを中継サーバーのTCP50022番ポートにマッピングします。 すると、中継サーバーの50022番ポートへのアクセスが、Raspberry Piの22番ポートへ転送されます。 そのため、中継サーバーの50022番にさえつながれば、Raspberry PiのSSHにアクセスできます。
中継サーバーを用意しよう
VPSを借りよう
中継サーバーはSSHが動けば大丈夫です。個人で使う分にはそれほどスペックも要らないので、安い💰VPSで十分でしょう。私は初期費用・最低利用期間なしで月額349円で利用できる、WebARENA Indigoの最安プランにしました。
他にもDigital Oceanなども安くて有名どころでしょうか。 実験に少し使うくらいなら、Amazon Web Services (AWS)のEC2を無料枠の中で使うのもありかもしれませんね。お好みのサービスをご利用ください。
私はUbuntu 18.04をインストールしました。WebARENA Indigoの場合は、SSHサーバーがデフォルトでONで、公開鍵認証のみの設定になっているようです。あと追加でファイアウォールを設定しSSH(22番)以外をアクセス拒否🙅♀️しました。
このあたりのセットアップはVPSによって違うので、マニュアルを読んでがんばってください。
Raspberry Piから接続できるように公開鍵を登録しよう
Raspberry Piから中継サーバーにSSH接続できるよう、公開鍵を登録しましょう。Raspberry Piで、~/.ssh
に入り、鍵を作成します。
pi@raspberrypi $ cd ~/.ssh pi@raspberrypi $ ssh-keygen -t ed25519 Generating public/private ed25519 key pair. Enter file in which to save the key (/home/pi/.ssh/id_ed25519): forward_server_key
途中で秘密鍵のファイル名を聞かれますので、好きな名前を設定します。ここでは、forward_server_key
としました。
パスフレーズも聞かれます。あってもなくても良いです。私はなしにしました。
pi@raspberrypi $ ls forward_server_key forward_server_key.pub
鍵ができています。.pub
がついているほうが公開鍵、無いほうが秘密鍵です。
公開鍵を中継サーバーに転送します。中継サーバーにログインして、~/.ssh/authorized_keys
ファイルを編集します。
無い場合は新規作成します。
mikan@example.com $ nano ~/.ssh/authorized_keys
先ほどのssh_relay_server.pub
の中身をコピーします。例えば、中身は次のようになります。
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILRfURwaxXsAN8vDs9MLf/2SRldXDBh8P2qSeEQMev5G mikan@LAPTOP-ABCDEFG ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDRjr8YGB312hU452HbLl4OuvE2OEvd4cuWcWfi5HLAi pi@raspberrypi
2行目を追加しました。このauthorized_keysに公開鍵を登録すると、対応する秘密鍵を持っている人がログインできるようになります。 上記に対応する秘密鍵は私が持っていますので、そのままコピペしないように注意してください笑
これで、Raspberry Piから中継サーバーにSSHログインできるようになりました。
ポートフォワードを使って外出先からアクセス
すぐ上に出てきた図ですが、再掲します。 Raspberry Piのポートを中継サーバーにフォワードし(図の右側)、中継サーバーのポートを外出先のパソコンにフォワードします(図の左側)。
この2段構成で、外出先パソコンから自宅のRaspberry Piまでがつながります。
Raspberry Piのポートを中継サーバーにポートフォワード
まずはコマンドラインから普通にSSH接続を試してみましょう。なお、ユーザー名をmikan
、中継サーバーのドメインをexample.com
とします。適宜設置した中継サーバーのIPアドレスなどに読み替えてください。
pi@raspberrypi $ ssh -i ~/.ssh/forward_server_key mikan@example.com
これで中継サーバーにログインできれば大丈夫です。成功したら、いよいよポートフォワードしましょう。 Raspberry PiのSSH(ポート22番)を中継サーバーの50022番にポートフォワードします。
pi@raspberrypi $ ssh -i ~/.ssh/forward_server_key -T -N -R 50022:localhost:22 user@example.com
エラーも何も出ず、終了もしないでしょうか?それで大丈夫です。-T -N
オプションが付いているので、ポートフォワードのみを行うようになっています。
-i <ファイル名> :秘密鍵ファイルの指定
-T: 仮想端末を起動しない
-N: ポートフォワードのみ行い、リモートでコマンドを実行しない
-R <接続先サーバーのポート>:<ホスト>:<ホストのポート> : ホストのポートを接続先サーバーのポートに転送する
最後の-Rオプションが肝心で、自分から見えるポートを接続先サーバーのポートにマッピングします。ここでは、sshコマンドをを実行しているlocalhost(Raspberry Pi)の22番ポートを接続先サーバー(example.com)の50022番ポートにポートフォワードします。
これで、中継サーバーの50022へのアクセスが、Raspberry Piのポート22番に転送されるようになりました。 すなわち、中継サーバーにログインさえできれば、どこからでもRaspberry Piのポート22番(SSHサーバー)にアクセスできます。
ちなみにCTRL-Cで終了し、トンネルを閉じられます。
中継サーバーのポートを外出先マシンにポートフォワード
ここから先は、外出先のパソコンでの作業です。 自宅のRaspberry Piにつなぐには、中継サーバーの50022番ポートを自分のパソコンにフォワードすればOKです。
Windowsマシンでssh
コマンドが使える場合は、次のようにします。
> ssh -i ~/.ssh/forward_server_key -T -N -L 60022:localhost:50022 user@example.com
こんどは-Lオプションを使っています。これは、接続先サーバーから見えるポートを自分のところに持ってくるためのオプションです。 先ほどの-Rオプションとは方向が逆ですね。この例では、接続先サーバー(example.com)から見てlocalhost:50022を自分のマシンの60022番ポートにフォワードします。
この2段のポートフォワードで、自分のパソコンのローカルにRaspberry Piのポートがフォワードされました。
外出先マシンからRaspberry Piにログイン
これだけでは正しく動いているのかわかりませんね🤔動作確認しましょう。 これも外出先のパソコンで行います。
先ほどのトンネルのコマンドを実行したまま、ローカルホストの60022番ポートに接続します。
> ssh -p 60022 pi@localhost (中略) pi@raspberrypi $
なんと、ローカルホストに接続したはずが、Raspberry Piにログインできました!不思議ですね。 ローカルホストの60022番へのアクセスが中継サーバーの50022番へ転送され、中継サーバーの50022番へのアクセスがRaspberry Piの22番へ転送され…という2段構えのトンネルでアクセスしています。
トンネルを常時有効にする
Raspberry Piからssh -i ~/.ssh/forward_server_key -T -N -R 50022:localhost:22 user@example.com
でトンネルを作れることはわかりましたが、これを常に有効にするために、Raspberry Pi OSのサービス化しましょう。
pi@raspberrypi $ nano /etc/systemd/system/forward_server_ssh.service
例えば次のような内容のファイルを作成します。
[Unit] Description = SSH no tunnel dayo After=network.target [Service] ExecStart=/usr/bin/ssh -i ~/.ssh/forward_server_key -T -N -o ServerAliveInterval=60 -o ExitOnForwardFailure=yes -R 50022:localhost:22 user@example.com User=pi Group=pi Restart=always RestartSec=60 [Install] WantedBy=multi-user.target
もしトンネルが切断されても、自動で再接続します。これを保存し、有効化します。
pi@raspberrypi.local $ sudo systemctl enable forward_server_ssh.service
これで、次回起動時から自動でトンネルを接続します。
もう少し簡単な方法?
「2段もポートフォワードをするなんて、面倒すぎる😫」「外出先マシンからトンネルを作って、さらにSSH接続するなんて、何回sshコマンドを実行させる気だ😡」 などとお怒りの方のために、もう少し簡単な方法も紹介しておきます。ただし、リスクもありますのでよく注意してくださいね。
先ほどのコマンドでは、ポートフォワードしたポートはローカルホストからのみアクセス可能でした。 しかし、オプションでこれを公開ポートにできます。
すなわち、中継サーバーの50022番ポートを公開ポートにすれば、いちいち外出先マシンからポートフォワードせずとも、中継サーバーの50022番ポートにアクセスするだけでOKです。トンネルが1段で済み、便利ですね。
ただし、公開ポートにするということは、悪意を持った人にもRaspberry Piを公開するということでもあります。セキュリティ設定はしっかりしましょう。 ファイアーウォールやFail2banなども併用すると良いでしょうね。
中継サーバーの設定
SSHサーバーの設定によっては、ポートフォワードのグローバル公開を許可していないこともあります。
SSHサーバーの設定ファイル/etc/ssh/sshd_config
を編集します。
mikan@example.com $ sudo nano /etc/ssh/sshd_config
ここで、GatewayPort
という設定項目をyes
に設定します。
GatewayPort yes
なければ追加、あるいはnoになっていたらyesに変更しましょう。 sshサーバーを再起動して反映します。
mikan@example.com $ sudo systemctl restart sshd.service
これで中継サーバーの準備はOKです。
Raspberry Piのポートを中継サーバーにポートフォワード
Raspberry Piから中継サーバーへトンネルを作る時に、-g
オプションを追加します。
pi@raspberrypi $ ssh -i ~/.ssh/forward_server_key -T -N -g -R 50022:localhost:22 user@example.com
すると、ポートフォワードされたポートが全世界に公開されます。 あとは、外出先パソコンからexample.comの50022番ポートにSSH接続すれば、Raspberry Piに転送されます。
Raspberry Piのセキュリティをちゃんとしてから実行してくださいね。 初期ユーザとパスワードの組み合わせでログインできる状態でこんなことをすると、すぐに悪用されることでしょう。
まとめ
同じようにすると、22番(SSH)だけでなく、80番(HTTP)など様々なサービスを転送できます。セキュリティに十分気をつけて、楽しいRaspberry Piライフを送りましょう☺️