CentOSにNode.js + MySQLを利用したアプリケーションをデプロイする


### 各種バージョン
- CentOS7 x86_64
- Node.js v16.14.0
- Nginx 1.20.1
- MySQL Ver 8.2.0

### sshでCentOSに接続
```
$ ssh user@000.000.000.000
Password://パスワードを入力
```

## Node.jsをインストール
```
$ sudo yum install nodejs -y
$ node -v
// v16.14.0と表示されればOK
```

### 作業用にvimをインストール
```
$ vim --version
// VIM - Vi IMproved 8.2 (2019 Dec 12, compiled Nov 13 2021 05:05:08)のように表示されればOK
//入ってなければ以下のコマンドでインストール
$ sudo yum install vim -y
```

## Nginxをインストール
```
$ sudo yum -y install nginx
$ nginx -v
// nginx version: nginx/1.20.1 のように表示されればOK
```
試しにブラウザから`http://000.000.000.000`とサーバーのIPアドレスにアクセスしてみて、CentOSのデフォルト画面が表示されればOK。
![centos_default.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2781928/d3d32a1e-7d77-7753-eb9f-afe92e9dbb25.png)


### （補足）Nginxのエラーが出る場合、SELinuxを無効化する
```
$ sudo vi /etc/selinux/config
// SELINUX=disabledに変更
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
#       enforcing - SELinux security policy is enforced.
#       permissive - SELinux prints warnings instead of enforcing.
#       disabled - No SELinux policy is loaded.
SELINUX=disabled
# SELINUXTYPE= can take one of these two values:
#       targeted - Targeted processes are protected,
#       mls - Multi Level Security protection.
SELINUXTYPE=targeted
```
`:wq`で設定ファイルを保存したら、システムを再起動する。
```
$ sudo reboot
```

再起動したら、getenforceコマンドで、Disabledが返ってきたら無効化されている。
```
$ getenforce
Disabled
```

### Node.js用の設定ファイルを作成
nginxがインストールされたら、/etc/nginx/conf.dディレクトリに、
これからデプロイするNode.jsアプリを起動するための設定ファイルnodeapp.confを新規作成する。
```
$ sudo vim /etc/nginx/conf.d/nodeapp.conf
```
nodeapp.confに、以下の記述を追加する。
```nodeapp.conf
server {
        listen  80;
        server_name 000.000.000.000; //サーバーのIPアドレス
        location / {
               proxy_pass http://127.0.0.1:3000;
        }
}
```

Nginxを再起動する。
```
$ sudo service nginx restart
```
### 80番ポートを解放する
このサーバー上で稼働するwebアプリケーションにブラウザからアクセスするために、
サーバーの80番ポートを解放します。
GCPなどで、インスタンス作成時に80番ポートをダッシュボード上から解放している場合は、この作業は不要です。
```
$ sudo firewall-cmd --add-service=http --zone=public --permanent
//success
$ sudo firewall-cmd --list-services --zone=public --permanent
// dhcpv6-client http ssh と表示されれば、80番ポートが解放されている
```
firewallを再起動
```
$ sudo systemctl reload firewalld
```

### 試しにHello Worldしてみる
Node.jsとNginxの設定が完了したら、試しにNginxのルートディレクトリ'/usr/share/nginx/html'に、ブラウザに「Hello, World」と表示するだけのindex.jsファイルを作成して、アプリケーションが正常に動くか確かめてみます。
```
$ cd /usr/share/nginx/html
$ sudo vi index.js
```
index.jsに以下を記述

```/usr/share/nginx/html/index.js
const http = require('http');

const hostname = '127.0.0.1';
const port = 3000;

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello World');
});

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});
```
vimでindex.jsを`:wq`で保存したら、以下のコマンドでNode.jsアプリを起動。

```
$ node index.js
```
これで、ブラウザから`http://000.000.000.000`とサーバーのIPアドレスを打ち込んでアクセスし、「Hello, World」と表示されていれば成功です。

## MySQLをインストール
の前に、デフォルトで入っているMariaDBを削除する。
```
$ sudo rpm -qa | grep mariadb
//mariadb-libs-5.5.60-1.el7_5.x86_64のように表示される

$ sudo yum remove mariadb-libs
$ rm -rf /var/lib/mysql/
```

MySQLのリポジトリをインストール
```
$ sudo yum install https://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm
$ sudo yum repolist all | grep mysql
//以下のようにリポジトリ一覧が表示されればOK
mysql-cluster-7.5-community/x86_64                  MySQL Cluste disabled
mysql-cluster-7.5-community-source                  MySQL Cluste disabled
mysql-cluster-7.6-community/x86_64                  MySQL Cluste disabled
...
```
MySQL8をインストール
```
$ sudo yum --enablerepo=mysql80-community install mysql-community-server
// バージョン確認
$ mysqld --version
// /usr/sbin/mysqld  Ver 8.0.35 for Linux on x86_64 (MySQL Community Server - GPL)のように表示されればOK
```

MySQL8を起動
```
systemctl start mysqld.service
```

