2015年02月25日

ルーターを超えてリモートホストに接続できる ngrok(無料)を使って Raspberry Pi を IoT ハブにする方法

ngrok って知ってますか? ここ最近ブログで取り上げていた Cloud Pi のように、ルーターの下に隠れたデバイス、例えばホームネットワークにつながった Windows、Mac、Linux サーバーへ遠隔地から接続することができるようになるトンネリング・サービスなんですよ(しかも無料で始められるんです!)。 今日は ngrok の基本的な使い方とスマート・フォームの一例として irMagicianT を組み合わせた何処からでも自宅の家電を操作できる Web リモコンの作り方をご紹介します。

tunnel

ngrok の概要と Rapberry Pi でのセットアップ


何故異なるルーター配下のデバイス同士で通信することが難しいのでしょうか?

僕達があるネットワーク(例えば、自宅の無線 LAN)に接続してインターネットをブラウジングするとき、リクエスト/レスポンスという双方向のトラフィックが発生しています。 ただ、そのコンテクストは内(ルーターの内部)から外(インターネット)。 このような内側から開始(リクエスト)して、外側からのレスポンスを受け取るような身元が保証されたトラフィックに対してルーターは寛容です。

しかし、例えばスマートフォンを使ってホームネットワーク上の Raspberry Pi サーバーへ屋外から接続するような場合、トラフィックのコンテクストは外から内になり特別な設定・ネゴシーエションが無い限りルーターはその接続要求をドロップします(ファイヤーウォール!)。

basic_nat_firewall_model

さて、よく考えるとセッションを確立したいお互いのデバイスが常に内から外への通信コンテクストになるようなカラクリを注入すればルーター(ファイヤーウォール)を超えて会話することができそうです。 そう、これを実現するインターネット上の中継サーバーが ngrok.com なのです。 ngrok.com の仕組みは(多分)こうです。 接続確立を求めるクライアントからのリクエストを受け取った nrgrok.com はこれを変換してホームネットワーク内のピア・デバイス上で動き、同じく nrgrok.com に接続してデータ配信をフックしていた ngrok エージェントへレスポンス(ペイロードはクライアントのリクエスト)します。

ngrok_network_overview


そしてリクエストをレスポンスとして受け取ったホームネットワーク内の nrgrok エージェントは本来のリクエストに再変換してローカルのサービス(TCP ポート)に転送するのです。 帰り道でも同じことをすれば双方のプロシージャにおいて外から内というコンテクストは一度も発生しませんよね!

このような手法・アイデアは決して珍しいものでは無いのですが、無料・認証機能付き・マルチ・プロトコル(TCP)に対応というサービスは珍しい。

早速セットアップしてみましょうか。 まず貴方が行うべきは https://ngrok.com からアカウントを作ること。 アカウントを作ると次の3つのサービスを使えるようになります。

  • HTTP(S)アクセス時のユーザ、パスワードによる認証(BASIC)
  • サブドメインの利用
  • TCP ポート・マッピング

サインアップ後、ダッシュボード・ページに表示される auto token 値をコピーしておいて下さいね。

ngrok - auth token


さあ、準備はできました ngrok エージェントをダウンロードしましょう。 僕は Raspberry Pi でエージェントを動かすので Linux/ARM 版を入手(zip)します。

ngrok - download


この zip ファイルを Raspberry Pi にコピー、解凍した ngrok を /usr/local/bin あたりに移動すればインストールはおしまい。

pi@raspberrypi ~ $ unzip ngrok.zip
Archive:  ngrok.zip
  inflating: ngrok

pi@raspberrypi ~ $ sudo mv ngrok /usr/local/bin/
pi@raspberrypi ~ $ ngrok version
1.7


ngrok を使った HTTP/TCP ポート転送の使い方


まず、試しに apache2 Web サーバーをインストールしておき、

pi@raspberrypi ~ $ sudo apt-get install apache2


apache2 の HTTP ポート(80 番)を ngrok.com で公開してみましょう。

