気づいたらディスクが満杯でサイトがダウン…そんな本番事故を防ぐため、logrotateとPHP設定を組み合わせた安全なログローテーション手順を実案件ベースで解説します。
こんな悩みはありませんか?
「深夜にサーバー監視アラートが鳴り響き、確認してみたらディスク使用率が99%。原因を調べると /var/log/php/error.log が数十GBに膨れ上がっていた」——これ、実は珍しい話ではありません。
PHPのエラーログは放置すると静かに、しかし確実に肥大化します。特にWordPressやLaravelで運用しているサイトでは、プラグインの互換性警告や大量のNoticeレベルのメッセージが毎秒積み重なることも。そしてある朝突然、Webサーバーが応答しなくなるという最悪の事態を招きます。
この記事では、実際のクライアント案件での経験をもとに、本番環境で安全に運用できるログローテーション設定を具体的な手順とコードでお伝えします。「設定したけど動かなかった」「ローテーション中にログが消えた」といった失敗を避けるためのポイントも包み隠さず解説します。
なぜエラーログはこれほど肥大化するのか
そもそも、なぜPHPのエラーログはあっという間に巨大化するのでしょうか。原因はいくつかに分類できます。
ログレベルの設定が広すぎる
php.ini の error_reporting が E_ALL に設定されていると、DeprecatedやNoticeといった軽微なメッセージまですべて記録されます。WordPressの場合、古いプラグインがPHP 8系で大量のDeprecatedを吐き続けるケースが頻発しています。
ログローテーションが未設定
サーバーセットアップ時に logrotate の設定を忘れると、ログファイルは永遠に1つのファイルに追記され続けます。月1GBのペースで増えれば、1年後には12GB超。VPSの標準ストレージが20〜30GBであることを考えると、致命的なリスクです。
アプリケーションの例外処理の不備
Laravelでキャッチされない例外が繰り返し発生したり、cronジョブが失敗し続けていたりすると、1行のエラーが1秒ごとに書き込まれることもあります。あるクライアントの本番サーバーでは、バッチ処理のバグにより1時間で600MBのエラーログが生成されていたこともありました。
本番で安全なログローテーション設定:手順を徹底解説
設定は大きく2段階に分かれます。①PHPのログ出力を適切に制御し、②OSレベルのlogrotateでファイルを安全に管理する、という組み合わせが鉄則です。
ステップ1:php.ini のログ設定を見直す
まず現在の設定を確認します。
php -i | grep -E 'error_log|error_reporting|log_errors'
本番環境での推奨設定は以下の通りです。
; エラーをブラウザに表示しない(セキュリティ上必須)
display_errors = Off
; エラーをログに記録する
log_errors = On
; ログの出力先を明示的に指定
error_log = /var/log/php/error.log
; DeprecatedやNoticeは本番では除外して肥大化を防ぐ
; E_ALL から E_DEPRECATED と E_NOTICE を除外
error_reporting = E_ALL & ~E_DEPRECATED & ~E_NOTICE & ~E_STRICT
; 1行あたりの最大バイト数(デフォルトは無制限)
log_errors_max_len = 4096
Laravelの LOG_CHANNEL=daily は非常に便利です。Laravelが自動的に日付付きのログファイル(laravel-2025-01-15.log)を生成し、LOG_DAILY_DAYS で指定した日数より古いファイルを自動削除してくれます。ただし、後述の落とし穴があるので注意が必要です。
ステップ2:logrotate の設定ファイルを作成する
Laravelのdailyチャンネルを使わない場合や、Nginx/Apacheのログも含めて一元管理したい場合は、logrotate の設定が不可欠です。
# 設定ファイルを作成
sudo vim /etc/logrotate.d/php-error
/var/log/php/error.log {
# 毎日ローテーション
daily
# 30世代分保持(30日分)
rotate 30
# ファイルが存在しなくてもエラーにしない
missingok
# ログが空の場合はローテーションしない
notifempty
# 圧縮して保存(ディスク節約)
compress
# 圧縮は1世代遅らせる(書き込み中のファイルを守るため)
delaycompress
# ローテーション後に新しい空のファイルを作成
create 0664 www-data www-data
# ローテーション後にPHP-FPMへシグナルを送り、ログファイルを再オープンさせる
postrotate
/usr/bin/kill -USR1 $(cat /run/php/php8.2-fpm.pid 2>/dev/null) 2>/dev/null || true
endscript
}
設定が正しいか、まずはドライランで確認しましょう。
# -d オプションでテスト実行(実際には何も変更しない)
sudo logrotate -d /etc/logrotate.d/php-error
# 問題なければ強制実行で動作確認
sudo logrotate -f /etc/logrotate.d/php-error
# ローテーションされたか確認
ls -lh /var/log/php/
ステップ3:ディスク使用量のアラートを設定する
ログローテーションを設定しても、突発的なエラー増加でディスクが埋まるリスクはゼロではありません。以下のシェルスクリプトをcronに登録して、事前に検知できる仕組みを作りましょう。
#!/bin/bash
# /usr/local/bin/disk-alert.sh
THRESHOLD=80
USAGE=$(df / | awk 'NR==2 {print $5}' | tr -d '%')
MAIL_TO="[email protected]"
if [ "$USAGE" -gt "$THRESHOLD" ]; then
echo "[警告] ディスク使用率が ${USAGE}% に達しました。" | \
mail -s "[$(hostname)] ディスク使用率アラート" $MAIL_TO
fi
# crontabに登録(1時間ごとに確認)
crontab -e
# 以下を追加
0 * * * * /bin/bash /usr/local/bin/disk-alert.sh
よくある失敗パターンと対処法
失敗① postrotate でPHP-FPMがログを書き続ける
最も多い落とし穴です。postrotate でPHP-FPMにシグナルを送らないと、プロセスは古いファイルディスクリプタを保持し続け、ローテーション後も古いファイルに書き込み続けます。ファイル名は変わっているのにサイズが増え続けるという不思議な状況になります。
対処法は前述の postrotate ブロックに kill -USR1 を必ず記述すること。PIDファイルのパスはPHPのバージョンや環境によって異なります。
# PIDファイルの場所を確認する
ls /run/php/
# php8.2-fpm.pid などが表示されるはず
失敗② Laravelの daily チャンネルで古いログが消えない
Laravelのdailyチャンネルは LOG_DAILY_DAYS で指定した日数を超えたログを自動削除しますが、削除処理はログ書き込み時にしか走りません。アクセスが途絶えた深夜のバッチ処理のみのサーバーでは、削除がいつまでも実行されないことがあります。logrotateと併用して確実に管理する方針を推奨しています。
失敗③ compress と create のオーナー指定ミス
create 0664 www-data www-data のユーザー・グループ指定が誤っていると、PHPがログファイルへの書き込み権限を失い、ローテーション直後だけエラーログが記録されないという状況が発生します。本番で気づきにくいため、ローテーション後に必ず動作確認するクセをつけましょう。
# ローテーション後のファイルオーナー確認
ls -la /var/log/php/error.log
開発・運用でお困りなら
システム開発
設計から運用まで、堅牢なシステムを構築します
※ 通常1営業日以内にご返信します
まとめと次のステップ
PHPのエラーログ肥大化は、適切な設定で確実に防げます。重要なのは「PHP側のログレベル制御」「logrotateによるファイル管理」「PHP-FPMへのシグナル送信」の3点セットを正しく組み合わせることです。
あるクライアントでは、この設定を導入した結果、ディスク使用量が常時30〜40%台で安定するようになり、深夜のアラート対応がゼロになりました。運用コストの削減という意味でも、費用対効果は非常に高い施策です。
「自分のサーバーにlogrotateが入っているか分からない」「PHP-FPMのバージョンが違うので設定を合わせてほしい」といったご相談も、Fivenine Designでは実環境を確認しながら対応しています。設定に不安がある場合はお気軽にお問い合わせください。