VirtualBoxを使ってExpressアプリを動かしてみる - AlmaLinux

パッケージのアップデート

sudo dnf -y update

EPELリポジトリのインストール

EPELリポジトリをインストールするには以下のようにします。

sudo dnf -y install epel-release

Gitのインストール

Gitをインストールします。

sudo dnf -y install git

# インストールされたかバージョンで確認
git -v

Node.jsのインストール

Node.jsのインストールについては、以下を参考にしてください。

Expressアプリの設置

GitHubからExpressアプリのサンプルをユーザーディレクトリにダウンロードします。

gitでクローンするには、以下のコマンドを実行します。以下のファイルでは、起動ポートを「 4000 」に変更しています。

git clone https://github.com/beginnerP765/exapp.git

ファイアウォールのインストール・設定

ファイアウォールは、利用環境によってはインストールされていないことがあるため、次のコマンドを実行しインストールされているか調べます。

sudo dnf list installd | grep firewalld

インストールされていなければ、以下のコマンドを実行しインストールします。

sudo dnf -y install firewalld

Apache のインストール

Apache をインストールします。

sudo dnf -y install httpd

自動起動の有効化にし、Apache を起動します。

sudo systemctl enable httpd
sudo systemctl start httpd

ファイアウォールの設定を変更します。

sudo firewall-cmd --permanent --add-service=http --zone=public
sudo firewall-cmd --reload

Apache の設定

プロキシサーバーとしての設定をします。「/etc/httpd/conf.d/exproxy.conf」というファイルを作成し、設定をします。

「 exproxy.conf 」の exproxy は好きな名前に変更可能です。vi で存在しないファイルを指定した場合、ファイルが自動で作成されます。

sudo vi /etc/httpd/conf.d/exproxy.conf

設定ファイルにプロキシサーバーとしての設定を書き込みます。

/etc/httpd/conf.d/exproxy.conf

<VirtualHost *:80>
    ProxyPass / http://localhost:4000/
    ProxyPassReverse / http://localhost:4000/
</VirtualHost>

設定を反映させるには、Apache を再起動します。

sudo systemctl restart httpd

Express アプリケーション

ローカル上で作成された Express のアプリを Express-Generator で作成し、ユーザーのホームディレクトリにアップロードします。

アプリケーションのディレクトリに移動し以下のコマンドを実行します。

npm start

ゲスト PC のブラウザで、サーバーにアクセスします。

作成時のサーバーの IP アドレスが「 192.168.11.5 」のため、ブラウザのアドレスバーに IP アドレスを入力します。

Welcome to Express の画面が表示されれば成功です。

SELinux

SELinux を enforcing で利用している場合、503 エラーになるため設定を変更します。

sudo setsebool -P httpd_can_network_connect on

以下の表は、httpd に関する SELinux のプール値についての説明です。

httpd_builtin_scripting on スクリプトへのアクセスを許可する
httpd_can_network_connect off リモートポートへの接続を許可
httpd_can_network_connect_db off データベースサーバーへの接続を許可
httpd_can_network_relay off リバースプロキシとして使用することを許可
httpd_can_sendmail off メールの送信を許可
httpd_enable_cgi off httpd_sys_script_exec_t タイプでラベル付けされたCGIスクリプトの実行を許可
httpd_enable_homedirs off ユーザのホームディレクトリへのアクセスを許可

PM2 の設定

PM2 は、Node.js を本番環境で起動するためツールで、プロセスをデーモン化したり、アプリの起動を管理することができます。

PM2を使ってデーモン化しておかないと、コンソールが起動したまま操作できないため、デーモン化しておきます。

PM2 のインストールは次のようにします。

npm install -g pm2

PM2 で環境変数を設定する

アプリのルートディレクトリに設定ファイルを保存します。ここでは「 pm2myapp.json 」というファイル名にしています。

「 bin/www 」がサーバー起動用のファイルになります。

/home/user/exapp/pm2myapp.json

{
    "name": "myapp",
    "script": "./bin/www",

    "env": {
        "NODE_ENV": "development"
    },

    "env_production": {
        "NODE_ENV": "production"
    }
}

コマンドから利用する環境変数を指定するには次のようにします。

# envを指定しない場合には、設定ファイル内のenvが利用されます。
pm2 start pm2myapp.json

# --envオプションの指定方法は、env_xxx の「 xxx 」の部分を指定します。「 env_production 」を利用したい場合は、以下のようにします。
pm2 start pm2myapp.json --env production

PM2 の自動起動の設定

PM2 には、サーバーが再起動しても自動で Expressアプリを起動する機能があります。

まず、Express アプリのルートディレクトリに移動し、次のコマンドを実行します。

/home/user/exapp のディレクトリに移動して実行

pm2 start pm2myapp.json --env production

