【Node.js】 RaspberryPiのプログラムを自動起動・永続化・SSH ログアウト後もプロセスを残す

前回記事→ [LINE BOTでラズパイから部屋の温度を教えてもらう【Push API】【Node.js】](https://qiita.com/mochifuture/items/13bed5e961a1232a660e)

#### 現状と課題

- ラズパイにはMacからwifiでSSH接続している
- SSH接続が切れる・Macがスリープするとプログラムも止まってしまう
 - Botが使えなくなる

#### 要件

- Nodeのプログラムを自動起動＆永続化させる
- RaspberryPiをサーバーに常時接続させる(ngrokの永続化）

ngrok（トンネリングツール）については→ [ngrokでトンネリング](https://qiita.com/mochifuture/items/bab1c233e6768d571098#ngrok%E3%81%A7%E3%83%88%E3%83%B3%E3%83%8D%E3%83%AA%E3%83%B3%E3%82%B0)

# 作業概要
1. Foreverをインストールし、プログラムを自動起動＆永続化
2. 無線LANの省電力機能をオフ
3. ngrokがタイムアウトしないようにする
4. ngrokの永続化（screen コマンドの利用）


# 1. Foreverをインストールし、プログラムを自動起動＆永続化

Raspberry Piにはプログラムを自動起動する方法がたくさんある

- /etc/rc.local
- autostart
- crontab
- /etc/init.d
- systemd

など・・
参照記事 [Raspberry Piでプログラムを自動起動する5種類の方法を比較・解説](
http://hendigi.karaage.xyz/2016/11/auto-boot/)

今回はNodeのプログラムなので、foreverを利用します。
foreverとは、nodeをデーモンとして動かすためのモジュール。バックグラウンドでnodeを動作させるためにインストールします。

> デーモン (英語: Daemon) は、UNIX, Linux, MacOSXなどUnix系ののマルチタスクオペレーティングシステム (OS) において動作するプロセス（プログラム）で、主にバックグラウンドで動作するプロセス。- [Wikipedia](https://ja.wikipedia.org/wiki/%E3%83%87%E3%83%BC%E3%83%A2%E3%83%B3_(%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2))


foreverのインストール
グローバルオプションをつけてインストールします。

```shell-session
$ sudo npm install -g forever
```
foreverのパスを確認

```shell-session
$ which forever
```

（例）もちさんの場合

```shell-session
/usr/local/nvm/versions/node/v10.0.0/bin/forever
```

/etc/rc.localを編集
`rc.local`はRaspberry Pi起動時に管理者権限で実行されるファイルです

```shell-session
$ sudo nano /etc/rc.local
```
下記のようなファイルです

```sh:rc.local
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.
#
# Print the IP address
_IP=$(hostname -I) || true
if [ "$_IP" ]; then
  printf "My IP address is %s\n" "$_IP"
fi

exit 0
```

ファイル末尾「exit 0」の手前に起動時に実行したいプログラムを指定する

```shell-session
$ sudo -u [ユーザ名] [nodeのパス] [forever のパス] start -a -d [動かしたいスクリプトのパス]
```

例

```sh:rc.local
_IP=$(hostname -I) || true
if [ "$_IP" ]; then
  printf "My IP address is %s\n" "$_IP"
fi

sudo -u username /usr/local/nvm/versions/node/v10.0.0/bin/node /usr/local/nvm/versions/node/v10.0.0/bin/forever start -a -d /home/username/workspace/mylinebot/server.js

exit 0
```
正しく実行されるか確認

```shell-session
$ sudo /etc/rc.local
```

`info:Forever processing file: 動かしたいスクリプトのパス`と出たら成功！

```shell-session
$ sudo /etc/rc.local
My IP address is 192.000.0.0 000.00.00.00 
warn:    --minUptime not set. Defaulting to: 1000ms
warn:    --spinSleepTime not set. Your script will exit if it does not stay up for at least 1000ms
info:    Forever processing file: /home/username/workspace/mylinebot/server.js
```

Raspberry Piを再起動する

```shell-session
$ sudo reboot
```

再度ラズパイに接続し、サービスが起動しているか確認しましょう

Foreverのプロセスを確認するコマンド

```shell-session
$ forever list
```
失敗だと

```shell-session
$ forever list
info:    No forever processes running
```

成功

```shell-session
$ forever list
info:    Forever processes running
data:        uid  command                                       script                                     forever pid id logfile                        uptime       
data:    [0] f70E /usr/local/nvm/versions/node/v10.0.0/bin/node /home/username/workspace/mylinebot/server.js 770     941    /home/username/.forever/f70E.log 0:0:0:46.495 
```
参照記事　[ラズパイ再起動時にNode.jsアプリを自動起動する](https://584homes.com/it/raspberry-pi/rasberrypi-startup1803.html%20=)

# 2. 無線LANの省電力機能をオフ

/etc/rc.localに以下を追記する

```shell-session
iwconfig wlan0 power off
```
無線LANの省電力機能の状態確認。 `Power save: off`と表示されたらOK

```shell-session
$ iw dev wlan0 get power_save
Power save: off
```
Raspberry Piを再起動、再接続し、状態確認しましょう

# 3. ngrokがタイムアウトしないようにする

ngrokは一定の時間が立つと、接続を解除してしまいます。
ngrokで無料のアカウントを作成し設定ファイルを作成すれば、時間がたってもトンネルが解除されなくなります。

ngrokでアカウントを作成 [https://ngrok.com/](https://ngrok.com/)

作成したアカウントでngrokのwebページへログインするとConnect your accoutというところにauthtokenが表示されます。
<img width="760" alt="authtoken.png" src="https://qiita-image-store.s3.amazonaws.com/0/258078/107bab22-8424-f729-d5cc-624932ef4bd0.png">

設定ファイルの作成。以下のコマンドを実行します。
`[ngrokのパス] authtoken [自分のアカウント用Authtoken]`

```shell-session
$ ngrok authtoken XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
```
設定ファイルが、~/.ngrok2/ngrok.yml に作成されます。これでタイムアウトはなくなります！

```shell-session
$ ngrok authtoken XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Authtoken saved to configuration file: /root/.ngrok2/ngrok.yml
```

# 4. ngrokの永続化（screen コマンドの利用）

ngrok(トンネリングサーバー)を常時起動させてラズパイをグローバルに接続しっぱなしにしましょう

Linux では仮想端末を作成する`screen`というコマンドがあります。 「SSH をログアウトしても仮想端末を残す」ことで、仮想端末上にプロセスを残すことができます。

参照記事 [Raspberry pi で SSH ログアウト後もプロセスを残したい](http://edosha.hatenablog.jp/entry/2017/11/10/142855)

インストール

```shell-session
$ sudo apt-get install screen
```
プロセスを残す

screen を起動

```shell-session
$ screen
```

ngrokを起動

```shell-session
$ ngrok http 3000（任意のポート）
```
ngrokのURLを確認。
Ctrl + A、Ctrl + Dで仮想端末からデタッチ（抜け出す）。デタッチ後もプロセスは残り続けます。
デタッチできたら以下のようなメッセージが出ます

```shell-session
[detached from 17974.pts-0.raspberrypi]
```

仮想端末の確認

```shell-session
$ screen -list
```
数字（この場合17974）がプロセス番号です

```shell-session
$ screen -list
There is a screen on:
	17974.pts-0.raspberrypimochi	(2018年06月22日 11時26分49秒)	(Detached)
1 Socket in /var/run/screen/S-user.
```

仮想端末にアタッチ（再接続）したい時は

```shell-session
$ screen -r [プロセス番号]

# もし、セッションが1つだけの時は
$ screen -r
```

参照 [screenコマンドの要点](https://qiita.com/ryounagaoka/items/8203e9c149b542986c92)


完了です！
前回記事・LINE BOTで利用する場合は、このngrokのURLをLINE DevelopersのWebHookURLに登録すれば、常時BOTが使用できるようになります。

# 課題

- サーバーを起動しなおしたり、RaspberryPiの再起動が発生したとき、ngrokのURLが変わってしまう
  - 有料アカウントにすれば固定ドメインが利用可能
  - とりあえず今は保留

参照記事
[google-home-notifier周りをほぼ自動化した](https://qiita.com/k_keisuke/items/3e67aa25a24f07656f47)
[10分でSlackからGoogleHomeを喋らせるめちゃ速レシピ](https://qiita.com/m2u/items/b4bebd3e03930ee77f4d)