Sakura VPS + CentOS 7 + Nginx + pm2 + Nuxt.js で本番環境を構築する

## はじめに
時代の流れなのかどうなのかはわかりませんが、Nuxt.js のデプロイ方法を調べると Heroku だの Firebase だの Netlify だの GitHub Pages だの、それ系の記事はたくさん引っかかるんですが、実際問題、「本番環境で Ubuntu や CentOS 上で動作させる Nuxt.js」に絞ると、ほとんど日本語での情報が出てきません。

困った。でも困ってても仕方ない。
ということで、趣味サイトのフロント部分を PHP から Nuxt.js に変えたので、そこらへんのことを書いていきます。

## 環境
- Sakura VPS
- CentOS 7.x
- Nginx mainline
- Node.js 10.x
- Nuxt 2.x universal mode

## 必要なものをインストールする

サーバにログインして、いろいろインストール、設定していきます。

Nginx のインストールと起動:

```
vi /etc/yum.repos.d/nginx.repo
```

```:/etc/yum.repos.d/nginx.repo
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/mainline/centos/7/$basearch/
gpgcheck=0
enabled=1
```

```
yum -y install --enablerepo=nginx nginx
nginx -v
systemctl start nginx
systemctl enable nginx
```

nginx をリバースプロキシとして使い Nuxt.js を起動させる設定:

```conf:/etc/nginx/conf.d/example.com
map $sent_http_content_type $expires {
    "text/html"                 epoch;
    "text/html; charset=utf-8"  epoch;
    default                     off;
}

server {
    listen 80;
    server_name example.com;
    return 301 https://example.com$request_uri;
}

server {
    listen       443 ssl;
    server_name  example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    #ssl_... settings

    gzip            on;
    gzip_types      text/plain application/xml text/css application/javascript;
    gzip_min_length 1000;

    location /.well-known {
        root  /path/to/example.com/public/;
    }

    location / {
        expires $expires;

        proxy_redirect                      off;
        proxy_set_header Host               $host;
        proxy_set_header X-Real-IP          $remote_addr;
        proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto  $scheme;
        proxy_read_timeout                  1m;
        proxy_connect_timeout               1m;
        proxy_pass                          http://127.0.0.1:3000;
    }
}
```


server_name とか https 化とかでちょいちょい設定が変わってくるので読み取ってください。
ここらへんは公式ドキュメントの日本語翻訳もあり助かります。
[nginx をリバースプロキシとして使う](https://ja.nuxtjs.org/faq/nginx-proxy/)

Nginx の再起動:

```
systemctl restart nginx
```


Node.js のインストール:
(\<version> 部分はそれぞれの環境で異なるので書き換えてください)

```
curl -sL https://rpm.nodesource.com/setup_<version>.x | bash -
yum -y install nodejs
node -v
```

n さん入れとくと便利なのでインストール ([https://github.com/tj/n](https://github.com/tj/n)):

```
npm install -g n
n <version>
```

Nuxt.js の起動を pm2 というプロセスマネージャで管理したいのでインストール:

```
npm install -g pm2
```

これで準備はだいたい OK です。

## デプロイする

API 側は PHP で書いていて [Deployer](https://deployer.org/) (Capistrano みたいなもの) というツールでデプロイしているので、Nuxt.js 側もそれでデプロイします。
(ここらへんも環境に合わせて差し替えてください)

```php:deploy.php
namespace Deployer;

require 'recipe/common.php';
require 'recipe/npm.php';

set('repository', 'something...');

set('clear_paths', [
    // something...
]);

host('example.com')
    // something...
    ->stage('production')
    ->set('branch', 'master')
    ->set('deploy_path', '/path/to/project');

after('deploy:update_code', 'npm:install');
task('npm:build', 'npm run build');
task('pm2:start', 'cd {{deploy_path}} && pm2 startOrRestart ecosystem.config.js');

task('deploy', [
    'deploy:info',
    'deploy:prepare',
    'deploy:lock',
    'deploy:release',
    'deploy:update_code',
    'npm:build',
    'deploy:clear_paths',
    'deploy:symlink',
    'pm2:start',
    'deploy:unlock',
    'cleanup',
])->desc('Deploy example.com');

after('deploy', 'success');
```

内容としてはサーバにログインして `npm install` して `npm run build` してプロジェクトルートに移動して pm2 で Nuxt.js を立ち上げる、といった流れです。ビルド後は最低でも .nuxt, node_modules, static ディレクトリと pakage.json だけあれば動作するので、その他は削除しても問題ないかと思います。

サーバのプロジェクトルートに pm2 の設定ファイルを用意します:

```js:/path/to/project/ecosystem.config.js
module.exports = {
  apps : [{
    name: 'example.com',
    exec_mode : 'cluster',
    instances: 0,
    cwd: './current',
    script: './node_modules/nuxt-start/bin/nuxt-start.js',
    log_date_format: 'YYYY-MM-DD HH:mm Z'
  }]
}
```

これで 簡単に言うと `npm run start` を pm2 にまかせる形になります。pm2 の cluster モードについては詳しく説明しませんが、上記の設定の場合、サーバの CPU のコア数分同時にインスタンスが立ち上がります。

デプロイの準備が終わったのでクライアントから以下を実行します:
(Deployer でデプロイする場合)

```
composer global require deployer/deployer
composer global require deployer/recipes
cd /path/to/deploy_script_directory
dep deployer prodction
```

デプロイが上手くいったかサーバで `pm2 list` を叩いてみたり、実際 example.com にアクセスして確認してみましょう。お疲れさまでした :)

## その他の注意点

上記の諸々の設定だけでは、VPS 側で再起動などが発生した場合 (メンテナンスなどで)、pm2 で起動させたプロセスが停止してしまうので、VPS の再起動があった場合に、自動でプロセスを再度起動させる設定もしておいたほうがいいかなと思います。

やり方としては以下 (pm2 でプロセスを起動させたユーザで行う):

```
pm2 startup
// コマンドが表示されると思うのでコピペします
pm2 save
```

これで安心 :)


## 成果物

[PlusArchive](https://plusarchive.com)
[GitHub - jamband/plusarchive.com](https://github.com/jamband/plusarchive.com)

## まとめ
というか、そんなことより早く Vue.js, Nuxt.js で TypeScript をざわざわしない気分で書けるようになってほしいですよね。この趣味サイトも Vue.js 3 がリリースされて Nuxt.js でもざわざわしない気分で TypeScript を書けるようになってから、徐々に対応していきたいと思います。Vue.js 3 が待ち遠しい！

## リンク
[nginx をリバースプロキシとして使う](https://ja.nuxtjs.org/faq/nginx-proxy/)
[PM2](https://pm2.keymetrics.io/)
[Deployer](https://deployer.org/)