pi@raspberrypi ~ $ ngrok 80
ngrok                                                    (Ctrl+C to quit)
                                                                         
Tunnel Status                 online                                     
Version                       1.7/1.7                                    
Forwarding                    http://4e739be6.ngrok.com -> 127.0.0.1:80  
Forwarding                    https://4e739be6.ngrok.com -> 127.0.0.1:80 
Web Interface                 127.0.0.1:4040                             
# Conn                        3                                          
Avg Conn Time                 22.00ms


これでポート転送が始まりました。 Forwarding と表示された http://4e739be6.ngrok.com へアクセスしてみると・・・

connect ngrok by using Mozilla Firefox


お、別の場所、別のルーター配下にいる Raspberry Pi の Web ページを見ることができました!

マダム 「でも URL が暗号みたいで覚えにくいのよねぇ・・・うちのワンちゃんの名前とか自由に設定できないのものかしら?」

(軽くボディ・タッチしつつ)「奥様!そんな時こそサインアップ・アカウントへ提供されるサブドメイン機能をお試し下さい(今なら無料でご提供中です)!」

マダム「頂くわ」

一度 ngrok を止め、-subdomain で netbuffalo を指定して再起動します(your_ngrok_auth_token は先程コピーしておいた auth token 値)。

pi@raspberrypi ~ $ ngrok -authtoken your_ngrok_auth_token -subdomain netbuffalo -httpauth "user:secret" 80

ngrok                                                     (Ctrl+C to quit)

Tunnel Status                 online
Version                       1.7/1.7
Forwarding                    http://netbuffalo.ngrok.com -> 127.0.0.1:80
Forwarding                    https://netbuffalo.ngrok.com -> 127.0.0.1:80
Web Interface                 127.0.0.1:4040
# Conn                        0
Avg Conn Time                 0.00ms


ほう、URL が大分覚えやすくなりました。 httpauth オプションも指定しているので接続の際にはユーザ名(ここでは user)、パスワード(secret)による認証プロセスも必要になります。

ngrok basic authentication


最後に設定ファイルの作り方を覚えましょうね。 authtoken を付けて ngrok を起動するとホームディレクトリ配下に設定ファイル(~/.ngrok)が自動生成されます。 このファイルの書式は YAML。 見出しごとにスペースでインデントされる書式と覚えればおk。

次の例ではポート転送(tunnels:)の設定として apache2:(80 番ポート、サブドメイン、認証指定あり)、remocon:(8080 番ポート)、ssh:(22 番ポート)の3つを定義しています。

pi@raspberrypi ~ $ cat ~/.ngrok
auth_token: your_ngrok_auth_token

tunnels:
  apache2:
    subdomain: "netbuffalo"
    auth: "user:password"
    proto:
      https: 80

  remocon:
    subdomain: "irmagic"
    auth: "ir:password"
    proto:
      https: 8080

  ssh:
    proto:
      tcp: 22


こうしておくと「ngrok start +名称」で複数ポートの転送を始めることができるのです。

pi@raspberrypi ~ $ ngrok start apache2 ssh remocon

Tunnel Status                 online
Version                       1.7/1.7
Forwarding                    https://netbuffalo.ngrok.com -> 127.0.0.1:80
Forwarding                    https://irmagic.ngrok.com -> 127.0.0.1:8080
Forwarding                    tcp://ngrok.com:21084 -> 127.0.0.1:22
Web Interface                 127.0.0.1:4040
# Conn                        0
Avg Conn Time                 0.00ms


SSH だってこの通り。

remote computer $ ssh -p 21084 pi@ngrok.com
Linux raspberrypi 3.18.7-v7+ #755 SMP PREEMPT Thu Feb 12 22:20:48 GMT 2015 armv7l

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.

※ 複数のコンフィグレーションを用意する場合、-config=/path/to/yaml オプションで切り替え可能。

