Nuxt.js使用時のサーバ設定

# Node.jsのインストール

各ユーザにて。バージョンはフロントに合わせる。

```
git clone https://github.com/nodenv/nodenv.git ~/.nodenv
git clone git://github.com/nodenv/node-build.git ~/.nodenv/plugins/node-build
echo 'export PATH="$HOME/.nodenv/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(nodenv init -)"' >> ~/.bash_profile
source ~/.bash_profile

nodenv install 10.15.3
nodenv local 10.15.3
node -v
```

yarnも必要ならば

```
curl -o- -L https://yarnpkg.com/install.sh | bash
source ~/.bashrc
```

# プロジェクトのインストールと起動確認

```
git clone git@bitbucket.org:test/test.git repo/
yarn install
yarn run build
#フロントのコマンド設定による→nuxt buildのこと
yarn start
#フロントのコマンド設定による→nuxt startのこと
#localhost:3000で起動する
```

# apacheの設定

Let's用にドキュメントルートも残しつつ、プロキシで3000ポートへ

```
<VirtualHost *:80>
    ServerName example.com
    ErrorLog /home/example/logs/error_log
    CustomLog /home/example/logs/access_log common
    <Proxy *>
        Require all denied
        Require ip xxx.xxx.xxx.xxx
    </Proxy>
    DocumentRoot /home/example/public_html
    ProxyPass /.well-known/ !
    ProxyPass / http://localhost:3000/
    ProxyPassReverse / http://localhost:3000/
</VirtualHost>
```

yarn start
している状態で、httpへアクセスし、表示されるかどうか確認する。

# PM2でデーモン化

yarn startで起動したプロセスは終了しておく。

```
npm install pm2 -g

#管理するコマンドを指定するファイルを作成
vi pm2.config.js

module.exports = {
  apps : [
  {
    name: "nuxt",
    script: "yarn start",
    cwd : '/home/example/repo/'
  }
  ]
}

#開始
#nodenvでやってる場合はパスを指定
/home/example/.nodenv/versions/10.15.3/bin/pm2 start pm2.config.js
#systemctlに登録
/home/example/.nodenv/versions/10.15.3/bin/pm2 startup
#ここでsudoしろと言われるので、sudoまたはrootになって実行する
root$ env PATH=$PATH:/home/example/.nodenv/versions/10.15.3/bin /home/example/.nodenv/versions/10.15.3/lib/node_modules/pm2/bin/pm2 startup systemd -u example --hp /home/example
#root終了
#pm2立ち上がり時に起動するプロセスを保存
/home/example/.nodenv/versions/10.15.3/bin/pm2 save
```

# Nuxtの更新方法

CIなどでは下記を実行

```
cd repo
git checkout . && git fetch && git pull
yarn install
yarn run build
/home/example/.nodenv/versions/10.15.3/bin/pm2 restart nuxt
```

# APIサーバの設定

テスト中などIP制限をする場合は、NuxtのサーバのIPも許可する必要がある。
SSRの場合はクライアントではなく、サーバからアクセスがある。

# 運用してみて判明したよろしくない現象

## 問題1：プロジェクト更新時（pm2 restart nuxt）にサーバが1分ほど503で落ちていた

- 原因1
    - restart時にnodeが数秒落ちる
- 原因2
    - apacheがproxyで http://localhost:3000/ へ流す際に、送信先が落ちているので、一定時間（デフォルトで60秒）送信を止めていた。
        - apacheのエラーログで`ap_proxy_connect_backend disabling worker for (localhost) for 60s` と表示
        - `ProxyPass / http://localhost:3000/ retry=0` でデフォルト60秒が0秒になる。実際にnodeが立ち上がるまでは1秒ちょっとのようなので、落ちている時間をその1秒ちょっとまで減らすことは可能。だが、なるべくダウンタイムはゼロにしたい。

## 問題2：ビルド時（yarn run build）に現在使用している.nuxtフォルダの中身が一時的に削除される

その結果、jsファイルなど404が発生する。
ビルドがある程度進むと解消される（ビルドが遅いので30秒くらいは404が発生してしまう）。