Express アプリが起動した状態のまま、次のコマンドを実行します。

pm2 startup

コマンドを実行すると次のような表示がされます。

[PM2] Init System found: systemd
[PM2] To setup the Startup Script, copy/paste the following command:
sudo env PATH=$PATH:/home/user/.nvm/versions/node/v20.15.0/bin /home/user/.nvm/versions/node/v20.15.0/lib/node_modules/pm2/bin/pm2 startup systemd -u user --hp /home/user

「 sudo env 」から始まる部分をコピーし、そのコマンドを実行します。

上記の場合だと、「 sudo env PATH=$PATH:/home/user/.nvm/versions/node/v20.15.0/bin /home/user/.nvm/versions/node/v20.15.0/lib/node_modules/pm2/bin/pm2 startup systemd -u user --hp /home/user 」をコピーします。

以下のコマンドを実行して、設定を保存します。

pm2 save

以下のコマンドを実行し、「 pm2-ユーザー名.service 」の「 STATE 」が「 enabled 」になっていれば設定できています。

sudo systemctl list-unit-files -t service

これで設定は完了です。あとは、サーバーを再起動して、アプリケーションが自動的に起動しているか確認してください。

PM2が自動起動しない場合

SELinux が有効の場合、PM2の自動起動の設定をしてもエラーになり自動起動しません。

SELinux のポリシーの設定が必要になるため、以下のコマンドでログを確認します。

sudo less /var/log/messages

上記の方法以外にエラーのアラートと解決策の概要が生成するには、以下のコマンドを実行します。

sudo sealert -a /var/log/audit/audit.log

SELinux で拒否されている場合は、必要な設定について記載があるため適宜設定を行います。

以下のようなエラーが発生していました。

  • execute アクセス
  • 'read, open' アクセス
  • execute_no_trans アクセス
  • map アクセス
  • execmem アクセス
  • write アクセス
  • create アクセスがファイル /home/user/.pm2/pm2.log で拒否
  • unlink アクセス
  • create アクセスが、sock_file pub.sock
  • unlink アクセスが、sock_file pub.sock で拒否

PM2 が自動起動しない場合の SELinux のポリシー設定ファイル

「 /var/log/audit/audit.log 」のエラーログを確認してポリシーの設定を行う場合、一つずつ設定を行う必要があります。

一度作成された、設定ファイルを保存しておくと開発環境を再構築する場合は、そのファイルをコンパイルすれば次からは楽に設定を行うことができます。

環境によって設定するポリシーは違いますが、VirtualBox で開発環境を作った場合は、以下の設定ファイルで SELinux が有効な状態で動作しました。

my-PM2v605God.te

module my-PM2v605God 1.0;

require {
	type init_t;
	type user_home_t;
	class sock_file { create unlink };
	class file { ioctl write };
}

#============= init_t ==============

#!!!! This avc is allowed in the current policy
#!!!! This av rule may have been overridden by an extended permission av rule
allow init_t user_home_t:file { ioctl write };

#!!!! This avc is allowed in the current policy
allow init_t user_home_t:sock_file unlink;
allow init_t user_home_t:sock_file create;

my-pm2.te

module my-pm2 1.0;

require {
	type init_t;
	type user_home_t;
	class file { execute execute_no_trans open read };
}

#============= init_t ==============

#!!!! This avc is allowed in the current policy
allow init_t user_home_t:file { execute open read };
allow init_t user_home_t:file execute_no_trans;

my-node.te

module my-node 1.0;

require {
	type user_home_t;
	type init_t;
	class file { append create map };
	class sock_file write;
	class process execmem;
}

#============= init_t ==============

#!!!! This avc is allowed in the current policy
allow init_t self:process execmem;

#!!!! This avc is allowed in the current policy
allow init_t user_home_t:file map;
allow init_t user_home_t:file { append create };

#!!!! This avc is allowed in the current policy
allow init_t user_home_t:sock_file write;

それぞれのファイルをコンパイルし設定を適用するには、以下のコマンドを実行します。

# my-PM2v605God.te のコンパイル
# モジュールのコンパイル
checkmodule -M -m -o my-PM2v605God.mod my-PM2v605God.te

# ポリシーパッケージの作成
semodule_package -o my-PM2v605God.pp -m my-PM2v605God.mod

# カーネルへのモジュール読み込み
sudo semodule -i my-PM2v605God.pp

# ------------------------------------------------------------------------
# my-pm2.te のコンパイル
checkmodule -M -m -o my-pm2.mod my-pm2.te
semodule_package -o my-pm2.pp -m my-pm2.mod
sudo semodule -i my-pm2.pp

# ------------------------------------------------------------------------
# my-node.te のコンパイル
checkmodule -M -m -o my-node.mod my-node.te
semodule_package -o my-node.pp -m my-node.mod
sudo semodule -i my-node.pp