### MySQLのパスワードを設定
MySQLをインストールした段階では、rootユーザーのパスワードが仮で設定されているので、新しいパスワードに変更します。
```
$ grep password /var/log/mysqld.log
// 2024-01-09T12:32:18.352804Z 6 [Note] [MY-010454] [Server] A temporary password is generated for root@localhost: 仮パスワード
//と表示されるので、一時的なパスワードとして設定されている仮パスワードを使ってmysqlにログインします。
```

```
$ mysql -u root
Enter password: //仮パスワードを入力
mysql > use mysql;
mysql > ALTER USER 'root'@'localhost' identified BY '新しいパスワード';
mysql > \q
```
これでMySQLのrootユーザーのパスワードが設定できました。
ここから、アプリケーション用のデータベースを作成していきます。

### データベースを新規作成
MySQLにログイン
```
$ mysql -u root -p
Password://先程設定したパスワード
```
プロンプトの先頭がmysql > に変わったら、以下のSQL文を実行してデータベースを作成。
```sql
CREATE DATABASE nodeapp;

USE nodeapp;

CREATE TABLE users (id INT NOT NULL, username VARCHAR(10), email TEXT, age INTEGER);

INSERT INTO users (id, username, email, age) VALUES (1,'山田太郎','yamada@mail.com',25);
INSERT INTO users (id, username, email, age) VALUES (2,'田中一郎','tanaka@mail.com',32);
INSERT INTO users (id, username, email, age) VALUES (3,'鈴木花子','suzuki@mail.com',45);
INSERT INTO users (id, username, email, age) VALUES (4,'佐藤和子','satoh@mail.com',54);
```

`/q`でMySQLからログアウトして完了。


## Gitをインストール
ローカルで開発したアプリケーションのリポジトリをGitHub上に作成し、そこからcloneする形で今作業をしているCentOS上にデプロイします。
このとき、privateリポジトリにしているとcloneができないので、publicリポジトリにするのを忘れないようにします。

```
$ sudo yum install git
$ git --version
// git version 2.32.0 のように表示されればOK
```

### git cloneでアプリケーションをデプロイ
アプリケーションをデプロイしたいディレクトリ（今回は/usr/share/nginx/html）に移動し、git cloneを実行。
```
$ cd /usr/share/nginx/html
$ git clone https://github.com/ユーザー名/リポジトリ名.git
```

### アプリを起動
npmコマンドで、cloneしてきたアプリケーションを起動します。
```
$ cd リポジトリ名
$ npm start
```
ブラウザから`http://000.000.000.000:3000`にアクセスし、アプリケーションが稼働していたら、デプロイ完了です。
![app.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2781928/0ca2b0ab-2e82-3438-3353-6f8d91b42c4d.png)


### （補足）bash: npm: command not foundとエラーが出たら
通常Node.jsをインストールすると、npmも一緒にインストールされますが、
何らかの事情でnpmがインストールされていない場合に出るエラー。
その場合は、npmをあらためてインストールする。
```
$ sudo yum install npm
```

### アプリケーションを更新したら
`git pull https://github.com/ユーザー名/リポジトリ名.git`で差分データをpullして、`npm start`で確認する。

## サービスとして永続化させる
これで、`npm start`によってアプリケーションを起動できるようになりました。
が、このままだとssh接続を切ったらNode.jsアプリケーションも停止してしまうので、
Node.jsの`pm2`というモジュールを使って、アプリケーションをサービスとして永続化させます。

```
//pm2をグローバルインストール
$ sudo npm install pm2 -g
```
アプリケーションのディレクトリ`/usr/share/nginx/html/nodeapp`に移動し、`pm2 start ./bin/www`でアプリケーションを起動。
```
$ cd /usr/share/nginx/html/nodeapp
$ pm2 start ./bin/www
```
下記のように表示されたら、アプリケーションが起動していますので、
ブラウザからアプリケーションのアドレス`http://000.000.000.000`にアクセスして確認します。
```
[PM2] Starting /usr/share/nginx/html/nodeapp/bin/www in fork_mode (1 instance)
[PM2] Done.
┌────┬────────────────────┬──────────┬──────┬───────────┬──────────┬──────────┐
│ id │ name               │ mode     │ ↺    │ status    │ cpu      │ memory   │
├────┼────────────────────┼──────────┼──────┼───────────┼──────────┼──────────┤
│ 0  │ www                │ fork     │ 0    │ online    │ 0%       │ 5.8mb    │
└────┴────────────────────┴──────────┴──────┴───────────┴──────────┴──────────┘
```

### サーバーの再起動時に自動でアプリケーションも起動させる
ここまでで、ssh接続を切ってもNode.jsアプリケーション自体は稼働し続けるようになりましたが、
サーバー自体が再起動した場合、アプリケーションは停止したままになります。
なので、サーバーの再起動時に自動でアプリケーションも起動させる設定にします。

```
$ pm2 startup
```
コマンドが表示されるので、コピペしてそのまま実行します。
最後に、再起動時にアプリケーションを復旧する設定をして完了です。
```
$ pm2 save
```