ngrokを用いてRaspberryPiを起動したら自動で立ち上がるTCPサーバーにする

この記事は急遽[GWIoTLTアドベントカレンダー４日目](https://gw-advent.9wick.com/calendars/3)になりました!

平成最後の１日になりましたが．よろしくお願いいたします！！！
# モチベーション
ある事情でRaspberryPiを外部からSSH接続できるTCPサーバーにしたいという状況が発生しました．

通常の場合であれば，ポート開放を行いグローバルなIPアドレスを経由してSSH接続できるようにするのが一般的です．その場合は，下のような記事を見ていただければできるかと思います．

>参考
>[Raspberry Piに外部ネットワークからアクセスできる様にして携帯でペットを遠隔監視する方法](https://qiita.com/kinpira/items/c9e6dc910e8d96e8c19b)
>[Raspberry Pi3のLAN外からのSSH接続設定方法](https://qiita.com/3no3_tw/items/4b5975a9f3087edf4e20)

しかし，以下のような状況では先ほど紹介した方法ではこれがうまくいきません．

```
・ ポート開放できないルーターを使用している（ポケットWifiやUSBスティック型ルーター)
・ 会社やビルによっては無線LAN側でポート開放が行えない
```

このような状況に陥ると，通常の方法では手も足も出ません．

しかし，ngrokを使うとインターネットにさえ繋がっていればRasspberryPiを外部から接続できるようなTCPサーバーにすることができるというのが今回の内容です．

## 使用する装置もしくはソフトについて

### RaspberryPi
これについては言わずもがなですが，簡単に書くと小さなパソコンです．元々は教育目的で開発されていますが，その小ささや大きな電圧を要さないことからIoTとの相性が抜群です．

私の場合もセンサーデータを収集するためにRaspberryPiを使用していますが，状況的にポート開放が行えず今回紹介する方法を選択しています．

種類は問いませんがなるべくメモリに余裕がある方がいいでしょう．

### [ngrok](https://ngrok.com/)
今回紹介する中で最も重要なソフトです．読み方は「エヌグロック」と読むそうです．

ngrokとは，簡単に説明しますと「接続されているルーターのポートを無視して，そのPCをHTTPサーバーもしくはTCPサーバーとして外部に公開することができる」というものになります．これをポートフォワーディングと言います．

ngrokを使えば簡単に使っているパソコンをHTTPサーバーやTCPサーバーとして外部に簡単に公開することができます．

ハッカソンといった開発イベントにはかなりもってこいなソフトです！！

## 実装

それでは早速RaspberryPiを永続的に使えるTCPサーバーにしていきましょう．
手順としては下のようになります．

- ngrokのセットアップ
- アカウントの追加
- 外部からSSH接続できるのかの確認
- 固定のportからssh接続できるようにする(pro以上)
- ngrokを動かすようなスクリプトの作成
- systemd(serviceファイル)の作成
- daemonとして登録

多そうに見えますが，大変なのは一部分なので，一つずつ見ていきましょう．

### ngorkのセットアップ
先ほどの説明では少し分かりづらかったと思うので，手を動かしながら説明していきます．

[ダウンロードページ](https://ngrok.com/download)からurlをコピーしてダウンロードとインストールを行います．

```
$ wget https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-arm.zip
$ unzip ngrok-stable-linux-arm.zip
$ sudo mv ngrok /usr/local/bin
$ ngrok http 80
```
すると下のような画面が出てくると思います．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193812/57c388dc-77f2-8819-79a9-8625bee38979.png)

これでlocalhostの80番ポートとhttp://ec9eae9e.ngrok.io が接続されたということになります．このドメインはランダムで毎回割り振られますので，ngrokを閉じればこのドメインは無くなります．

ホームページやアプリを公開したい場合であれば，apacheやnginxなどを使って指定したlocalhostのポートと接続しましょう．

## アカウントの追加

ngrokは無料でも色々と使いやすいですが，有料版も用意されています．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193812/095dbdb9-fb48-2821-d72c-f4e0d5f370d8.png)

以前使用した際には（2018年11月頃)，無料版だと連続でngrokを起動できる時間が18時間とかだった気がします．もし何か知っている方がいれば教えていただけますと幸いです．

有料版だと，特定のドメインやポート番号を指定することができるようになります．

アカウントのタグ付けの方法ですが，まずsignupをしてloginします．
左のメニューからAuthを選択します．すると画像では隠していますがAuthtokenが記述されています．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193812/3e030205-6869-ec7a-b798-6a87f845d772.png)

これをコピーして，ターミナルから

```
$ ngrok authtoken xxxxxxxxxxxxxxxxxxx
```

と入力すると，アカウントとパソコンの紐付けが完了します．

これを行わないとTCPサーバーとして立ち上げが出来ないので気をつけてください．

## 外部からSSH接続できる確認

