Linuxサーバーを運用する上で、避けて通れないトラブルの一つが「ログファイルの肥大化によるディスク容量枯渇(Disk Full)」です。Webサーバー(Nginx / Apache)や自作のWebアプリケーション(Python, Node.js, Go等)、バッチ処理のログを放置すると、数週間〜数ヶ月でディスクを圧迫し、最悪の場合はOSやデータベースがクラッシュしてサービス停止に追い込まれます。
この問題を自動で解決する標準ツールが「logrotate(ログローテート)」です。logrotateを正しく設定すれば、ログを日次や週次で新しいファイルに切り替え(ローテーション)、過去ログを自動圧縮(gzip)し、指定した世代数(例: 14世代、30世代)を超えた古いログを安全に自動削除してくれます。
しかし、いざ /etc/logrotate.d/ に設定ファイルを書こうとすると、「copytruncate と create + postrotate はどちらを使うべき?」「設定したのにローテーションされない」「テスト実行はどうやるの?」といった疑問やトラブルに直面しがちです。
この記事では、logrotate 設定ファイルの書き方、主要ディレクティブの意味と一覧、Nginxや自作アプリ向けの実践設定例、logrotate -d(ドライラン)や logrotate -f(強制実行)による動作確認手順、パーミッションエラー等のトラブルシューティングまで、実務で即コピペして使える形で徹底解説します。
【早見表】logrotate 設定ディレクティブ & 管理コマンド チートシート
logrotate の設定ファイル(/etc/logrotate.d/*)で頻繁に使用する主要ディレクティブと、動作確認用の管理コマンドの一覧です。
主要ディレクティブ早見表
| ディレクティブ | 設定例・引数 | 動作・役割 |
|---|---|---|
| daily / weekly / monthly | daily |
ローテーションを実行する周期(日次 / 週次 / 月次 / 年次)。 |
| rotate | rotate 14 |
保持するログの世代数。超過した古い世代は自動削除される。 |
| size / maxsize | maxsize 100M |
指定サイズを超えた場合にローテーションを実行(日次待たず制限可能)。 |
| compress | compress |
ローテーション後の過去ログを gzip で圧縮して容量を節約。 |
| delaycompress | delaycompress |
直近の過去ログ(.1)の圧縮を次回まで遅延(ログ書き込み中エラー防止)。 |
| dateext | dateext |
過去ログの末尾に連番(.1)ではなく日付(YYYYMMDD等)を付与。 |
| missingok | missingok |
対象ログファイルが存在しなくてもエラーを出さずスキップ。 |
| notifempty | notifempty |
ログファイルが空(0バイト)の場合はローテーションを実行しない。 |
| create | create 0640 www-data adm |
ローテーション直後に新しい空ファイルを指定のパーミッション・所有者で作成。 |
| copytruncate | copytruncate |
現行ログをコピー後に元ファイルを空(0バイト)に切り詰める(シグナル不要)。 |
| su | su appuser appgroup |
指定したユーザー・グループの権限でローテーション処理を実行。 |
| postrotate ~ endscript | postrotate ... endscript |
ローテーション完了後に実行するシェルコマンド(シグナル送信等)。 |
| sharedscripts | sharedscripts |
対象ログが複数あっても postrotate スクリプトを1回だけ実行。 |
管理・テストコマンド早見表
| コマンド例 | 実行目的・動作内容 |
|---|---|
sudo logrotate -d /etc/logrotate.d/myapp |
ドライラン(デバッグ表示): 実際のファイル変更を行わず、設定構文とローテーション判定をシミュレーション。 |
sudo logrotate -vf /etc/logrotate.d/myapp |
強制実行(詳細出力): 期間やサイズの条件を無視して強制的にローテーションを実行し、詳細ログを表示。 |
cat /var/lib/logrotate/status |
ステータス確認: 各ログファイルが最後にローテーションされた日時の一覧を確認。 |
systemctl status logrotate.timer |
自動実行タイマー確認: systemdによる定期実行スケジュールの稼働状態を確認。 |
1. logrotate の基本構造と動作の仕組み
logrotate を扱う上で、まず理解しておくべきは「logrotate 自体は常駐デーモンではない」という点です。logrotate はバックグラウンドで常に動いているわけではなく、OSのスケジューラーによって1日1回(または定期的に)呼び出されてバッチ実行されます。
設定ファイルの配置構成
Linux環境における logrotate の設定は、以下の2階層に分かれています。
- 全体共通設定:
/etc/logrotate.conf
システム全体のデフォルト設定(全ログ共通の周期や圧縮設定など)が定義されています。末尾でinclude /etc/logrotate.dが指定されており、個別設定ディレクトリを読み込みます。 - 個別アプリケーション設定:
/etc/logrotate.d/
Nginx, Apache, rsyslog, 自作アプリケーションなどの個別設定ファイルを配置するディレクトリです。新規にログローテーションを追加する場合は、この/etc/logrotate.d/配下にファイルを作成するのが標準的なルールです。
# /etc/logrotate.d/ 配下の設定ファイル一覧を確認
ls -la /etc/logrotate.d/
# 出力例:
# -rw-r--r-- 1 root root 232 apt
# -rw-r--r-- 1 root root 408 dpkg
# -rw-r--r-- 1 root root 382 nginx
# -rw-r--r-- 1 root root 670 rsyslog
誰が logrotate を実行しているのか?(cron vs systemd timer)
logrotate が自動実行されるタイミングは、ディストリビューションやバージョンによって以下のいずれかで管理されています。
- systemd timer(Ubuntu 20.04+, Debian 11+, RHEL 8+, AlmaLinux/Rocky Linux等):
logrotate.timerがlogrotate.serviceを毎日定期的にキックします(通常は午前0時〜早朝)。systemctl status logrotate.timerで次回実行時刻を確認できます。 - cron.daily(従来の環境):
/etc/cron.daily/logrotateシェルスクリプトがanacronやcron経由で日次実行されます。
# systemd タイマーの次回実行予定を確認
systemctl list-timers logrotate.timer
実行履歴を記録するステータスファイル
logrotate は「前回のローテーション日時」をステータスファイル(/var/lib/logrotate/status または /var/lib/logrotate.status)に記録しています。この記録をもとに、「前回から1日(または1週間)経過したか」を判定して処理を行います。
2. 設定ファイル(/etc/logrotate.d/)の書き方と主要ディレクティブ一覧
個別設定ファイル(例: /etc/logrotate.d/myapp)の基本構文は、「対象ログファイルのパス」を指定し、中括弧 { ... } の中にディレクティブを並べる形式です。
# /etc/logrotate.d/myapp の基本構文
/var/log/myapp/*.log {
daily
rotate 14
missingok
notifempty
compress
delaycompress
copytruncate
}
ここからは、設定ファイルで使用できる主要ディレクティブを用途別に詳しく解説します。
【1】ローテーション周期と保持世代数
| ディレクティブ | 詳細解説と使いどころ |
|---|---|
| daily | 毎日1回ローテーションを実行します。WebアクセスログやAPIログなど、日次で区切りたい大半のログに最適です。 |
| weekly [weekday] | 週に1回ローテーションを実行します。weekly 0(日曜)のように曜日を指定することも可能です。 |
| monthly | 月に1回、月初にローテーションを実行します。出力頻度の低い管理ログ等に向いています。 |
| yearly | 年に1回、年の初めにローテーションを実行します。 |
| rotate <count> | 保持する過去ログの世代数を指定します(例: rotate 30 で30世代)。これを超えた最も古いログは自動的に削除されます。rotate 0 を指定すると過去ログを残さず即座に削除します。 |
| size <size> | ファイルサイズが指定値(例: size 100M, size 1G, size 500k)を超えた場合にローテーションします。daily等の時間指定よりもサイズ条件が優先されます。 |
| maxsize <size> | 指定周期(daily等)に達していなくても、サイズがこの上限を超えた場合にローテーションを実行します。急激なログ急増によるディスク圧迫を防ぐセーフティネットとして非常に有効です。 |
| minsize <size> | 指定周期(daily等)に達していても、ファイルサイズがこの下限未満の場合はローテーションをスキップします。 |
【2】圧縮とファイル命名規則
| ディレクティブ | 詳細解説と使いどころ |
|---|---|
| compress | ローテーションされた過去ログを gzip で圧縮(.gz)します。テキストログは通常70%〜90%圧縮できるため、ディスク節約に必須です。 |
| nocompress | 過去ログを圧縮しません(デフォルト)。 |
| delaycompress | 直近にローテーションされたファイル(.1 または前日分)の圧縮を、次回のローテーション時まで1回分遅延させます。アプリケーションが古いファイルを開いたままログを書き込み続けている場合のエラーを防ぎます(compress と併用)。 |
| dateext | 過去ログのファイル名末尾に連番(app.log.1)ではなく、日付文字列(例: app.log-20260826.gz)を付与します。日次ログの管理やS3等のアーカイブ時に極めて分かりやすくなります。 |
| dateformat <format> | dateext で付与する日付フォーマットを strftime 形式でカスタマイズします(例: dateformat -%Y%m%d)。 |
| dateyesterday | dateext で付与する日付を、ローテーション実行日(本日)ではなく「昨日(ログが記録されていた日付)」にします。日次バッチで前日分ログを整理する際に直感的です。 |
【3】例外制御・ファイル生成・実行権限
| ディレクティブ | 詳細解説と使いどころ |
|---|---|
| missingok | 対象のログファイルが存在しなくてもエラーを出さず、警告なしで処理を続行します。一時的に停止しているサービスや動的ログには必須の設定です。 |
| nomissingok | ログファイルが存在しない場合にエラーを出力します(デフォルト)。 |
| notifempty | ログファイルが空(0バイト)の場合はローテーションを行いません。無駄な空ファイル(app.log.1.gz)の量産を防ぎます。 |
| ifempty | ログファイルが空であっても強制的にローテーションを行います(デフォルト)。 |
| create <mode> <owner> <group> | ローテーション(名前変更)直後に、新しい空のログファイルを指定のパーミッション・所有者・グループで即時作成します(例: create 0640 www-data www-data)。 |
| su <user> <group> | root権限ではなく、指定したユーザー・グループの権限でローテーションを実行します。非特権ユーザーのログディレクトリで parent directory has insecure permissions エラーが出る場合に必須です。 |
| olddir <directory> | ローテーション後の過去ログを同一ディレクトリではなく、指定したサブディレクトリ(例: olddir /var/log/myapp/archive)へ移動して保管します。 |
【4】スクリプト実行とプロセス通知(シグナル制御)
| ディレクティブ | 詳細解説と使いどころ |
|---|---|
| copytruncate | 現行のログファイルを別名へコピーした後、元のログファイルの内容を空(0バイトに truncate)にします。プロセスを再起動せず、シグナル送信も不要でログローテーションを行えるため、自作アプリやDocker環境で多用されます。 |
| prerotate ~ endscript | ローテーション処理が始まる直前に実行するシェルスクリプトを記述します。 |
| postrotate ~ endscript | ローテーション処理が完了した直後に実行するシェルスクリプトを記述します。Nginx等のWebサーバーに「ログファイルを再オープン(Reopen)」させるシグナル(kill -USR1)を送信する際によく使われます。 |
| sharedscripts | 設定ファイル内でワイルドカード(例: /var/log/nginx/*.log)により複数のログファイルがマッチした場合でも、postrotate / prerotate スクリプトを全ファイルまとめて1回だけ実行します。無駄なシグナル連打や再起動を防ぐために必須です。 |
3. どちらを使う?「copytruncate」vs「create + postrotate」徹底比較
logrotate を設定する際、実務で最も重要となるのが「copytruncate を使うべきか、それとも create + postrotate(シグナル再オープン)を使うべきか」という設計判断です。
なぜこの2つの方式があるのか?(Linuxのファイルハンドル問題)
Linuxでは、プログラムがログファイルを開くと「ファイルディスクリプタ(inode)」を保持し続けます。単に mv app.log app.log.1 でファイル名を変更しただけでは、プログラムは名前が変わった app.log.1 の方へログを書き込み続けてしまいます。
| 方式 | 動作の仕組み | メリット | デメリット・注意点 |
|---|---|---|---|
| create + postrotate (シグナル再読込方式) |
1. mv app.log app.log.12. create で新しい空 app.log 作成3. kill -USR1 <pid> でアプリに再オープン指示 |
ログの欠落が一切ない(0%)。 ファイル移動のみで高速。 |
アプリケーション側がシグナルによるログ再オープン(USR1 や HUP)に対応している必要がある。 |
| copytruncate (コピー&切り詰め方式) |
1. cp app.log app.log.12. 元の app.log をサイズ0に truncate(> app.log) |
アプリの改修・シグナル対応が不要。 Python, Node.js, Java, Docker等どんなプログラムでも動く。 |
「コピー中」から「切り詰め」までの数ミリ秒間に書き込まれたログが極稀に消失する可能性がある。大容量ログだとコピー負荷大。 |
どちらを選ぶべきかの判断基準チャート
- Nginx, Apache, rsyslog, PostgreSQL, MySQL 等:
迷わずcreate + postrotate(シグナル送信)を選択します。公式パッケージの設定もすべてこの方式です。 - Python (FastAPI / Flask / Django), Node.js (Express / NestJS), Go, Ruby on Rails, Java (Spring Boot) 等の独自アプリ:
アプリ側でシグナルハンドラを特別に実装していない限り、copytruncateを選択するのが最も安全で簡単です。 - Docker コンテナ(JSONログやマウントされたファイル):
コンテナ内のプロセスにホストからシグナルを送るのは困難なため、copytruncateが標準です。
4. 【実践例】コピペで使える logrotate 設定ファイル集
実務の現場でそのままコピー&ペーストして使える実践的な設定ファイル例です。用途に合わせて調整してください。
実践例1:Nginx / Webサーバー向け(標準的なシグナル方式)
Nginxのアクセスログ・エラーログを日次でローテーションし、14世代保持、gzip圧縮、日付サフィックスを付与する王道設定です。
# /etc/logrotate.d/nginx
/var/log/nginx/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
create 0640 www-data adm
sharedscripts
dateext
dateformat -%Y%m%d
postrotate
if [ -f /var/run/nginx.pid ]; then
kill -USR1 $(cat /var/run/nginx.pid)
elif [ -f /run/nginx.pid ]; then
kill -USR1 $(cat /run/nginx.pid)
fi
endscript
}
create 0640 www-data adm: 新規ログを Nginx 実行ユーザー(www-data)と管理者グループ(adm)で作成します。kill -USR1 <pid>: Nginx に「ログファイルを新しいパスで開き直せ」というシグナルを送ります。サービス断(ダウンタイム)は一切発生しません。sharedscripts:access.logとerror.logの2つがあっても、シグナル送信は1回だけにまとめられます。
実践例2:自作Webアプリケーション(Python / Node.js / Go / Rails)向け
バックグラウンドで動く独自アプリケーションのログを copytruncate で安全にローテーションする設定です。専用ユーザー権限での実行にも対応しています。
# /etc/logrotate.d/myapp
/var/log/myapp/*.log {
daily
rotate 30
missingok
notifempty
compress
delaycompress
copytruncate
dateext
dateformat -%Y%m%d
su appuser appgroup
}
copytruncate: アプリケーションを再起動することなく、ログファイルを切り詰めてローテーションします。su appuser appgroup: ログディレクトリの所有者がappuserの場合、logrotate が権限エラー(insecure permissions)になるのを防ぎます。rotate 30: 過去30日分のログを保持します。
実践例3:Docker コンテナログ(json-log)向け
Docker のデフォルトロギングドライバ(json-file)で肥大化しやすいコンテナログを、容量上限(maxsize)を設けて定期ローテーションする設定です。
# /etc/logrotate.d/docker-containers
/var/lib/docker/containers/*/*-json.log {
daily
rotate 7
missingok
notifempty
compress
delaycompress
maxsize 50M
copytruncate
}
maxsize 50M: 1日の途中でログが急増し50MBを超えた場合でも、日次を待たずに即時ローテーションされます。
実践例4:過去ログを専用の保管ディレクトリ(olddir)に退避する設定
アクティブなログディレクトリを綺麗に保ちたい場合、圧縮された過去ログを archive フォルダに退避させることができます。
# /etc/logrotate.d/batch-archive
/var/log/batch/*.log {
weekly
rotate 8
missingok
notifempty
compress
delaycompress
copytruncate
olddir /var/log/batch/archive
create 0640 batchuser batchuser
}
※ olddir で指定するディレクトリ(例: /var/log/batch/archive)は、事前に mkdir で作成し、同じ所有権・パーミッションを設定しておく必要があります。
5. logrotate の動作確認・デバッグ・強制テスト手順
設定ファイルを作成・変更したら、「本番で放置して翌朝エラーになっていた」という事態を避けるため、必ず手動で動作確認テストを行いましょう。
Step 1:ドライラン(-d / –debug)で設定構文と判定をチェック
-d(デバッグ)オプションを付けると、実際のファイル移動や圧縮は一切行わず、設定ファイルの構文チェックと「どのログがローテーション対象になるか」のシミュレーション結果のみを出力します。
# デバッグモードで実行(ファイル変更なし・安全)
sudo logrotate -d /etc/logrotate.d/myapp
【出力の見方・確認ポイント】:
reading config file /etc/logrotate.d/myapp
Reading state from file: /var/lib/logrotate/status
Allocating hash table for state file, size 64 entries
Handling 1 logs
rotating pattern: /var/log/myapp/*.log after 1 days (30 rotations)
empty log files are not rotated, old logs are removed
considering log /var/log/myapp/app.log
log does not need rotating (log has been already rotated)
- 構文エラーがある場合は、行番号とともに
error: ...が表示されます。 log does not need rotatingと出た場合は、設定は正しいですが「まだローテーション条件(1日経過など)を満たしていない」ことを意味します。
Step 2:強制実行(-f)と詳細出力(-v)で実テスト
実際にローテーションが正しく行われるか(ファイルがコピー・圧縮・シグナル送信されるか)をテストするには、-f(強制実行: force)と -v(詳細表示: verbose)を組み合わせて実行します。
# 強制的にローテーションを実行(ファイルが実際に切り替わる)
sudo logrotate -vf /etc/logrotate.d/myapp
【実行後の確認コマンド】:
# ログディレクトリを確認して .1 や .gz、日付付きファイルが生成されているか確認
ls -la /var/log/myapp/
# アプリケーションが新しいログファイルに継続して書き込んでいるか確認
tail -f /var/log/myapp/app.log
Step 3:ステータス管理ファイル(/var/lib/logrotate/status)の確認
logrotate が各ログファイルを最後にいつローテーションしたかは、ステータスファイルに記録されています。
# 特定アプリの最終ローテーション記録を確認
grep "myapp" /var/lib/logrotate/status
# 出力例:
# "/var/log/myapp/app.log" 2026-8-26-8:0:0
※ 手動で再度テストしたい場合は、このステータスファイル内の該当行を削除するか、-f オプションで強制実行します。
Step 4:systemd timer の動作状況確認
OSのスケジュール機能によって logrotate が定期的に呼び出される状態になっているかを確認します。
# logrotate タイマーの稼働状況を確認
systemctl status logrotate.timer
# タイマーが停止している場合は起動&自動起動を有効化
sudo systemctl enable --now logrotate.timer
6. 実務でよくあるエラーとアンチパターン解決チェックリスト
logrotate の運用で現場のエンジニアが遭遇しやすいトラブルと、その解決策をまとめました。
| エラー・現象 | 主な原因 | 対処法・解決手順 |
|---|---|---|
parent directory has insecure permissions |
ログディレクトリのパーミッションが他ユーザーから書き込み可能(0777 等)になっている。 |
1. ディレクトリ権限を chmod 755 や 750 に修正。2. 設定ファイル内に su <user> <group> を追記する。 |
| 設定ファイルを作成したのに無視される(実行されない) | 設定ファイル名にドット(.bak, .old, .conf)やチルダ(~)が含まれている。 |
logrotate の include 処理は .rpmorig, .dpkg-old, .bak 等を自動無視します。ファイル名は myapp のように拡張子なしにするのが安全です。 |
| ローテーション後にログが一切出力されなくなった(サイズ0のまま) | create 方式を採用しているのに、postrotate でアプリに再オープンシグナル(USR1 等)を送っていない。 |
1. アプリがシグナル対応なら postrotate に kill -USR1 を設定。2. シグナル非対応なら copytruncate に切り替える。 |
copytruncate でログの一部が欠落・消失する |
毎秒数百行以上のログが出力されている環境で、コピーから truncate までの瞬間にログが書き込まれた。 | 1. アプリ側にシグナルハンドラ(再オープン)を実装し create + postrotate へ移行。2. アプリ側のロギングライブラリ(Python logging 等)で自律ローテーションを行う。 |
error: Compressing program wrote following message to stderr |
ディスク容量がすでに100%になっており、gzip 圧縮処理が途中で失敗した。 | 不要な古い一時ファイルを削除してディスク空き容量を確保してから、再度 logrotate -vf を実行する(詳細は ディスク逼迫の初動対応 参照)。 |
設定ファイルのパーミッションに関する注意点
/etc/logrotate.d/ 配下の設定ファイル自体の所有者は root:root、パーミッションは 0644 である必要があります。他ユーザーへの書き込み権限(0666 や 0777)が付いていると、セキュリティ保護のため logrotate に無視される場合があります。
# 設定ファイルのパーミッションを正しく設定
sudo chown root:root /etc/logrotate.d/myapp
sudo chmod 0644 /etc/logrotate.d/myapp
まとめ & 関連リファレンス
Linux環境で安定したサーバー運用を続けるために、logrotate によるログファイルの世代管理と自動圧縮は必須のインフラ設定です。
- 設定ファイルの配置: 個別の設定は
/etc/logrotate.d/配下に拡張子なしで配置する。 - 方式の選び方: Nginx等のシグナル対応デーモンは
create + postrotate、自作WebアプリやDockerはcopytruncateを採用する。 - 容量・世代の鉄則:
daily+rotate 14〜30+compress+delaycompressを基本構成とし、急増対策にmaxsizeを活用する。 - テストの徹底: 本番適用後は必ず
sudo logrotate -d <config>(ドライラン)とsudo logrotate -vf <config>(強制テスト)で動作を確認する。
ログの保持期間設計やディスク監視の自動化についてさらに深く学びたい方は、以下の関連ガイドもあわせてご活用ください。

コメント