みかんのゆるふわ技術ブログ

Raspberry PiやIoT関係のことを書き残していきます

自宅のRaspberry Piに外出先からアクセスする~中継サーバーを使おう

2020/9/17 画像を追加するなどして、全面的に説明を刷新しました。

せっかく自宅のRaspberry Piで素晴らしいサービスを作っても、おうちの中でしか使えないと不便です😞

f:id:kimura_khs:20200501152407p:plain:w480

自宅の回線がグローバルIPアドレスであれば、ルーターのポート開放機能とダイナミックDNSなどを使ってアクセスできます。しかし、回線によってはそうもいきません。そこで、インターネット上に中継サーバーを用意し、そこを経由してアクセスしてみたいと思います。

f:id:kimura_khs:20200501152413p:plain:w480

この方法なら、外出先から自宅へ直接インターネットアクセスできない場合でも、「自宅から中継サーバー」、「外出先から中継サーバー」がそれぞれアクセスできれば、「外出先から自宅」へアクセスできます。

便利ですね🥰早速やってみましょう。

中継のやり方はいくつかありますが、いちばん一般的と思われるSSHポートフォワードを使用します。トンネリングとも呼ばれます

※インターネットにサーバーを公開する場合はセキュリティに十分ご注意ください。犯罪活動などに悪用される危険性があります。

しくみ

SSHのポートフォワード機能を使うと、自分のポートへのアクセス他のマシンのポートへ転送できます。

f:id:kimura_khs:20200916184418p:plain

Raspberry PiのSSHはデフォルトでTCP22番ポートで動いていますが、これを中継サーバーのTCP50022番ポートにマッピングします。 すると、中継サーバーの50022番ポートへのアクセスが、Raspberry Piの22番ポートへ転送されます。 そのため、中継サーバーの50022番にさえつながれば、Raspberry PiのSSHにアクセスできます。

中継サーバーを用意しよう

VPSを借りよう

中継サーバーはSSHが動けば大丈夫です。個人で使う分にはそれほどスペックも要らないので、安い💰VPSで十分でしょう。私は初期費用・最低利用期間なしで月額349円で利用できる、WebARENA Indigoの最安プランにしました。

web.arena.ne.jp

他にも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ログインできるようになりました。

ポートフォワードを使って外出先からアクセス

f:id:kimura_khs:20200916184418p:plain

すぐ上に出てきた図ですが、再掲します。 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

これで、次回起動時から自動でトンネルを接続します。

もう少し簡単な方法?

f:id:kimura_khs:20200916184426p:plain

「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ライフを送りましょう☺️