Raspberry Pi をサーバとしてRailsのアプリケーションをデプロイするまで

# 概要
開発中のRailsアプリケーションを実際に自分でも使いたいので、できるだけ金をかけずにデプロイする方法を考えた。URLとかドメインとかの個人的なこだわりとアプリケーションの使用環境を考えるとHerokuはやなので、Apache&Passengerのコンボで以前購入したRaspberry Piをサーバーとして、アプリケーションをデプロイしてみる。作業が色々回りくどかったことと、あまり包括的にラズパイでのサーバー構築に関してカバーしてる記事がなかったので備忘として残しておくことに。
自分も初めてやったし独学なので、今後のために極力わかりやすく丁寧に書く。
*セキュリティは現段階では(おそらく)貧弱なので自己責任でお願いします。ご指摘いただけると幸いです。
*各ステップにおける説明の加減は自分の理解度が低いところに優先的に比重をかけています。

## 前提
使用するのは主に、
- Raspberry Pi
- Filezilla (Piへのファイル転送用)
- Apache
- Passenger
- Ruby&Rails (Ruby 2.6.0, Rails 5.2.3)
- ドメインと転送設定他

**Raspberry Pi**は、以前トライしてみたHeadlessインストール(ディスプレイなしでのインストール)で要素が増えすぎて大変だったので、Noob経由でRaspbian Liteをインストール。sshを有効にした状態からスタート。操作はMacbookからsshで行う。
**Apache**と**Passenger**はこれから導入していく。
**RubyとRails**もこれからインストール。すでに作成したアプリケーションがあるのでそれをデプロイする。
**ドメイン**は、フリードメインを入手してある(.tk)。Piが繋がってるルーターで転送設定して、かつドメインからDNSでルータに繋がるように設定済み。

ドメインのところは、それはそれで初心者にはややこしい。また機会があれば書くけれど、今回は面倒なので割愛。特にドメインとかいらないよって場合は、この記事ではドメインをpublic IPで置き換えて入れればだいたいうまくいくはず。というかそちらの方が要素が少ないので確実。

## 目標
最終的に、ブラウザーで専用のドメインのURLを入力して、アプリケーションのトップページが表示されれば成功。

## 流れ
全体的な流れは以下のように進めます。
0. スタート地点の確認
1. RubyとRailsをインストール
2. Apacheをインストール
3. Passengerをインストール
4. Testアプリで動作確認
5. アプリケーションの転送と設定
6. 最終確認

長くなりそう。
それでは早速。

# 0. スタート地点の確認
前提でも書きましたが、目標に照らしてさらっと現状を確認します。
現段階でブラウザにURL入れるとこんな感じ。
<img width="571" alt="image.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458673/fcfe5285-a2d2-0159-4419-1c1aa79f8739.jpeg">
当たり前。
当たり前すぎてある意味安心。

# 1. RubyとRailsをインストール
下準備として、まずRubyをPiに入れていきます。今回は2.6.0でいきます。
## sshでpiにログイン
MacbookのTerminalからsshでPiにログインします。
`ssh pi@YOUR_DOMAIN`
*pi*はRaspberry Piのユーザ名(デフォルトはpiです)、YOUR_DOMAINのところに自分のドメインか、転送設定をしたpublic IPを入れます。


## バージョン管理のための下準備
アプリケーションによって使用するrubyのバージョンが異なる場合があるので、バージョン管理をするために使うrbenvを入れます。

まずはパッケージの更新。

```shell:pi
$ sudo apt-get update
$ sudo apt-get upgrade
```

gitを入れる。rbenv入れるのとかupdateに使います。 

```shell:pi
sudo apt install git
```

nodejs (念のため)

```shell:pi
$ sudo apt-get install nodejs
```

### rbenvインストール (バージョン管理用)
rbenv

```shell:pi
$ sudo git clone https://github.com/rbenv/rbenv.git ~/.rbenv
```

