logrotateでLinuxのログを自動ローテーションする方法|設定ファイルの書き方とトラブル対処

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOMELinux技術 リナックスマスター.JP(Linuxマスター.JP)Linuxtips > logrotateでLinuxのログを自動ローテーションする方法|設定ファイルの書き方とトラブル対処
「logrotateを設定したはずなのに、ログがローテーションされていない」「設定ファイルの書き方がよく分からない」

Linuxサーバーを運用していると、放置したログファイルがディスクを圧迫して障害につながることがあります。「ネットで調べればすぐ分かる」と思って検索しても、断片的な情報ばかりで結局うまく動かない、そんな経験はないでしょうか。

この記事では、logrotate(ログローテーション)の仕組みから設定ファイルの書き方、手動テスト、トラブル対処まで体系的に解説します。
この記事を読めば、ログ管理の不安を解消し、安定したサーバー運用ができるようになります。

実行環境:RHEL 9.4 / Ubuntu 24.04 LTSで動作確認済み

この記事のポイント

・logrotate は /etc/logrotate.conf と /etc/logrotate.d/ を読み込み、cronまたはsystemdタイマーで1日1回自動実行される
・daily / weekly・rotate N・compress の設定を押さえれば実務の9割に対応できる
・logrotate -d(ドライラン)で設定ミスを本番反映前に検出し、-f で強制実行できる
・postrotate を忘れると、ローテーション後もアプリが古いファイルに書き続けるため必ず動作確認する


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
図解60P/登録10秒/解除も3秒 / 詳細はこちら

なぜlogrotateが必要なのか

Linuxサーバーは稼働している限り、ログファイルを生成し続けます。Webサーバーのアクセスログ、メールサーバーのログ、認証ログなど、放置すれば際限なく肥大化します。

ログが肥大化すると、以下の問題が発生します。

ディスク容量の逼迫:/var/log が100%になるとサービスが停止する
ログ解析の困難:数GBのファイルをgrepするのは現実的ではない
バックアップの肥大化:不要な古いログまで毎回バックアップされる

logrotateは、これらの問題を自動的に解決する仕組みです。現在のログファイルをリネームして退避し、新しい空のファイルに書き込みを継続させます。世代数を超えた古いファイルは自動で削除されます。

たとえば /var/log/messages を毎週ローテーションする設定(rotate 4)にした場合、ファイルは以下のような状態になります。

# ローテーション前 /var/log/messages ← 現在書き込み中 # ローテーション後(compress + dateext + rotate 4 の設定例) /var/log/messages ← 新しい空ファイル /var/log/messages-20260518.gz ← 今週のログ(圧縮) /var/log/messages-20260511.gz ← 1週間前のログ /var/log/messages-20260504.gz ← 2週間前のログ /var/log/messages-20260427.gz ← 3週間前(次回ローテーションで削除)

ほぼすべてのLinuxディストリビューションに標準でインストールされており、Apache、Nginx、syslogなど主要なサービスのログローテーション設定もパッケージに含まれています。

logrotateの仕組み(cronとの関係)

logrotateは常駐プロセス(デーモン)ではありません。cron(定期実行の仕組み)によって1日1回呼び出されて動作します。

具体的な流れは以下のとおりです。

・cronが毎日 /etc/cron.daily/logrotate を実行する
・logrotateが /etc/logrotate.conf を読み込む
・/etc/logrotate.conf の中で /etc/logrotate.d/ 配下の個別設定を読み込む(include)
・各設定ファイルの条件に従ってローテーションを実行する
・実行結果を /var/lib/logrotate/logrotate.status に記録する

RHEL/CentOS 7以降では、cronではなくsystemdタイマー(logrotate.timer)で実行される場合もあります。以下のコマンドで確認できます。

# logrotateがインストールされているか確認する [root@web01 ~]# which logrotate /usr/sbin/logrotate # バージョンを確認する [root@web01 ~]# logrotate --version logrotate 3.21.0 # systemdタイマーの状態を確認する(RHEL 9 / Ubuntu 20.04以降) [root@web01 ~]# systemctl status logrotate.timer * logrotate.timer - Daily rotation of log files Loaded: loaded (/usr/lib/systemd/system/logrotate.timer; enabled; preset: enabled) Active: active (waiting) since Tue 2026-06-10 00:00:01 JST; 10h ago Trigger: Wed 2026-06-11 00:00:00 JST; 13h left Triggers: * logrotate.service # 次回のlogrotate実行時刻を確認する [root@web01 ~]# systemctl list-timers | grep logrotate Tue 2026-06-11 00:00:00 JST 13h left Tue 2026-06-10 00:00:01 JST 10h ago logrotate.timer logrotate.service # 従来のcronで動いているか確認する [root@web01 ~]# ls -la /etc/cron.daily/logrotate -rwx------. 1 root root 130 Apr 1 2026 /etc/cron.daily/logrotate # cronからの呼び出し設定を確認する(RHEL系) [root@web01 ~]# cat /etc/cron.daily/logrotate #!/bin/sh /usr/sbin/logrotate -s /var/lib/logrotate/logrotate.status /etc/logrotate.conf EXITVALUE=0 if [ != 0 ]; then /usr/bin/logger -t logrotate "ALERT exited abnormally with []" fi exit