## 上記を解決するために

- CPUが複数コア使用できる場合は、pm2のclusterモードを使用すればいいらしい。
    - 今回のサーバは1コアだが、試しにclusterモードで動かしてみたらエラーが発生した。
- 予備プロセスをホットスタンバイさせ、プロジェクト更新時は一時的に切り替える。
    - 今回はこちらを採用

## 設定

### apacheのロードバランス機能を使用

```
ProxyPass / balancer://devcluster/ lbmethod=byrequests timeout=1 maxattempts=1
ProxyPassReverse / balancer://devcluster/
<Proxy balancer://devcluster>
    BalancerMember http://localhost:3002 loadfactor=1 retry=10
    BalancerMember http://localhost:3003 status=+H
    ProxySet failonstatus=500,503
</Proxy>

# ProxyPass / balancer://devcluster/ の最後のスラッシュが無いとエラーになったので注意
```

Apache モジュール mod_proxy
https://httpd.apache.org/docs/2.2/ja/mod/mod_proxy.html

Apacheロードバランサで負荷分散。冗長化構成を開発環境でも。～負荷分散と冗長化の基礎を添えて～
https://www.ritolab.com/entry/128

apacheのmod_proxy_balancerを使ってロードバランサを試してみる
http://djangoapplab.com/22/

mod_proxy_balancer の振り分け挙動について調べたのと failonstatus を試してみた
https://inokara.hateblo.jp/entry/2013/12/04/071312

Apacheで実現するロードバランサー
https://www.geek.sc/archives/777

apache 2.2.12以降で ProxyPassReverse が balancer:// でも使えるようになってた
https://hogem.hatenablog.com/entry/20100908/1283951825

“No protocol handler valid for the URL” with httpd mod_proxy_balancer
https://serverfault.com/questions/773449/no-protocol-handler-valid-for-the-url-with-httpd-mod-proxy-balancer

### ホットスタンバイ用のプロジェクトフォルダを作成

```
git clone -b develop git@bitbucket.org:test/test.git /home/dev_example/repo_hotstandby
yarn install
yarn run build
```

### PM2でプロセスを2個起動

ポートを別々にする。

```
    {
      name: "dev_nuxt",
      script: "yarn start",
      cwd: "/home/dev_example/repo/",
      env: {
        PORT: 3002,
        NODE_ENV: "development"
      }
    },
    {
      name: "dev_nuxt_hotstandby",
      script: "yarn start",
      cwd: "/home/dev_example/repo_hotstandby/",
      env: {
        PORT: 3003,
        NODE_ENV: "development"
      }
    }
```

### テスト

通常使用するプロセスをstopしてみる。
問題なくサイトが見えれば、ホットスタンバイしているプロセスが使用されているのが確認できる。

### CI

- 通常プロセスをstop→ホットスタンバイプロセスが使用される
- 通常プロジェクトを更新
- 通常プロセスをstart
- sleep（確実に立ち上がるのを待つ）→通常プロセスが使用されるようになる
- ホットスタンバイプロジェクトを更新
- ホットスタンバイプロセスをrestart

```
cd /home/${DEV_PREF}example/repo
/home/${DEV_PREF}example/.nodenv/versions/10.15.3/bin/pm2 stop ${DEV_PREF}nuxt
git checkout . && git fetch && git pull
yarn install
yarn run build && /home/${DEV_PREF}example/.nodenv/versions/10.15.3/bin/pm2 start ${DEV_PREF}nuxt

sleep 10

cd /home/${DEV_PREF}example/repo_hotstandby
git checkout . && git fetch && git pull
yarn install
yarn run build && /home/${DEV_PREF}example/.nodenv/versions/10.15.3/bin/pm2 restart ${DEV_PREF}nuxt_hotstandby
```

# ログの場所

```
/home/example/.pm2
pm2.log
# pm2をリスタートした場合などのログ

/home/example/.pm2/logs
# 各プロセスのログ。nodeのエラーなどもここに出る
```