これでrbenvは入ったんですが、これを`rbenv init ほにゃらら`で実行できるようにするため、俗にいう「pathを通す」ということをします。

```shell:pi
$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
$ echo 'eval "$(rbenv init -)"' >> ~/.bashrc
```
.bashrcはbashが起動されるたびに実行される。`>>`は追記という意味なので、.bashrcに`rbenv init -`を追記することになる。.bassh_profileはログイン時のみなのでsshだとめんどくさそうということで、ここでは.bashrcにしておく。(sshでrapberry pi再起動した時は嫌な思い出しかない)

次。ruby-buildを入れておきます。rbenvでrubyをインストールするために必要です。~/.rbenv/plugingsに作成されます。

```shell:pi
$ git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
```

最後にrehashする。

```shell:pi
$ sudo rbenv rehash
```
rbenvでは、バージョンごとに実行するファイルを分けるためにerb, gem, irb等ごとにフォルダを用意し、以下にバージョンごとのファイルを振り分けてくれます。shimと呼ばれるやつです。こうしておくことで、rbenv関連のコマンドが入ると、~/.rbenv/shimsを通して、バージョンに適切なファイルを実行できるようにしてあります。このshimsは、新しいgemなどを入れるたびに更新する必要があるため、それを行なっているのが上記のコマンド。

ここで念のため、一度MacbookのTerminalも閉じて、もう一度sshを接続し直します。

## Rubyをインストール
まずはインストールできるバージョンを確認。上記でgitからrbenv/ruby-buildを入れているなら最新なはずです。

2.6.0があるか確認。
 
```shell:pi
$ rbenv install --list
```
<img width="210" alt="Screen Shot 2019-07-12 at 10.37.48.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458673/c4582ddb-8fe1-a0dc-9b4f-df5e20dd01bd.jpeg">
あった。よし。