このスクリプトがポイントです。logrotateが正常終了(終了コード0)しない場合、loggerコマンドでシステムログに「ALERT exited abnormally with [1]」と記録されます。これがcron経由で管理者メールに届く「ALERTメール」の発生源です。

なお、systemdタイマーで管理されている場合は Persistent=true が設定されているため、サーバーが停止していた期間があっても次回起動時に自動でlogrotateが実行されます。cronとsystemdタイマー、どちらの方法でも設定ファイルの書き方は同じです。

基本的な設定方法

1. 設定ファイルの場所を確認する

logrotateの設定ファイルは2つの場所にあります。

/etc/logrotate.conf:全体のデフォルト設定ファイル
/etc/logrotate.d/:サービスごとの個別設定ファイルを格納するディレクトリ

まずは /etc/logrotate.conf の中身を確認してみましょう。

[root@web01 ~]# cat /etc/logrotate.conf # ローテーション周期(weekly = 週1回) weekly # 保持する世代数(4世代分を残す) rotate 4 # ローテーション後に新しい空ファイルを作成する create # ローテーション後のファイル名に日付を付ける dateext # 個別設定ファイルを読み込む include /etc/logrotate.d

この設定が「デフォルト値」として機能します。個別の設定ファイルで同じディレクティブを指定すると、個別設定が優先されます。

/etc/logrotate.d/ には、RPMパッケージがインストール時に自動的に設定ファイルを配置します。

[root@web01 ~]# ls /etc/logrotate.d/ btmp chrony dnf firewalld rsyslog syslog wtmp # rsyslogの設定例を確認する [root@web01 ~]# cat /etc/logrotate.d/rsyslog /var/log/messages /var/log/secure /var/log/maillog /var/log/spooler /var/log/cron { missingok sharedscripts postrotate /usr/bin/systemctl kill -s HUP rsyslog.service >/dev/null 2>&1 || true endscript }

httpd、nginx、syslog、postfixなど、インストール済みサービスの設定ファイルが並んでいるはずです。

2. 個別の設定ファイルを作成する

独自のアプリケーションログなど、自分で設定を追加したい場合は /etc/logrotate.d/ に新しいファイルを作成します。

以下は、/var/log/myapp/ 配下のログを管理する設定例です。

# /etc/logrotate.d/myapp の設定例 /var/log/myapp/*.log { daily rotate 14 compress delaycompress missingok notifempty create 0640 myapp myapp }

設定ファイル名に拡張子は不要です。ファイル名にドット(.)やチルダ(~)が含まれていると、logrotateが読み飛ばすので注意してください。

【重要】設定ファイルのパーミッションは644にする

/etc/logrotate.d/ 配下に置くファイルは、グループや他ユーザーに書き込み権限があると logrotate が読み込みを拒否します。必ず644(root:root)に設定してください。

# 設定ファイルのパーミッションを確認する [root@web01 ~]# ls -la /etc/logrotate.d/myapp -rw-rw-r-- 1 myapp myapp 120 Apr 11 10:00 /etc/logrotate.d/myapp # グループ書き込み権限があると以下のエラーが出る error: Ignoring /etc/logrotate.d/myapp because it is writable by group or world. # 644 (root:root) に修正する [root@web01 ~]# chmod 644 /etc/logrotate.d/myapp [root@web01 ~]# chown root:root /etc/logrotate.d/myapp

設定のポイントは以下の3つです。

