
シリーズ:Bun × PM2 サーバー運用入門 ( 3 / 3 )
1
基礎:プロセス管理の必要性
2
導入:PM2の基本操作
3
運用:ログ・自動起動・デプロイ
第2回でPM2の基本操作をマスターし、クラッシュしても自動で復活する仕組みが手元で動くようになりました。
最終回となる今回は「本番サーバーに置いてそのまま運用できるレベル」まで仕上げます。
ecosystem.config.js の完成形・OS再起動後の自動起動・ログのローテーション設計・デプロイ手順 の4テーマを順番に進めます。
🔍 前提条件
第2回で作成した bun-server-demo/ と ecosystem.config.js を使います。PM2がインストール済みであることを確認してください( pm2 --version で確認)。
ecosystem.config.js の完成形
第2回では最小限の設定しか書きませんでした。ここでは本番運用に必要なオプションをすべて追加した「完成形」を作ります。
module.exports = {
apps: [
{
/* ── 基本設定 ── */
name: "my-server",
script: "./server.ts",
interpreter: "bun", // Bunで実行する(最重要)
/* ── 再起動ポリシー ── */
watch: false, // 本番ではfalse(開発時はtrueで変更検知再起動)
max_restarts: 10, // 連続クラッシュの上限(超えると停止)
min_uptime: "5s", // この時間内に落ちたらクラッシュとみなす
restart_delay: 3000, // クラッシュ後の再起動待機時間(ms)
/* ── ログ設定 ── */
out_file: "./logs/out.log", // 標準出力の保存先
error_file: "./logs/error.log", // エラー出力の保存先
merge_logs: true, // out と error を1ファイルに統合
log_date_format: "YYYY-MM-DD HH:mm:ss", // タイムスタンプのフォーマット
/* ── 環境変数 ── */
env: {
NODE_ENV: "development",
PORT: 3000,
},
env_production: { // pm2 start --env production で切り替わる
NODE_ENV: "production",
PORT: 3000,
},
},
],
};設定を反映するには、一度削除してから再起動するか pm2 reload を使います。
# production 環境変数で起動する場合
pm2 start ecosystem.config.js --env production
# すでに起動中で設定変更を反映したいとき(無停止で再起動)
pm2 reload ecosystem.config.js --env production 主要オプションの詳細
| オプション | 役割 | 推奨値 |
|---|---|---|
| max_restarts | バグ起因の無限再起動ループを防ぐ上限 | 10 (超えると errored で停止) |
| min_uptime | 起動後この時間内に落ちたらクラッシュと判定 | "5s" 〜 "10s" |
| restart_delay | 再起動までの待機時間(ms)。連鎖クラッシュを抑制 | 3000 〜 5000 |
| watch | ファイル変更時に自動再起動するか | 本番は false 、開発は true |
| merge_logs | stdout/stderr を1ファイルにまとめる | true (見やすい) |
✨ pm2 reload vs pm2 restart の違い
pm2 restart は一度プロセスを落としてから起動するため、数秒のダウンタイムが発生します。 pm2 reload は新旧プロセスを切り替えるためダウンタイムがほぼゼロです。本番環境でのコード更新は reload を使いましょう。
自動起動設定 ― OS再起動後も自動で立ち上がる
セキュリティアップデートなどでサーバーを再起動したとき、PM2アプリが自動で立ち上がるよう設定します。 2コマンドで完了 します。
Step 1 — 起動スクリプトを生成する
pm2 startup
# [PM2] Init System found: systemd
# [PM2] To setup the Startup Script, copy/paste the following command:
# sudo env PATH=$PATH:/home/user/.bun/bin pm2 startup systemd -u user --hp /home/user出力の最後に sudo env PATH=... で始まるコマンドが表示されます。 それをそのままコピー&ペーストして実行してください。 環境によって内容が異なるため、コピーして使います(上記はあくまで例です)。
sudo env PATH=$PATH:/home/user/.bun/bin pm2 startup systemd -u user --hp /home/user
# [PM2] Writing init configuration in /etc/systemd/system/pm2-user.service
# [PM2] Making script booting at startup...
# [PM2] [-] Executing: systemctl enable pm2-user...
# [PM2] [v] Command successfully executed.Step 2 — 現在のプロセスリストを保存する
pm2 save
# [PM2] Saving current process list...
# [PM2] Successfully saved in /home/user/.pm2/dump.pm2これでOS再起動後も、 pm2 save 時点のアプリリストが自動で復元されます。
🔍 アプリを追加・削除したら save し直す
pm2 save は「その時点のスナップショット」を保存します。新しいアプリを追加したり pm2 delete したりした後は、必ず再度 pm2 save を実行してください。
ログ設計 ― ログローテーションと構造化ログ
ログはそのまま放置するとファイルが肥大化し続けます。本番では ローテーション(定期的な切り詰め) を設定するのが必須です。
pm2-logrotate をインストールする
Step 1 — プラグインをインストール
pm2 install pm2-logrotate
[PM2] Installing pm2-logrotate...
[PM2] Module pm2-logrotate installed and running.Step 2 — ローテーション設定を調整する
# 1ファイルの最大サイズ(10MB を超えたらローテーション)
pm2 set pm2-logrotate:max_size 10M
# 保持するファイル数(7世代=約7日分)
pm2 set pm2-logrotate:retain 7
# ローテーション間隔(毎日0時)
pm2 set pm2-logrotate:rotateInterval '0 0 * * *'
# ローテーション後にgzipで圧縮する
pm2 set pm2-logrotate:compress true 構造化ログ(JSON形式)でログを検索しやすくする
エラーを調査するとき、テキストのログより JSON形式のログ のほうが検索・フィルタリングがしやすくなります。Bunのサーバーコードで出力形式を変えます。
// ログ出力のユーティリティ関数
function log(level: "info" | "error", message: string, extra?: Record<string, unknown>) {
console.log(JSON.stringify({
timestamp: new Date().toISOString(),
level,
message,
...extra,
}));
}
const server = Bun.serve({
port: Number(process.env.PORT) || 3000,
fetch(req) {
const url = new URL(req.url);
const start = Date.now();
try {
if (url.pathname === "/") {
const res = new Response("Hello, Bun! 🎉");
log("info", "request", {
method: req.method,
path: url.pathname,
status: 200,
ms: Date.now() - start,
});
return res;
}
return new Response("Not Found", { status: 404 });
} catch (err) {
log("error", "unhandled error", { error: String(err) });
return new Response("Internal Server Error", { status: 500 });
}
},
});
log("info", "server started", { port: server.port });このログ設計にしておくと、後から grep や jq でフィルタリングが簡単になります。
# エラーログだけ抽出
cat logs/out.log | jq 'select(.level == "error")'
# 直近1時間のログだけ表示
pm2 logs my-server --lines 200 | jq '.' デプロイ戦略
コードを更新して本番サーバーに反映する手順を整理します。ここではもっとも汎用的な 「Git pull + pm2 reload」 パターンと、 PM2のdeployコマンド を使うパターンを紹介します。
基本パターン:Git pull + pm2 reload
シンプルで確実な方法です。SSHでサーバーに入り、以下の手順で更新します。
1
最新コードを取得する
GitHubなどからコードをpullします。
2
パッケージを更新する
依存関係の追加・変更があればインストールします。
2
パッケージを更新する
依存関係の追加・変更があればインストールします。
3
ゼロダウンタイムで再起動する
pm2 reload で新旧プロセスを切り替えます。
4
プロセスリストを保存する
OS再起動時に最新状態が復元されるよう保存します。
# 1. 最新コードを取得
git pull origin main
Updating abc1234..def5678
Fast-forward
server.ts | 12 ++++++++++--
# 2. 依存パッケージを更新(変更があれば)
bun install
# 3. ゼロダウンタイムで再起動
pm2 reload ecosystem.config.js --env production
[PM2] Applying action reloadProcessId on app [my-server](ids: [ 0 ])
[PM2] [my-server](0) ✓
# 4. プロセスリストを保存
pm2 save
[PM2] Successfully saved in /home/user/.pm2/dump.pm2 応用パターン:シェルスクリプトで1コマンド化する
上記4ステップを毎回手打ちするのは面倒です。シェルスクリプトにまとめておきましょう。
#!/bin/bash
set -e # エラーがあれば即座に停止
echo "🚀 デプロイを開始します..."
# 最新コードを取得
git pull origin main
# 依存パッケージを更新
bun install
# ゼロダウンタイムで再起動
pm2 reload ecosystem.config.js --env production
# プロセスリストを保存
pm2 save
echo "✅ デプロイ完了!"
pm2 listchmod +x deploy.sh
# 次回以降はこれだけ
./deploy.sh
#🚀 デプロイを開始します...
#✅ デプロイ完了!✨ GitHub Actions で自動化するには
さらに一歩進めるなら、GitHub ActionsでSSH越しに deploy.sh を実行するワークフローを組むと、 git push だけで自動デプロイが走るようになります。今後の応用テーマとして覚えておいてください。
本番運用チェックリスト
| 確認項目 | コマンド | 状態 |
|---|---|---|
| アプリが online になっている | pm2 list | 必須 |
| interpreter: "bun" が設定されている | ecosystem.config.js を確認 | 必須 |
| OS再起動後の自動起動を設定した | pm2 list → pm2 save | 必須 |
| ログローテーションを設定した | pm2 install pm2-logrotate | 必須 |
| デプロイスクリプトを用意した | deploy.sh など | 推奨 |
| 環境変数を env_production に分けている | ecosystem.config.js を確認 | 推奨 |
| 構造化ログ(JSON)を出力している | server.ts のログ実装を確認 | 推奨 |
🎉
シリーズ完走おめでとうございます!
第1回でBun単体の限界を理解し、第2回でPM2の基本操作をマスターし、第3回で本番運用に必要な設定を仕上げました。
ここまでの設定があれば、 クラッシュ時の自動再起動・OS再起動後の自動起動・ログの永続管理・ゼロダウンタイムデプロイ が整った状態です。
✅ 自動再起動
✅ バックグラウンド実行
✅ OS再起動後の自動起動
✅ ログローテーション
✅ ゼロダウンタイムデプロイ