はじめに
遅れてしまいましたが、
この記事はLinkbal Advent Calendar 2020の10日目の記事です。
Serverlessについての記事を書こうと思いましたが、準備に間に合わなかったので、このネタは次の記事で書かせていただきます。
本記事はNginx
,pm2
を使ってNuxt.js
のユニバーサルモードの本番環境を構築することについて紹介したいと思います。
環境
- Centos 7.x
インストール
まず、以下の必要なものをインストールする
- Nginx
インストール
$ sudo yum install nginx
自動起動設定
$ sudo systemctl enable nginx
- Node.js(そして、自分の好みのパッケージマネージャーは
yarn
ですので、yarn
もインストールする)
Node.jsのインストール
$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.37.2/install.sh | bash
$ . ~/.nvm/nvm.sh
$ nvm
$ nvm install node
Yarnのインストール
$ curl --silent --location https://dl.yarnpkg.com/rpm/yarn.repo | sudo tee /etc/yum.repos.d/yarn.repo
$ sudo yum install yarn
- pm2:
Node.js
のプロセル状態、ログなどを管理するツールです。Nuxt.jsのユニバーサルモードでサーバーサイドレンダリングはNode.js
で動かせるので、このツールを使うべきです。
$ npm install pm2@latest -g
pm2の設定
プロジェクトのディレクトリ内にpm2設定用ecosystem.config.js
ファイルを作成する
module.exports = {
apps: [
{
name: 'nuxt_app',
cwd: '/path/to/project',
exec_mode: 'cluster',
instances: 2,
script: './node_modules/.bin/nuxt',
args: 'start -n ./tmp/nuxt_app.sock',
env: {
NODE_ENV: 'production'
}
}
]
}
- cwd: アプリケーションを動かせるディレクトリ
- exec_mode:
cluster
モードで動かせる - instances: クラスターのインスタンス数
- script: アプリケーションを動かせるスクリプトのパス
- args:
script
の引数です。今回の紹介はTCPじゃなくて、unix socket
で動かせます。理由はunix socket
の方が効率が高いです。 - env: アプリケーションで使う環境変数。
NODE_ENV: 'production'
はNuxtの本番環境モードの設定のためです。
pm2自動起動の設定
最後に、サーバーを再起動した際に、自動にプロセスを再起動するように設定します。
サーバーを再起動した場合、自動にプロセスを再起動する設定は以下のpm2
コマンドで実現できます。
$ pm2 startup
$ pm2 save
ですが、Unix Socket
で動かせる場合、うまくできなかったです。原因はおそらくpm2
再起動の前に、既存のsocketファイルを削除しないといけないことです。
その代わりに、以下の簡単な起動スクリプトを作成して、サーバーの再起動の時に、pm2を再起動させます。
#!/bin/bash
#
#
# description: PM2 next gen process manager for Node.js
# processname: pm2
#
### BEGIN INIT INFO
# Provides: pm2
# Required-Start: pm2
# Required-Stop:
# Should-Start:
# Should-Stop:
# Default-Start:
# Default-Stop:
# Short-Description: PM2 init script
# Description: PM2 is the next gen process manager for Node.js
### END INIT INFO
# アプリケーション名
NAME=nuxt_app
# pm2のパス: `which pm2`コマンドでわかります。
PM2="/home/webuser/.nvm/versions/node/v15.4.0/bin/pm2"
# nodeのパス: `which node`コマンドでわかります。
NODE="/home/webuser/.nvm/versions/node/v15.4.0/bin/node"
# pm2を動かせるユーザー
USER=webuser
UNIX_SOCKET_PATH=/path/to/project/tmp/nuxt_app.sock
CONFIG_FILE_PATH=/path/to/project/ecosystem.config.js
start() {
echo "Starting $NAME"
su - $USER -c "$PM2 start $CONFIG_FILE_PATH --update-env"
for i in {0..30}
do
echo "Waiting for creating socket file..."
if [ -e $UNIX_SOCKET_PATH ]; then
break
fi
sleep 1
done
# nginxのユーザーもアクセスできるように、権限を設定する
chmod o+w $UNIX_SOCKET_PATH
}
stop() {
su - $USER -c "$NODE $PM2 kill"
}
restart() {
if [ -e $UNIX_SOCKET_PATH ]; then
rm -rf $UNIX_SOCKET_PATH
fi
echo "Restarting $NAME"
stop
start
}
reload() {
echo "Reloading $NAME"
su - $USER -c "$PM2 reload all"
}
status() {
echo "Status for $NAME:"
$NODE $PM2 list
RETVAL=$?
}
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status
;;
restart)
restart
;;
*)
echo "Usage: {start|stop|status|restart}"
exit 1
;;
esac
exit $RETVAL
自動起動設定
$ sudo chkconfig --add nuxt_client
Nginxの設定
Nginxの簡単な設定は以下のようです。
upstream nuxt_client {
server unix:/path/to/project/tmp/nuxt_app.sock fail_timeout=0;
}
server {
listen 80;
server_name example.com;
index index.html;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://nuxt_client;
}
}
デプロイ
デプロイするには、capistrano
を使います。
# config valid for current version and patch releases of Capistrano
lock "~> 3.12.1"
set :application, "nuxt_app"
set :repo_url, "リポジトリのURL"
set :deploy_to, "/var/www/nuxt_app"
set :ssh_options, user: 'webuser'
set :branch, ENV['BRANCH'] || 'master'
# build app
after 'deploy:updated', 'init_app:build'
# restart pm2
after 'deploy:publishing', 'init_app:start'
namespace :init_app do
task :build do
on roles(:web) do
execute "cd #{release_path}; yarn install"
execute "cd #{release_path}; yarn nuxt build"
end
end
task :start do
on roles(:web) do
sudo "/etc/init.d/nuxt_client restart"
end
end
end
以上です。