TCPサーバーとしてRaspberryPiを立ち上げるには下のようなコマンドを入力します．

```
$ ngrok tcp 22
```

すると下のような画面が立ち上がります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193812/0a219e73-f591-1843-ab06-d5cb5b67521d.png)

TCPサーバーの場合はポート番号が毎回ランダムに割り振られてドメインの部分は0.tcp.ngrok.ioで固定されます．
有料版の場合ですと，このポート番号を固定することが可能になり，ドメインは1.tcp.ngrok.ioになります．

お使いのパソコンでSSH接続してみましょう．僕はMacユーザーなので下のようなコマンドになります．

```
$ ssh username@0.tcp.ngrok.io -p portnumber
```

エラーが起きず接続ができれば，これで晴れてRaspberryPiにSSH接続できるようになりました．もし，エラーが起きるようでしたら，RaspberrryPiの設定でSSH接続ができるようになっていない可能性があります．
下のサイトを参考にしてください．

[Raspberry Pi 3 model BでSSH接続の設定をする](https://blog.ko31.com/201803/raspi-ssh-setup/)

## 固定のportでssh接続できるようにする(pro以上)

ここに関しては，pro以上で登録した人のみ可能です．
お金を払っていなくてもこれ以降の操作は可能なのでご安心ください．

ngrokのダッシュボードにログインして，左の「Reserved」に入ります

下のReserved TCP AddressesからReserveを押すと，ランダムなポート番号が指定されたアドレスが配布されます．

ドメインの固定はsshに関しては出来なさそうです．httpに関しては指定したサブドメイン名で登録できるようです．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193812/e92dc01a-571a-60d7-0772-a1e4f5bd8589.png)

指定したドメインを用いてngrokを動かすには下のように入力します．これはドキュメントに書いてある通りです．

```shell
ngrok tcp --region=us --remote-addr 1.tcp.ngrok.io:20301 22
```


## ngrokを動かすようなスクリプトの作成

これはシェルスクリプトにまとめるだけです．

ngork-startup.sh

```shell
#!/bin/sh ←　これがないとあとでエラーが発生します！
ngrok tcp 22
```

もし，固定のport番号で起動したい場合であれば

ngork-startup.sh

```shell
#!/bin/sh
ngrok tcp --region=us --remote-addr 1.tcp.ngrok.io:20301 22
```

のようになります．このファイルを`/opt/`ディレクトリの直下あたりに置きましょう．

ngrok自体の機能はここまでになります．ここからはdaemonへの登録といった作業になります．

## systemd(serviceファイル)の作成

ここからはサーバーとしての設定です．
まずは，下のようにserviceファイルを`/etc/systemd/system/`の直下に作成してください．

ngrok.service

```
[Unit]
Description=説明文（好きにに入れて良いです）
After=network.target (この設定によりネットに繋がった後に有効なdaemonとなる）
ConditionPathExists=自動起動するプログラムが配置されているディレクトリ（/opt/)

[Service]
ExecStart=自動起動するプログラムへのフルパス(/opt/ngrok-startup.sh)
Restart=no
Type=simple
User=user_name

[Install]
WantedBy=multi-user.target
```

serviceファイルの詳細につきまして下の記事がとても参考になりますのでこちらをご覧ください．ここら辺の知識はまだまだ浅いのでぜひまさかりを汗

【補足】
User=user_nameを必ず入れてください．これを入れないと，ngrokはsudo権限では動かせないので，各ユーザー権限で動かす必要があります．systemファイルは，指定しないとroot権限で実行されてしまうのでこれがないとエラーが発生してしまいます．

[Qiita Systemd メモ書き](https://qiita.com/a_yasui/items/f2d8b57aa616e523ede4)
[Systemdを使ってさくっと自作コマンドをサービス化してみる](https://qiita.com/DQNEO/items/0b5d0bc5d3cf407cb7ff)
[systemdを用いたプログラムの自動起動](https://qiita.com/tkato/items/6a227e7c2c2bde19521c)

## daemonとして登録

最後に，この作ったserviceファイルをdaemon化します！

```
$ systemctl start ngrok.service
```

これで今までのように，ssh接続ができるようになりましたら成功です！daemonファイルなのでターミナル上にログは出ないので注意しましょう．
そして，動作が確認できたら下のコマンドを入力して永続化しましょう

```
$ systemctl enable ngrok.service
```

これで，再起動させても動いているようでしたら大成功です！お疲れ様です！

もしうまくいかないようでしたら，下のコマンドを入力してみてください．

```
$ ngrok status ngrok.service
```

---

#　所管
かなり限られた条件で使われる記事になりましたが，急遽プロトタイプを作ることになった人には参考になった記事として読んでいただければ幸いです．

実は手元にRaspberryPiがない状態での記事でしたのでまた適宜修正します．．．