2026年5月31日
2026年5月31日
Node.jsアプリをPM2で本番運用する方法:ecosystem設定・自動起動・ログ管理・無停止リロード
PM2 は、Node.js のアプリを常駐させ、落ちたら自動で再起動し、サーバーの再起動後も立ち上げ直してくれるプロセスマネージャーです。本番で使うなら、コマンドを手で打って起動するのではなく、設定ファイル(ecosystem ファイル)に起動方法をまとめ、pm2 startup と pm2 save で自動起動を登録し、ログが溢れないようにローテーションを設定するところまでが一式です。この記事では、その手順と、デプロイ時に接続を切らずに入れ替える方法、運用でつまずきやすい点を説明します。
前提と全体の構成
ここでは Ubuntu などの Linux の VPS に、Node.js の Web アプリ(Express など)を置く場合を例にします。構成は次のとおりです。
- アプリは
127.0.0.1:3000のようにローカルだけで待ち受ける。 - 外からの通信は Nginx が 80/443 番で受け、アプリへ転送する(HTTPS もここで終端する)。
- PM2 がアプリのプロセスを管理し、OS の起動時には systemd 経由で PM2 が立ち上がる。
アプリを直接 80 番で公開しないのは、root 権限が要らなくなること、静的ファイルの配信や HTTPS を Nginx に任せられることが理由です。
PM2 は root ではなく、アプリ専用の一般ユーザー(例: deploy)で動かします。PM2 の状態はユーザーごとのホームディレクトリ(~/.pm2)に保存されるため、あるときは sudo pm2、あるときは一般ユーザーで pm2 と使い分けると、別々の PM2 が2つ動いてしまいます。「pm2 list にアプリが出てこない」という相談の多くはこれが原因です。
インストールと最初の起動
# アプリ用ユーザーで実行(Node.js は nvm などで導入済みとする)
npm install -g pm2
pm2 --version
# まずは手で起動して動作を確かめる
cd /srv/myapp
pm2 start server.js --name myapp
pm2 list
pm2 logs myapp --lines 50
pm2 list で状態が online になり、再起動回数(↺ の列)が増え続けていなければ起動できています。回数が増え続ける場合は起動直後に落ちているので、pm2 logs のエラーを読みます。ポートの重複(EADDRINUSE)や、環境変数の不足がよくある原因です。
ecosystem ファイルに起動方法をまとめる
本番では、起動の設定をファイルにしてリポジトリで管理します。pm2 init simple でひな形が作られます。
// /srv/myapp/ecosystem.config.js
module.exports = {
apps: [
{
name: 'myapp',
script: './server.js',
cwd: '/srv/myapp',
instances: 2, // CPU コア数に合わせる。'max' で全コア
exec_mode: 'cluster', // 複数プロセスで同じポートを共有する
max_memory_restart: '400M', // メモリがこの値を超えたら再起動
kill_timeout: 5000, // 停止の合図から強制終了までの猶予(ミリ秒)
time: true, // ログの各行に時刻を付ける
out_file: '/var/log/myapp/out.log',
error_file: '/var/log/myapp/error.log',
merge_logs: true, // cluster の各プロセスのログを1つのファイルにまとめる
env_production: {
NODE_ENV: 'production',
PORT: 3000,
HOST: '127.0.0.1',
},
},
],
};
sudo mkdir -p /var/log/myapp && sudo chown deploy:deploy /var/log/myapp
pm2 delete myapp # 手で起動したものは消しておく
pm2 start ecosystem.config.js --env production
設定の考え方を補足します。
- cluster モード:
exec_mode: 'cluster'にすると、複数のプロセスが同じポートを共有し、リクエストが振り分けられます。後述の無停止リロードもこのモードで使えます。ただし、セッションをメモリに持つ作りや、WebSocket を使うアプリでは、プロセスごとに状態が分かれてしまいます。セッションを Redis などに置くか、まずはinstances: 1で動かしてください。 - max_memory_restart: メモリリークがあるアプリの応急処置にはなりますが、再起動の頻度が高いならコードの問題です。
pm2 listの再起動回数を定期的に見ます。 - 秘密の値: API キーやデータベースのパスワードを ecosystem ファイルに書くと、リポジトリに入ってしまいます。秘密の値は Git の管理外の
.envファイル(パーミッションは 600)に置き、アプリ側で読み込みます。Node.js の新しい版には--env-fileオプションがあり、ecosystem ファイルのnode_args: '--env-file=.env'で渡せます。使える版かどうかは Node.js のドキュメントで確かめてください。
サーバー起動時に自動で立ち上げる
pm2 startup
# → 「sudo env PATH=... pm2 startup systemd -u deploy --hp /home/deploy」の形の
# コマンドが表示されるので、それをコピーして実行する
pm2 save # 今動いているプロセスの一覧を保存する
pm2 startup は、自分では設定を書き込まず、実行すべきコマンドを表示するだけです。表示されたコマンドを実行して初めて systemd にサービスが登録されます。そのあと pm2 save を忘れると、再起動後に PM2 は立ち上がってもアプリが1つも起動しません。アプリを追加・削除したら、そのたびに pm2 save を実行します。
登録できたかは、メンテナンスの時間にサーバーを再起動して pm2 list で確かめるのがいちばん確かな方法です。nvm で Node.js を入れている場合、Node.js のバージョンを上げると、登録されたサービスが古いパスを指したままになることがあります。バージョンを上げたら pm2 unstartup で登録を外し、pm2 startup からやり直してください。
ログを溢れさせない
PM2 のログは、そのままでは際限なく大きくなり、ディスクを使い切る原因になります。PM2 のモジュールの pm2-logrotate を入れると、サイズや日数でログを切り替えられます。
pm2 install pm2-logrotate
pm2 set pm2-logrotate:max_size 50M # 1ファイルの上限
pm2 set pm2-logrotate:retain 14 # 残す世代数
pm2 set pm2-logrotate:compress true # 古いログを gzip で圧縮
OS の logrotate でまとめて管理したい場合は、pm2-logrotate を入れずに logrotate の設定を書きます。その場合、アプリはファイルを開いたまま書き込み続けるので、copytruncate を指定するか、ローテーション後に pm2 reloadLogs を実行します。どちらの方式にするか1つに決め、二重に設定しないでください。
ログには、リクエストの中身やパスワード、トークンなどを書き出さないようにします。障害の調査に必要なのは、時刻・エラーの内容・処理の識別子です。
デプロイ時に接続を切らずに入れ替える
cd /srv/myapp
git pull --ff-only
npm ci --omit=dev
npm run build --if-present
pm2 reload ecosystem.config.js --env production --update-env
pm2 restart は全プロセスを一度止めてから起動するため、その間のリクエストはエラーになります。cluster モードで pm2 reload を使うと、プロセスを1つずつ入れ替えるため、ほかのプロセスがリクエストを受け続けます。--update-env は、環境変数の変更を反映させるための指定です。
入れ替えをきれいに行うには、アプリ側で停止の合図を受け取ったときの処理を書いておきます。PM2 はプロセスを止めるときに SIGINT を送り、kill_timeout を過ぎても終わらなければ強制終了します。
// server.js の末尾(Express の例)
const server = app.listen(process.env.PORT, process.env.HOST);
process.on('SIGINT', () => {
// 新しい接続の受け付けをやめ、処理中のリクエストが終わったら終了する
server.close(() => {
// データベースの接続などもここで閉じる
process.exit(0);
});
});
デプロイの前には、リリース前のコミットに戻せるようにしておきます。npm ci が途中で失敗した状態で reload すると、全プロセスが起動に失敗することがあります。まずステージングで同じ手順を通してから本番に流してください。
日々の確認に使うコマンド
pm2 list: 状態・CPU・メモリ・再起動回数の一覧。pm2 show myapp: ログの場所、起動したパス、環境など詳しい情報。pm2 monit: CPU とメモリの使い方を端末で見る。pm2 logs myapp --err: エラーのログだけを見る。
外形監視(外から URL にアクセスして応答を見る監視)は PM2 とは別に用意します。PM2 はプロセスが生きているかは見ていますが、アプリが正しく応答しているかまでは見ていないためです。
コンテナで動かす環境なら、Docker や Kubernetes の再起動の仕組みと PM2 が役割を取り合います。その場合は PM2 を使わないか、コンテナ向けの pm2-runtime を使う構成を検討してください。ここでの説明は執筆時点(2026年10月現在)の PM2 に基づいています。オプションは版によって変わることがあるので、公式ドキュメントも参照してください。
まとめ
- PM2 はアプリ専用の一般ユーザーで動かす。
sudo pm2と混ぜると PM2 が2つできる。 - 起動方法は ecosystem ファイルにまとめ、秘密の値は Git の管理外の
.envに置く。 pm2 startupは表示されたコマンドを実行して完了。アプリを変えたらpm2 save。- ログは pm2-logrotate か OS の logrotate のどちらか1つでローテーションする。
- デプロイは cluster モードの
pm2 reloadで入れ替え、アプリ側でSIGINTを受けて後始末をする。