今回は2.6.0を入れます。
2.4, 2.5あたり以前を入れる場合は注意。CPUとの相性がどうたらでPassengerでBus ErrorやSegmentation Fault Errorが出たりします。解決法はありますが、めんどいので2.6.0。解決法は[ここ(HatenaBlog)](https://lilac-xi.hatenablog.com/entry/2018/08/31/175719)
時間かかるので注意。僕の場合は30分弱かかった。

```shell:pi
$ rbenv install 2.6.0
$ rbenv global 2.6.0 # 以降使用するバージョンを設定
$ rbenv rehash # 恒例のrehash
```

インストールできたか確認する。

```:pi
$ ruby --version
=> ruby 2.6.0p0 (2018-12-25 revision 66547) [armv7l-linux-eabihf]
```
バージョン情報が表示されたということは、入ってる。
よし。

## Railsのインストール
### 導入
Railsを入れていきます。
まずパッケージ管理用のbundlerを入れます。

```shell:pi
$ gem install bundler
```

Railsを入れます。
これは僕の場合は15分くらいかかりました。

```shell:pi
$ gem install rails
```

動作確認。

```:pi
$ rails --version
=> Rails 5.2.3
```
おっけい。

# 2. Apacheをインストール
こちらは、Raspberry Pi公式で[ドキュメンテーション](https://www.raspberrypi.org/documentation/remote-access/web-server/apache.md)があるのでそれに従います。(この記事では利用しませんが、index.htmlを変更して自分の簡単なwebサイトをApacheに表示させる方法も書いてあります。)

```shell:pi
$ sudo apt-get update
$ sudo apt-get install apache2 -y
```

-yは、`--assume-yes`の略で、promptに対して自動で`y`で回答するというもの。

## Apache動作確認
ここまでうまくいって入れば、ブラウザでURLを入力すればApacheの初期画面が表示されるはず。
やってみる。
<img width="1440" alt="image.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458673/990b57d8-12c9-b4c9-1294-f5fb2baa1f04.jpeg">
やった...! (涙目

# 3. Passengerをインストール
次。ApacheでRailsアプリケーションを動かすために、ApacheのモジュールであるPhusion Passengerを入れます。インストールと初期設定(configuration)で少し量があるので見出し分けます。

## インストール
まずはPassengerをgemでインストール。
5分ほどかかります。sudoは使わない。

```shell:pi
$ gem install passenger
```

次に、ApacheとPassengerを連帯させます。コマンドを入力するとインストラクションが表示されるので、従っていけば大丈夫です。しっかり読みながら進めます。

```shell:pi
$ passenger-install-apache2-module
```

いくつかEnterを押すと、自動でチェックを始める。
<img width="565" alt="image.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458673/6dc85b4a-6192-8333-4692-b47bf65b8e1c.jpeg">
チェックが終わると、必要なもののインストール方法を教えてくれる。
<img width="565" alt="image.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458673/bac0b772-c422-324d-73ac-08eea064a890.jpeg">

従順に従って、すべてインストールします。
文頭にはsudoをつけて実行します。
僕の場合は、
- `sudo apt-get install libcurl4-openssl-dev`
- `sudo apt-get install ruby-dev`
- `sudo apt-get install apache2-threaded-dev`
- `sudo apt-get install libapr1-dev`
- `sudo apt-get install libaprutil1-dev`

やってみると、エラーが出た。

```:pi
$ sudo apt-get install apache2-threaded-dev
=> Reading package lists... Done
Building dependency tree       
Reading state information... Done
E: Unable to locate package apache2-threaded-dev
```
対処法は、こう書き換えて実行すること。原因は不明。
`sudo apt-get install apache2-dev`


全部終わったら、再度

```shell:pi
$ passenger-install-apache2-module
```
ここは20分以上かかりました。

備考:
仮にインストールしたはずなのにまた同じインストール要求をされる場合は、
`sudo apt autoremove`
を行なって、apache2-devのみ入れて、もう一度
`passenger-install-apache2-module`
を行なってみるとうまくいくかも。

終了すると以下のような表示が出ます。
<img width="650" alt="image.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458673/a95200bc-7de1-b2c6-b690-246c8e3493eb.jpeg">

Apache configurationファイルを編集し、以下を追記してくださいという表示です。僕の場合はこのように出ています。

```:pi
   LoadModule passenger_module /home/pi/.rbenv/versions/2.6.0/lib/ruby/gems/2.6.0/gems/passenger-6.0.2/buildout/apache2/mod_passenger.so
   <IfModule mod_passenger.c>
     PassengerRoot /home/pi/.rbenv/versions/2.6.0/lib/ruby/gems/2.6.0/gems/passenger-6.0.2
     PassengerDefaultRuby /home/pi/.rbenv/versions/2.6.0/bin/ruby
   </IfModule>
```
これは環境によって変わる可能性があるので、ご自分のコンソールに表示されたものをコピーしておいてください。

## 初期設定 (configuration)
上記でコピーを取ったものをApacheのconfigurationファイルに追加します。

"Press ENTER when you are done editing."

とあるので、念のため別のsshセッションを開始してそこから編集します。

基本的にApacheのconfigurationファイルは、
`/etc/apache2/`
内にある、apache2.confです。

編集権限を持たせるためsudoでテキストエディタ(nano)を起動します。

```shell:pi
$ sudo nano /etc/apache2/apache2.conf
```

コピペ。
<img width="650" alt="image.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458673/d481f172-c158-c253-9d04-7f33066fa206.jpeg">

`ctr+x`のちに`Y`、そして`Enter`を押すと保存してnanoを終了します。

1つめのsshに戻って、`Enter`を押すと、インストールが正しく行われたかチェックしてくれます。
<img width="650" alt="image.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458673/2497531a-49b9-1028-5c6a-d576408de199.jpeg">
`Everything looks good. :-) `
を表示されればOk.

最後に念のため、PassengerとApache双方がうまく動いているか確認。

```shell:pi
$ sudo passenger-config validate-install
```

すると
<img width="640" alt="image.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458673/8ccb4e8a-2ad8-bce6-a5a3-0f2b59d5e697.jpeg">

おっと、

```:pi
* Checking whether the Passenger module is correctly configured in Apache... ✗

Incorrect Passenger module path detected
   
   Phusion Passenger for Apache requires a 'LoadModule passenger_module'
   directive inside an Apache configuration file. This directive has been
   detected in the following config file:
   
      /etc/apache2/apache2.conf
   
   However, the directive refers to the following Apache module, which is wrong:
   
      /home/pi/.rbenv/versions/2.6.0/lib/ruby/gems/2.6.0/gems/passenger-6.0.2/buildout/apache2/mod_passenger.so
   
   Please edit the config file and change the directive to this instead:
   
      LoadModule passenger_module /var/lib/gems/2.5.0/gems/passenger-6.0.2/buildout/apache2/mod_passenger.so

```

configファイルは存在するけど、Apacheへのパスの設定が間違っている、と言っています。
ただ僕はrubyをrbenvで管理しており、rubyも2.6.0を入れたので、パスはあっていると判断。
続行します。


# 4. Testアプリで動作確認
Railsでテスト用のアプリを作成し、Passengerにそのファイルを参照させることで、URLにアクセスするとRuby on Railsの初期画面が表示されるところまで持っていきます。これで、Apache, Passenger, Railsが正しく動作することを確認。

## TestアプリをRailsで作成
ただプロジェクトを作るだけです。
プロジェクトを作成するパスまでナビゲートし、rails用のフォルダを作成。

```shell:pi
$ cd /var/www/ 
$ sudo mkdir rails # rails用のフォルダ作成
$ sudo chmod -R 777 rails # permissionを設定 (注意!)
$ cd rails # 作ったフォルダに移動
```
**3行目の `sudo chmod -R 777 rails` は、危険な方法です。**
今回はRailsが必要なフォルダを作成するためにrailsフォルダの全ての権限を解放しています。しかし、これは今回の目的が実験的にRailsを動かすためであるからで、セキュリティ的には危険です。ウェブサイトとして公開した際、訪問者がrailsフォルダ内のデータをどうとでもできる状態です。本来はApacheのみに権限を与えることでRailsが必要な挙動を許可されるようにします。 [参考1](https://stackoverflow.com/questions/8127849/rails-3-1-errnoeacces-permission-denied/12700438#12700438), [参考2](https://serverfault.com/questions/357108/what-permissions-should-my-website-files-folders-have-on-a-linux-webserver)

今回は個人的なテストなのでよしとして、ここで、Railsプロジェクトを作成。

```shell:pi
$ rails new TestApp --skip-bundle
```

`--skip-bundle`は、初期に自動でbundle installするのを飛ばします。古いバージョンのRailsでは、初期のbundle installが問題を起こすことがあったので念のため。


## PassengerをTestAppに向ける
まず、使うrubyのパスを調べます。

```shell:pi
$ passenger-config about ruby-command
=> passenger-config was invoked through the following Ruby interpreter:

  Command: /home/pi/.rbenv/versions/2.6.0/bin/ruby # これがrubyのパス。

  Version: ruby 2.6.0p0 (2018-12-25 revision 66547) [armv7l-linux-eabihf]

```

ということで、`/home/pi/.rbenv/versions/2.6.0/bin/ruby`がrubyのパス。

次に、`/etc/apache2/apache2.config`を再度nanoで編集し、以下を追記します。

```shell:pi
<VirtualHost *:80>
    ServerName yourserver.com # 自分のドメイン

    # Tell Apache and Passenger where your app's 'public' directory is
    DocumentRoot /var/www/rails/TestApp/public # 先ほど作ったTestApp内の'public'というフォルダ

    PassengerRuby /home/pi/.rbenv/versions/2.6.0/bin/ruby # 今見つけたrubyへのパス。

    # Relax Apache security settings
    <Directory /var/www/rails/TestApp/public> # ここのパスも、先ほどと同じくTestAppのpublicフォルダ
      Allow from all
      Options -MultiViews
      # Uncomment this if you're on Apache > 2.4:
      #Require all granted
    </Directory>
</VirtualHost>
```

先ほどと同じように、`ctr+x` → `Y` → `Enter`で保存してnanoを終了します。

できたら、Apacheを再起動します。

```shell:pi
$ sudo apachectl restart
```

ここまできたら、早速ブラウザからドメインにアクセスして見ましょう。

<img width="939" alt="image.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458673/ede17d5d-3dc4-1af1-6455-2ba0f23f5ef2.jpeg">
なんでやねん。

まずは、ブラウザ上からエラーメッセージの詳細を確認できるように設定しましょう。
`/etc/apache2/apache2.conf`に、

```shell:pi
PassengerFriendlyErrorPages on
```
と追記します。
VirtualHostタグの中に。
<img width="483" alt="hide.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458673/14ad7a15-958a-22c5-76c4-e8a0432b79e9.jpeg">


Apacheを再起動。

```shell:pi
$ sudo apachectl restart
```

ブラウザを更新すると、
<img width="947" alt="image.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458673/8f952dd3-a615-8a92-9203-0cc51bab0b1e.jpeg">
よし、進歩。


わかった、bundleだ。

```shell:pi
$ cd /var/www/rails/TestApp
$ bundle install
```

更新。
<img width="617" alt="image.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458673/90e52bbc-1d2e-4561-714b-102a42fd0834.jpeg">
なんでやねん。

あ、わかった、RailsアプリがDevelopmentになってると、Passengerはアプリを起動してくれません。それを、Developmentモードでも大丈夫だよとPassengerに伝えるために、Apacheのコンフィギュレーションをいじります。

なので、`/etc/apache2/apache2.conf`を再度編集し、`RailsEnv development`の記述を追加します。

```shell:pi
$ sudo nano /etc/apache2/apache2.conf
```
<img width="674" alt="hide2.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458673/91f9c27f-92ff-9976-4a14-f8eb83a1d1e9.jpeg">


できたら、
`sudo apachectl restart`でApacheを再起動。

ブラウザを更新すると...

<img width="675" alt="image.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458673/88ce7ceb-679c-0a73-be57-e85a2cb4dc38.jpeg">
これが見えた時の喜びのすごさよ。

# 5. アプリケーションの転送と設定
ただのRailsの画面では面白くないので、あらかじめ作成しておいたアプリをPiに転送して、それが動くか確かめて見る。

FileZillaで転送します。

Quick ConnectionでPiに接続後、アプリのフォルダを
`/var/www/rails` 内にドラッグドロップします。

転送が完了したら、`apache2.conf`を編集。

僕の場合アプリ名(つまりフォルダ名)は
`Daruma`
なので、

`/etc/apache2/apache2.conf`をnanoで編集し、VirtualHostの部分を以下のように編集します。

```shell:pi
<VirtualHost *:80>
    ServerName YOUR DOMAIN # ドメイン名またはIP
    # Tell Apache and Passenger where your app's 'public' directory is
    DocumentRoot /var/www/rails/Daruma/public # ← ここを変更。
    
    RailsEnv development
    PassengerRuby /home/pi/.rbenv/versions/2.6.0/bin/ruby
    PassengerFriendlyErrorPages on
    # Relax Apache security settings
    <Directory /var/www/rails/TestApp/public>
      Allow from all
      Options -MultiViews
      # Uncomment this if you're on Apache > 2.4:
      #Require all granted
    </Directory>
</VirtualHost>

```

できたら保存。

忘れずに、

```shell:pi
$ bundle install
```


# 6. 最終確認
ブラウザーを更新して、アプリのトップページが表示されるか確かめます。

<img width="753" alt="image.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458673/eaec290c-1152-ab9b-c2a3-410c4acc5944.jpeg">
よっしゃ。
目標達成!!!





/