パスにはワイルドカードが使える:/var/log/myapp/*.log のように指定すれば、ディレクトリ内の全.logファイルが対象になる
createのパーミッションとオーナーはアプリに合わせる:アプリケーションがログを書き込むユーザー・グループに設定しないと、ローテーション後にログが書けなくなる
postrotateが必要かどうかを確認する:アプリケーションがログファイルを開き直す仕組みを持っているかで判断する。copytruncateを使う方法もある(後述)

3. 主要なディレクティブを理解する

設定ファイルで使う主要なディレクティブ(設定項目)をまとめます。

ディレクティブ説明
daily / weekly / monthlyローテーションの間隔。アクセスログは daily、変化の少ないログは weekly が適切
rotate 数値保持する世代数。rotate 7 なら7世代分を保持し、それより古いものは削除
size サイズ指定サイズを超えた場合のみローテーション(例: size 100M)。daily/weeklyより優先
maxsize サイズdaily/weeklyと併用し、指定サイズ超えなら間隔を待たずにローテーション
minsize サイズdaily/weeklyと併用し、指定サイズ未満ならローテーションしない
compressローテーション後のログをgzip圧縮する
delaycompress圧縮を1世代遅らせる。実務ではcompressとセットで使うのが定番
compresscmd コマンド圧縮コマンドを変更する(デフォルトはgzip。bzip2やxzも指定可能)
compressext 拡張子圧縮後のファイル拡張子を指定(例: .bz2 や .xz)
create モード オーナー グループローテーション後に指定した権限で新しい空ファイルを作成する
missingokログファイルが存在しなくてもエラーにしない
notifemptyログファイルが空ならローテーションしない
maxage 日数指定日数より古いログファイルを削除する
dateextローテーション後ファイルのサフィックスを連番ではなく日付にする
sharedscriptsワイルドカードで複数ファイルがマッチしてもpostrotateを1回だけ実行する
su ユーザー グループローテーションをroot以外のユーザー権限で実行する

ローテーション間隔

アクセスログのように増加が速いログは daily、変化の少ないログは weekly や monthly が適切です。

圧縮

compress と delaycompress はセットで使うのが定番です。delaycompress があると直前のログは圧縮されず素のテキストで残るため、直近のトラブル調査がしやすくなります。「今日のアクセスログをgrepしたい」という場面でも、access.log.1 をそのままgrepできます。

エラー制御

missingok と notifempty は、ほぼすべての設定に入れておくことを推奨します。アプリが一時停止してログが出ないタイミングでエラーが起きることを防げます。

4. dateextでファイル名に日付を付ける

dateextを指定すると、ローテーション後のファイル名に日付が付きます。連番(.1、.2、.3...)より直感的にわかりやすくなります。

/var/log/myapp/app.log { daily rotate 30 compress dateext dateformat -%Y%m%d missingok notifempty }

# dateext有効時のファイル名の例 [root@web01 ~]# ls -la /var/log/myapp/ -rw-r----- 1 root root 245760 Apr 11 09:15 app.log -rw-r----- 1 root root 18432 Apr 10 23:59 app.log-20260410.gz -rw-r----- 1 root root 17920 Apr 9 23:59 app.log-20260409.gz -rw-r----- 1 root root 19456 Apr 8 23:59 app.log-20260408.gz

「3日前のログが見たい」というときに、ファイル名だけで対象を判断できるのが大きな利点です。

5. 手動でローテーションをテストする

設定ファイルを作成したら、いきなり本番で動かすのではなく、必ずテストしましょう。

デバッグモード(-d オプション):実際にはローテーションせず、何が実行されるかを表示します。

# ドライラン(実際にはローテーションしない) [root@web01 ~]# logrotate -d /etc/logrotate.d/myapp WARNING: logrotate in debug mode does nothing except printing debug messages! Consider using verbose mode (-v) instead if this is not what you want. reading config file /etc/logrotate.d/myapp 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 needs rotating rotating log /var/log/myapp/app.log, log->rotateCount is 30 dateext suffix '-20260621' dest: /var/log/myapp/app.log-20260621 compressing log with: /bin/gzip

「log needs rotating」と表示されれば、設定は正しく読み込まれています。「log does not need rotating」は条件をまだ満たしていないという意味です。エラーが出た場合は、パスの記述やディレクティブのスペルを確認してください。

強制実行(-f オプション):条件に関係なく即座にローテーションを実行します。

# 特定の設定ファイルを強制実行する [root@web01 ~]# logrotate -f /etc/logrotate.d/myapp # 実行後にローテーションされたか確認する [root@web01 ~]# ls -la /var/log/myapp/ -rw-r----- 1 myapp myapp 0 Apr 11 15:30 app.log -rw-r----- 1 myapp myapp 245760 Apr 11 15:30 app.log-20260411

-d で問題がないことを確認してから -f で実行する、という手順を守れば安全です。テスト目的で使ってください。本番ではcronによる自動実行に任せるのが原則です。

詳細出力(-v オプション):-f と組み合わせると、実行中の詳細な情報が表示されます。

# 詳細情報を表示しながら強制ローテーション(-v + -f の組み合わせが便利) [root@web01 ~]# logrotate -vf /etc/logrotate.d/myapp rotating log /var/log/myapp/app.log, log->rotateCount is 30 dateext suffix '-20260621' glob pattern '-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]' renaming /var/log/myapp/app.log to /var/log/myapp/app.log-20260621 creating new /var/log/myapp/app.log mode = 0640 uid = 1001 gid = 1001 running postrotate script

-vf の出力で「renaming」→「creating new」→「running postrotate script」と流れれば、設定が正しく動作しています。

強制ローテーション後、実際にファイルが正しく作成されているか ls -lh で目視確認してください。

# ローテーション後のファイル構成を確認する [root@web01 ~]# ls -lh /var/log/myapp/ -rw-r----- 1 myapp myapp 0 Jun 21 15:30 app.log -rw-r----- 1 myapp myapp 240K Jun 21 15:30 app.log-20260621.gz -rw-r----- 1 myapp myapp 210K Jun 20 23:59 app.log-20260620.gz -rw-r----- 1 myapp myapp 198K Jun 19 23:59 app.log-20260619.gz

現在のログファイルがサイズ0(空)になり、直前世代が日付付きで圧縮されていれば成功です。delaycompressを設定している場合、最新1世代は非圧縮(.gz なし)のまま残ります。

6. ステータスファイルでローテーション履歴を確認する

logrotateは最後にローテーションした日時をステータスファイルに記録しています。「本当にローテーションが実行されているのか」を確認するときに使います。

# ステータスファイルを確認する [root@web01 ~]# cat /var/lib/logrotate/logrotate.status logrotate state -- version 2 "/var/log/messages" 2026-4-11-3:0:0 "/var/log/secure" 2026-4-11-3:0:0 "/var/log/maillog" 2026-4-11-3:0:0 "/var/log/cron" 2026-4-11-3:0:0 "/var/log/myapp/app.log" 2026-4-11-15:30:0

日付が更新されていない場合は、logrotateが正常に動いていない可能性があります。/var/log/cron や journalctl -u crond でcronの実行ログを確認してください。

なお、「前回実行済みになっているため今すぐローテーションできない」という場面では、ステータスファイルから該当行を削除することでリセットできます。

# 特定ログのローテーション記録をリセットしたい場合 # ステータスファイルの該当行を削除してから通常実行する [root@web01 ~]# grep -v 'myapp' /var/lib/logrotate/logrotate.status > /tmp/logrotate.status.new [root@web01 ~]# mv /tmp/logrotate.status.new /var/lib/logrotate/logrotate.status # または -f で強制ローテーションする(ステータスを無視して実行) [root@web01 ~]# logrotate -f /etc/logrotate.d/myapp

テスト・開発環境で繰り返しローテーションを確認したい場合に覚えておくと便利です。

応用・実務Tips

postrotateでサービスを再読み込みする

ログファイルをローテーションした後、サービスに「新しいログファイルに書き込んでくれ」と通知する必要がある場合があります。

たとえばApache(httpd)は、起動時にログファイルを開いたまま書き込み続けます。ファイル名が変わっても古いファイルディスクリプタ(ファイルの参照情報)を使い続けるため、postrotateでサービスを再読み込みする必要があります。

注意:postrotateを書き忘れると、ローテーション後もアプリが古いファイルにログを書き続けます。ディスクを解放したつもりでも古いファイルが使われ続けるため、実務では必ず動作確認してください。

# /etc/logrotate.d/httpd の設定例 /var/log/httpd/*log { daily rotate 14 compress delaycompress missingok notifempty sharedscripts postrotate /bin/systemctl reload httpd.service > /dev/null 2>/dev/null || true endscript }

postrotateとendscriptの間に記述したコマンドが、ローテーション後に実行されます。

sharedscriptsは重要なディレクティブです。ワイルドカードで複数のログファイルがマッチした場合、sharedscriptsがないとファイルごとにpostrotateが実行されてしまいます。sharedscriptsを指定すると、全ファイルのローテーション完了後に1回だけ実行されます。

Nginxの場合、systemctl reload を使う方法と、PIDファイルからプロセスIDを取得してUSR1シグナルを直接送る方法があります。USR1シグナルは既存コネクションを切らずにログファイルを切り替えるため、高トラフィック環境では後者が推奨されます。

# Nginx設定例(systemctl reloadを使う方法) /var/log/nginx/*.log { daily rotate 14 compress delaycompress missingok notifempty create 0640 nginx adm sharedscripts postrotate /usr/bin/systemctl reload nginx >/dev/null 2>&1 || true endscript } # USR1シグナルを直接送る方法(PIDファイルを使う) # PIDファイルが存在するかチェックしてからシグナルを送ることで # Nginxが停止中でもエラーにならない /var/log/nginx/*.log { daily rotate 14 compress delaycompress missingok notifempty create 0640 nginx adm sharedscripts postrotate if [ -f /run/nginx.pid ]; then kill -USR1 $(cat /run/nginx.pid) fi endscript }

prerotate ~ endscript を使えば、ローテーション前にコマンドを実行することもできます。

copytruncateを使う場面

postrotateでサービスを再読み込みできない場合や、アプリケーション側にログファイルを開き直す仕組みがない場合は、copytruncateが有効です。

# copytruncateを使う設定例 /var/log/myapp/app.log { daily rotate 7 compress delaycompress missingok notifempty copytruncate }

copytruncateの動作は以下のとおりです。

1. 元のログファイルをコピーしてバックアップを作成する
2. 元のログファイルの中身を空にする(truncate)

ファイル名やiノード(ファイルの識別番号)が変わらないため、アプリケーション側の対応は不要です。

ただし、コピーとtruncateの間に書き込まれたログが失われる可能性がゼロではありません。ミッションクリティカルなログには使わず、postrotateでの再読み込みを優先してください。

圧縮形式を変更する(bzip2 / xz)

デフォルトの圧縮形式はgzipですが、大量のテキストログが出るシステムでは、より圧縮率の高いbzip2やxzに変更することでディスク消費を抑えられます。compresscmdcompressext を組み合わせて圧縮形式を切り替えます。

# bzip2圧縮に変更する設定例 /var/log/bigapp/*.log { daily rotate 7 compresscmd /usr/bin/bzip2 compressext .bz2 compress notifempty missingok create 0644 root root } # xz圧縮に変更する設定例(さらに圧縮率が高い) /var/log/bigapp/*.log { daily rotate 7 compresscmd /usr/bin/xz compressext .xz compress notifempty missingok create 0644 root root }

圧縮率は xz > bzip2 > gzip の順に高くなりますが、圧縮・解凍にかかるCPU時間も増えます。ログサーバーのように書き込みが多い環境では、CPUへの影響を考慮してgzipのままにするか判断してください。bzip2やxzで圧縮されたログは、それぞれ bzcatxzcat で解凍せずに直接閲覧できます。

サイズベースでローテーションする

周期ではなくファイルサイズでローテーションしたい場合は、size ディレクティブを使います。

/var/log/myapp/app.log { size 100M rotate 10 compress dateext missingok notifempty copytruncate }

ログファイルが100MBを超えた時点でローテーションが実行されます。ただし、logrotateはcronから1日1回しか呼ばれないため、1日で100MBを超えるペースでログが増加するなら、cronの実行頻度を上げる(例:1時間ごと)必要があります。

maxageで古いログを日数指定で削除する

rotate は世代数で管理しますが、maxage は日数で管理します。「30日以上前のログは削除する」といった運用に使います。

/var/log/myapp/app.log { daily rotate 90 maxage 30 compress dateext missingok notifempty }

rotate 90 は最大90世代を保持する設定ですが、maxage 30 を併用すると30日を超えたファイルが先に削除されます。実質的に30日分だけが残る運用になります。

ログの保存先を変えてディスクを分離する

ローテーション後のログファイルを別のディレクトリに保存したい場合は、olddir ディレクティブを使います。

/var/log/myapp/app.log { daily rotate 30 compress dateext olddir /var/log/myapp/archive createolddir 0750 myapp myapp missingok notifempty }

olddir:ローテーション後のファイルの移動先ディレクトリ
createolddir:移動先ディレクトリが存在しない場合に自動作成する(パーミッションとオーナーを指定)

dfコマンドで/var/logのディスク使用率が高い場合、olddirで別パーティションに退避させる運用が有効です。

独自アプリケーションのログをローテーションする

自作のアプリケーションやバッチ処理のログをlogrotateで管理する場合の設定例を紹介します。

# /etc/logrotate.d/myapp-batch /var/log/myapp/batch_*.log { weekly rotate 12 compress delaycompress missingok notifempty create 0644 appuser appuser olddir /var/log/myapp/archive dateext dateformat -%Y%m%d }

olddirを使うと、現在のログと過去のログを分離できるため、運用がすっきりします。

ワイルドカードで複数ファイルをまとめて管理する

複数のアプリケーションやモジュールがそれぞれログを生成する場合、ワイルドカードとsharedscriptsを組み合わせて一括管理できます。

# 複数のログファイルをまとめて設定する例 /var/log/myapp/module_*.log { weekly rotate 8 compress delaycompress missingok notifempty su myapp myapp create 0640 myapp myapp sharedscripts postrotate systemctl reload myapp > /dev/null 2>&1 || true endscript }

sharedscripts により、ワイルドカードにマッチするファイルが何件あっても postrotate は1回だけ実行されます。モジュールを追加するたびに設定を変更しなくて済むため、運用負荷が下がります。

複数のログファイルパスを一つの設定にまとめる

ワイルドカードでは対象にしにくい複数のログファイルを、同じポリシーで管理したい場合があります。そのようなときは、スペース区切りで複数のパスを1つのブロックに書けます。

# スペース区切りで複数のパスを1つのブロックにまとめる例 /var/log/myapp/error.log /var/log/myapp/access.log { daily rotate 14 compress missingok notifempty }

同じ設定を共有するログが複数あるときや、異なるディレクトリのログをまとめて同一ポリシーで管理したいときに役立ちます。ワイルドカードより厳密にファイルを指定できるため、意図しないファイルを巻き込むリスクもありません。

firstaction / lastactionでローテーション前後に一度だけ処理する

postrotate はファイルごとに実行されますが(sharedscripts を付けた場合は1回)、lastaction はすべてのファイルのローテーション完了後に必ず1回だけ実行されます。ローテーション結果のログ記録や外部通知処理に使います。

/var/log/myapp/*.log { daily rotate 7 compress missingok notifempty sharedscripts lastaction echo "$(date): logrotate completed" >> /var/log/logrotate-history.log endscript }

firstaction ~ endscript:ローテーション開始前に1回だけ実行する
lastaction ~ endscript:すべてのファイルのローテーション完了後に1回だけ実行する

prerotate / postrotate と組み合わせることもできます。実行順序は「firstaction → prerotate →(ローテーション)→ postrotate → lastaction」の順です。複数モジュールのログを一括ローテーションした後にまとめて通知したい場合などに重宝します。

トラブルシュート・エラー対処

「error: skipping」が出た時の対処法

logrotateを実行した際に以下のようなエラーが出ることがあります。

error: skipping "/var/log/myapp/app.log" because parent directory has insecure permissions

これは、ログファイルの親ディレクトリのパーミッション(アクセス権限)が安全でないとlogrotateが判断した場合に発生します。

対処法1:ディレクトリの権限を修正する

# 親ディレクトリの権限を確認 [root@web01 ~]# ls -ld /var/log/myapp/ # 権限を修正(他ユーザーの書き込みを禁止) [root@web01 ~]# chmod 755 /var/log/myapp/

対処法2:su ディレクティブで実行ユーザーを指定する

アプリケーション専用のディレクトリで、あえてroot以外の権限にしている場合は、設定ファイルにsuディレクティブを追加します。

# suディレクティブで実行ユーザーとグループを指定 /var/log/myapp/*.log { su myapp myapp daily rotate 7 compress missingok notifempty }

suディレクティブを追加すると、logrotateがそのユーザー権限でローテーションを実行するため、パーミッションエラーが解消されます。

「error: Ignoring ... because it is writable by group」が表示された場合

/etc/logrotate.d/ 配下に置いた設定ファイル自体のパーミッションが原因のエラーです。グループや他ユーザーへの書き込み権限があると、logrotateはセキュリティ上の理由でその設定ファイルを無視します。

# エラーメッセージの例 error: Ignoring /etc/logrotate.d/myapp because it is writable by group or world. # 設定ファイルの権限を確認する [root@web01 ~]# ls -la /etc/logrotate.d/myapp -rw-rw-r-- 1 myapp myapp 120 Apr 11 10:00 /etc/logrotate.d/myapp # 644 (root:root) に修正する [root@web01 ~]# chmod 644 /etc/logrotate.d/myapp [root@web01 ~]# chown root:root /etc/logrotate.d/myapp # 確認する [root@web01 ~]# ls -la /etc/logrotate.d/myapp -rw-r--r-- 1 root root 120 Apr 11 10:05 /etc/logrotate.d/myapp

設定ファイルを手動で作成すると、root以外のユーザーが所有者になっていたり、エディタによってグループ書き込みが付いたりすることがあります。新しい設定ファイルを追加したら、必ずパーミッションを確認してください。

「error: skipping - log entry is not a file」が表示された場合

指定したパスがファイルではない(ディレクトリやシンボリックリンクの場合など)ときに発生します。

[root@web01 ~]# logrotate -d /etc/logrotate.d/myapp error: skipping "/var/log/myapp/app.log" because it is not a regular file. # ファイルの種類を確認する [root@web01 ~]# file /var/log/myapp/app.log /var/log/myapp/app.log: symbolic link to /dev/null # 正しいログファイルのパスを確認して設定を修正する

Permission deniedエラーが出た場合

root権限でlogrotateを実行しているにもかかわらず Permission denied が出るケースがあります。

error: error opening /var/log/myapp/app.log: Permission denied

ディレクトリや設定ファイル自体のパーミッションが原因であることがほとんどです。su ディレクティブで実行ユーザーを指定すると解決するケースが多いです。

SELinuxが有効な環境ではコンテキストの不一致が原因になることもあります。

# SELinuxの拒否ログを確認する [root@web01 ~]# ausearch -m avc -ts recent | grep logrotate # SELinuxの状態を確認する [root@web01 ~]# getenforce Enforcing

SELinuxによるブロックが原因の場合は、対象ディレクトリのコンテキストを確認・修正するか、audit2allowでポリシーを追加してください。

ローテーション後にアプリケーションがログを書き込めなくなった場合

createディレクティブのパーミッションやオーナーが正しいか確認してください。

# ローテーション後のファイルのパーミッションを確認する [root@web01 ~]# ls -la /var/log/myapp/ -rw-r----- 1 root root 0 Apr 11 03:00 app.log -rw-r----- 1 myapp myapp 245760 Apr 11 03:00 app.log-20260411 # create行のオーナーが間違っている場合 # create 0640 root root ← rootで作成されているためmyappユーザーが書き込めない # create 0640 myapp myapp ← 正しい設定

createのオーナーは、アプリケーションの実行ユーザーに合わせてください。Nginxなら nginx、Apacheなら apache(またはwww-data)です。

ローテーション後もアプリが古いファイルにログを書き続けている場合(postrotateのシグナル送信が失敗している等)は、lsofで確認できます。

# ローテーション済みファイルを開いているプロセスを確認する [root@web01 ~]# lsof | grep deleted nginx 1234 nginx 4w REG 253,1 102400 12345 /var/log/nginx/access.log-20260410 (deleted) # または特定のファイルを指定して確認する [root@web01 ~]# lsof /var/log/nginx/access.log-20260410 # 対処:postrotateでUSR1シグナルを送りnginxにログを再オープンさせる postrotate /bin/kill -USR1 $(cat /run/nginx.pid 2>/dev/null) 2>/dev/null || true endscript

(deleted) と表示されているプロセスが残っている間は、そのプロセスが古いファイルに書き続けています。postrotateを見直してシグナルを正しく送れているか確認してください。

ログがローテーションされない時の確認手順

「設定したのにログがローテーションされない」場合は、以下の手順で原因を切り分けてください。

手順1:ステータスファイルを確認する

logrotateは前回の実行日時を /var/lib/logrotate/logrotate.status(ディストリビューションによっては /var/lib/logrotate.status)に記録しています。

# ステータスファイルで前回の実行日時を確認 [root@web01 ~]# cat /var/lib/logrotate/logrotate.status | grep myapp

前回の実行日時が記録されていない場合は、設定ファイルがlogrotateに認識されていない可能性があります。すでに「今日実行済み」になっている場合は、-f オプションで強制実行するか、ステータスファイルの該当行を削除してからlogrotateを実行してください。

手順2:デバッグモードで設定を検証する

# 設定ファイルの構文エラーを確認 [root@web01 ~]# logrotate -d /etc/logrotate.d/myapp

「error:」で始まる行がないかチェックしてください。

手順3:cronまたはsystemdタイマーが動いているか確認する

# 1. cronデーモンが動いているか確認する [root@web01 ~]# systemctl status crond Active: active (running) # 2. cronのログでlogrotateが実際に呼ばれているか確認する(RHEL系) [root@web01 ~]# grep logrotate /var/log/cron Jun 21 03:00:01 web01 CROND[12345]: (root) CMD (run-parts /etc/cron.daily) # Ubuntu系の場合はjournalctlで確認する [root@web01 ~]# journalctl -u cron | grep logrotate # 3. /etc/cron.daily/logrotate が存在するか確認する [root@web01 ~]# ls -la /etc/cron.daily/logrotate -rwx------. 1 root root 130 Apr 1 2026 /etc/cron.daily/logrotate # 4. 実行権限があるか確認する(xがないと実行されない) [root@web01 ~]# chmod +x /etc/cron.daily/logrotate # systemdタイマーの場合 [root@web01 ~]# systemctl status logrotate.timer [root@web01 ~]# systemctl list-timers | grep logrotate

cronが動いていても/etc/cron.daily/logrotateの実行権限が外れていると、logrotateは一切実行されません。パッケージ更新後に権限が変わることがあるので注意してください。

logrotate.timerが inactive になっていたり、/etc/cron.daily/logrotate が存在しない場合は、logrotate自体が定期実行されていません。

手順4:ディスク容量を確認する

ディスクが100%の状態では、ローテーション(新しいファイルの作成や圧縮)が失敗します。

# ディスク使用量を確認 [root@web01 ~]# df -h /var/log/

ディスクが逼迫している場合は、まず不要なファイルを削除してからlogrotateを実行してください。

手順5:手動で実行してエラーが出ないか確認する

# 手動で実行してエラーが出ないか確認する [root@web01 ~]# /usr/sbin/logrotate -s /var/lib/logrotate/logrotate.status /etc/logrotate.conf

compress / delaycompressの世代数がわかりにくい場合

rotate の数値は「圧縮ファイルを含むバックアップ世代数の上限」です。delaycompress を使っている場合、最新1世代は非圧縮のまま残り、それ以降が圧縮されます。「世代数を設定したのにファイルが想定より多い」と感じるのは、現在書き込み中のログ(世代数の外)も含めて数えているためです。

# rotate 7 + daily + compress + delaycompress 設定時のファイル例 /var/log/httpd/access_log ← 現在のログ(書き込み中・世代数の外) /var/log/httpd/access_log.1 ← 1世代前(非圧縮・delaycompress対象) /var/log/httpd/access_log.2.gz ← 2世代前(gzip圧縮済み) /var/log/httpd/access_log.3.gz ← 3世代前(gzip圧縮済み) /var/log/httpd/access_log.4.gz ← 4世代前(gzip圧縮済み) /var/log/httpd/access_log.5.gz ← 5世代前(gzip圧縮済み) /var/log/httpd/access_log.6.gz ← 6世代前(gzip圧縮済み) /var/log/httpd/access_log.7.gz ← 7世代前(次回ローテーションで削除)

rotate 7 の場合、バックアップは7個(.1 ~ .7)。現在のログを含めると計8ファイルが存在する状態が正常です。世代数が想定と違う場合は、この関係を念頭に置いて確認してください。

「logrotate: ALERT exited abnormally with [1]」がメールに届く場合

cronからlogrotateを実行したときに終了コードが1になると、/etc/cron.daily/logrotate の logger コマンドが「ALERT exited abnormally with [1]」とシステムログに記録し、それがcronのメール通知として管理者に届きます。

-v オプションで詳細を出力しながら手動実行すると、エラー箇所が特定できます。

# 詳細出力でエラー箇所を特定する [root@web01 ~]# logrotate -v /etc/logrotate.conf 2>&1 | grep -E "(error|warning|ALERT)" # 特定の設定ファイルを絞って確認する [root@web01 ~]# logrotate -v /etc/logrotate.d/myapp 2>&1 # よくある原因: # 1. missingok が抜けていてログファイルが存在しない # 2. postrotate スクリプトの終了コードが0でない(|| true が抜けている) # 3. create で指定したユーザー・グループが存在しない # 4. /etc/logrotate.d/ 配下の設定ファイルのパーミッションがグループ書き込み可能

postrotateの末尾に || true を忘れると、シグナル送信が失敗したとき(サービスが停止中など)に終了コード1が返り、毎日ALERTメールが届き続けます。|| true を付けておくと、シグナル送信に失敗してもローテーション自体は成功扱いになります。

postrotate内で systemctl 等のコマンドを絶対パスで指定していない場合、cronの環境(PATH が最小限)ではコマンドが見つからずにエラーになることもあります。which systemctl で絶対パスを確認し、/usr/bin/systemctl reload サービス名 のように書くと確実です。

本記事のまとめ

logrotateの設定方法とトラブル対処のポイントを整理します。
やりたいことコマンド・設定
デフォルト設定を確認するcat /etc/logrotate.conf
個別設定ファイルの一覧を確認するls /etc/logrotate.d/
設定をテストする(実行しない)logrotate -d /etc/logrotate.d/設定名
強制的にローテーションを実行するlogrotate -f /etc/logrotate.d/設定名
詳細表示で強制ローテーションするlogrotate -vf /etc/logrotate.d/設定名
前回の実行日時を確認するcat /var/lib/logrotate/logrotate.status
ローテーション記録をリセットするステータスファイルの該当行を削除または -f で強制実行
ファイル名に日付を付けるdateext + dateformat -%Y%m%d
サイズベースでローテーションするsize 100M
古いログを日数指定で削除するmaxage 30
ローテーション後のファイルを別ディレクトリに移動するolddir /var/log/myapp/archive
複数パスを一つの設定ブロックにまとめるスペース区切りでパスを並べる
ローテーション完了後に一度だけ処理するlastaction ~ endscript で設定
systemdタイマーの状態を確認するsystemctl status logrotate.timer
次回実行時刻を確認するsystemctl list-timers | grep logrotate
cronのログでlogrotateの実行を確認するgrep logrotate /var/log/cron
ローテーション後にサービスを再読み込みするpostrotate ~ endscript で設定
アプリ側の対応なしでローテーションするcopytruncate ディレクティブで設定
圧縮形式をbzip2/xzに変更するcompresscmd /usr/bin/bzip2 + compressext .bz2
複数ファイルをまとめて管理するワイルドカード + sharedscripts
パーミッションエラーを回避するsu ユーザー グループ ディレクティブで設定
設定ファイル自体のパーミッションを修正するchmod 644 /etc/logrotate.d/設定名
ALERTメールのエラー箇所を特定するlogrotate -v /etc/logrotate.conf 2>&1 | grep error

logrotateは「設定して放置」で動くツールですが、設定ミスに気づかないまま放置すると、ディスク満杯による障害を引き起こします。
新しいアプリケーションを導入したら /etc/logrotate.d/ に設定を追加し、logrotate -d で動作確認するところまでをセットにしてください。

関連するログ管理の記事も参考にしてください。

crontabコマンドの設定と書き方|動かない時のログ確認まで
dfコマンドでディスクの空き容量を確認する方法

ログが溢れて深夜に叩き起こされた経験はありませんか?

logrotateの設定を覚えても、「本番サーバーの運用設計をどう組み立てるか」は断片的な情報だけでは身につきません。現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、『Linuxサーバー構築入門マニュアル(図解60P)』を完全無料でプレゼントしています。

「独学の時間がもったいない」「プロから直接、現場の技術を最短で学びたい」という本気の方には、2日で実務レベルのスキルが身につく【初心者向けハンズオンセミナー】も開催しています。

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は1分、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

登録10秒/合わなければ解除3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。