【Linux】logrotate 設定ファイルの書き方と動作確認まとめ|ディレクティブ一覧・デバッグ実行・実務例を徹底解説

コマンドリファレンス実務レシピ

Linuxサーバーを運用する上で、避けて通れないトラブルの一つが「ログファイルの肥大化によるディスク容量枯渇(Disk Full)」です。Webサーバー(Nginx / Apache)や自作のWebアプリケーション(Python, Node.js, Go等)、バッチ処理のログを放置すると、数週間〜数ヶ月でディスクを圧迫し、最悪の場合はOSやデータベースがクラッシュしてサービス停止に追い込まれます。

この問題を自動で解決する標準ツールが「logrotate(ログローテート)」です。logrotateを正しく設定すれば、ログを日次や週次で新しいファイルに切り替え(ローテーション)、過去ログを自動圧縮(gzip)し、指定した世代数(例: 14世代、30世代)を超えた古いログを安全に自動削除してくれます。

しかし、いざ /etc/logrotate.d/ に設定ファイルを書こうとすると、copytruncatecreate + postrotate はどちらを使うべき?」「設定したのにローテーションされない」「テスト実行はどうやるの?」といった疑問やトラブルに直面しがちです。

この記事では、logrotate 設定ファイルの書き方、主要ディレクティブの意味と一覧、Nginxや自作アプリ向けの実践設定例、logrotate -d(ドライラン)や logrotate -f(強制実行)による動作確認手順、パーミッションエラー等のトラブルシューティングまで、実務で即コピペして使える形で徹底解説します。

  1. 【早見表】logrotate 設定ディレクティブ & 管理コマンド チートシート
    1. 主要ディレクティブ早見表
    2. 管理・テストコマンド早見表
  2. 1. logrotate の基本構造と動作の仕組み
    1. 設定ファイルの配置構成
    2. 誰が logrotate を実行しているのか?(cron vs systemd timer)
    3. 実行履歴を記録するステータスファイル
  3. 2. 設定ファイル(/etc/logrotate.d/)の書き方と主要ディレクティブ一覧
    1. 【1】ローテーション周期と保持世代数
    2. 【2】圧縮とファイル命名規則
    3. 【3】例外制御・ファイル生成・実行権限
    4. 【4】スクリプト実行とプロセス通知(シグナル制御)
  4. 3. どちらを使う?「copytruncate」vs「create + postrotate」徹底比較
    1. なぜこの2つの方式があるのか?(Linuxのファイルハンドル問題)
    2. どちらを選ぶべきかの判断基準チャート
  5. 4. 【実践例】コピペで使える logrotate 設定ファイル集
    1. 実践例1:Nginx / Webサーバー向け(標準的なシグナル方式)
    2. 実践例2:自作Webアプリケーション(Python / Node.js / Go / Rails)向け
    3. 実践例3:Docker コンテナログ(json-log)向け
    4. 実践例4:過去ログを専用の保管ディレクトリ(olddir)に退避する設定
  6. 5. logrotate の動作確認・デバッグ・強制テスト手順
    1. Step 1:ドライラン(-d / –debug)で設定構文と判定をチェック
    2. Step 2:強制実行(-f)と詳細出力(-v)で実テスト
    3. Step 3:ステータス管理ファイル(/var/lib/logrotate/status)の確認
    4. Step 4:systemd timer の動作状況確認
  7. 6. 実務でよくあるエラーとアンチパターン解決チェックリスト
    1. 設定ファイルのパーミッションに関する注意点
  8. まとめ & 関連リファレンス
    1. 関連記事
  9. 関連記事

【早見表】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.timerlogrotate.service を毎日定期的にキックします(通常は午前0時〜早朝)。
    systemctl status logrotate.timer で次回実行時刻を確認できます。
  • cron.daily(従来の環境):
    /etc/cron.daily/logrotate シェルスクリプトが anacroncron 経由で日次実行されます。
# 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.1
2. create で新しい空 app.log 作成
3. kill -USR1 <pid> でアプリに再オープン指示
ログの欠落が一切ない(0%)。
ファイル移動のみで高速。
アプリケーション側がシグナルによるログ再オープン(USR1HUP)に対応している必要がある。
copytruncate
(コピー&切り詰め方式)
1. cp app.log app.log.1
2. 元の 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.logerror.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 755750 に修正。
2. 設定ファイル内に su <user> <group> を追記する。
設定ファイルを作成したのに無視される(実行されない) 設定ファイル名にドット(.bak, .old, .conf)やチルダ(~)が含まれている。 logrotate の include 処理は .rpmorig, .dpkg-old, .bak 等を自動無視します。ファイル名は myapp のように拡張子なしにするのが安全です。
ローテーション後にログが一切出力されなくなった(サイズ0のまま) create 方式を採用しているのに、postrotate でアプリに再オープンシグナル(USR1 等)を送っていない。 1. アプリがシグナル対応なら postrotatekill -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 である必要があります。他ユーザーへの書き込み権限(06660777)が付いていると、セキュリティ保護のため 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>(強制テスト)で動作を確認する。

ログの保持期間設計やディスク監視の自動化についてさらに深く学びたい方は、以下の関連ガイドもあわせてご活用ください。

関連記事

Bash玄

はじめまして!Bash玄です。

エンジニアとしてシステム運用に携わる中で、手作業の多さに限界を感じ、Bashスクリプトを活用して業務を効率化したのがきっかけで、この道に入りました。「手作業は負け」「スクリプトはシンプルに」をモットーに、誰でも実践できるBashスクリプトの書き方を発信しています。

このサイトでは、Bashの基礎から実践的なスクリプト作成まで、初心者でもわかりやすく解説しています。少しでも「Bashって便利だな」と思ってもらえたら嬉しいです!

# 好きなこと
- シンプルなコードを書くこと
- コマンドラインを快適にカスタマイズすること
- 自動化で時間を生み出すこと

# このサイトを読んでほしい人
- Bashに興味があるけど、何から始めればいいかわからない人
- 定型業務を自動化したい人
- 効率よくターミナルを使いこなしたい人

Bashの世界に一歩踏み出して、一緒に「Bash道」を極めていきましょう!

Bash玄をフォローする

コメント