以前に irMagicianT 赤外線リモコン(+温度センサー)ボード向けに作った Web リモコン(「Raspberry Pi + irMagician (赤外線リモコン・ボード) でホーム・オートメーションを楽しむ方法」参照)だって ngrok 経由で動きますよ。

irMagicanT connected to Raspberry Pi 2


環境をセットアップして、

pi@raspberrypi ~ $ sudo apt-get install python-pip
pi@raspberrypi ~ $ sudo pip install pyserial
pi@raspberrypi ~ $ sudo pip install tornado
pi@raspberrypi ~ $ git clone https://github.com/netbuffalo/RemoteIRF.git
pi@raspberrypi ~ $ git clone https://github.com/netbuffalo/RemoteIRE.git


8080 ポートで Web アプリケーションを起動しておき、

pi@raspberrypi ~/RemoteIRF $ sudo python server.py -p 8080 -user admin -passwd secret
pi@raspberrypi ~/RemoteIRE $ python irelement.py -s localhost -p 8080 -t 60


ngrok にアクセスすると・・・ほら Web リモコンのページが見えました!

ngrok - use irMagicianT by using  Mozilla Firefox


勿論、スマートフォン(3G, LTE 回線)からでもアクセス可能。

ngrok open web application by using mobile phone


さて、通常 ngrok はフォア・グラウンドで動きます。 もし貴方が ngrok をバック・グラウンドでサービスとして動かしたいのであれば -log=stdout オプションを付けて起動しましょう。 標準出力されるログ・メッセージは /dev/null に捨てず logger にパイプするのが賢い選択でしょうね。

pi@raspberrypi ~ $ ngrok -log=stdout start apache2 ssh remocon| logger &


こうしておけば /var/log/syslog で ngrok の状態を確認することが可能です。

pi@raspberrypi ~ $ tail -f /var/log/syslog
Feb 24 23:28:07 raspberrypi logger: [02/24/15 23:28:07] [DEBG] [prv:621ddeea] Closing
Feb 24 23:28:07 raspberrypi logger: [02/24/15 23:28:07] [WARN] [prv:621ddeea] Copied 3351 bytes to pxy:330929c9 before failing with error read tcp 127.0.0.1:22: use of closed network connection
Feb 24 23:28:15 raspberrypi logger: [02/24/15 23:28:15] [DEBG] [ctl:4eeg519f] Writing message: {"Type":"Ping","Payload":{}}
Feb 24 23:28:15 raspberrypi logger: [02/24/15 23:28:15] [DEBG] [ctl:4eeg519f] Reading message with length: 28
Feb 24 23:28:15 raspberrypi logger: [02/24/15 23:28:15] [DEBG] [ctl:4eeg519f] Read message {"Type":"Pong","Payload":{}}
Feb 24 23:28:15 raspberrypi logger: [02/24/15 23:28:15] [DEBG] [ctl:4eeg519f] Waiting to read message
Feb 24 23:28:35 raspberrypi logger: [02/24/15 23:28:35] [DEBG] [ctl:4eeg519f] Writing message: {"Type":"Ping","Payload":{}}
Feb 24 23:28:35 raspberrypi logger: [02/24/15 23:28:35] [DEBG] [ctl:4eeg519f] Reading message with length: 28

※ ngrok はインターネット上の中継サーバーに対して定期的に Ping を送り、そのレスポンス(Pong)でクライアントからのリクエスト(Payload)有無を監視しているみたいですね!

自動起動したいのであれば /etc/rc.local に起動コマンドを追記してみて下さい。

総じて速度は遅い(100 - 300 Kbps)のですが、ピアで動くシンプルな Web アプリケーション程度であれば使っていてストレスは無し。 無料で使える楽しいクラウド・ポート・マッパーでしたよ。

それでは、より良い IoT ライフを。

Make: Electronics ―作ってわかる電気と電子回路の基礎 ((Make:PROJECTS))
Charles Platt
オライリージャパン
売り上げランキング: 29,574


Posted by netbuffalo at 19:50│Comments(0) Raspberry Pi | ネットワーク


コメントする

名前
 
  絵文字