Raspberry Pi 4B でルータのログ受信サーバを作る

目的

  • ルータの Syslog を Raspberry Pi で受信する
  • 受信したログを長期保存できるようにする
  • SD カードへの書き込みを減らすため、受信直後のログは RAM ディスク上へ置く
  • Raspberry Pi OS の Overlay File System を使って root を読み取り専用寄りで運用する
  • 一定サイズを超えたら毎時ローテートし、圧縮して外部ストレージへ退避する

前提

  • Raspberry Pi 4B
  • Raspberry Pi OS Bookworm 系
  • ルータが Syslog の UDP 送信に対応している
  • Raspberry Pi は LAN 内で固定 IP にしておく
  • 長期保存用に USB SSD、USB メモリ、または別パーティションを使えること

固定 IP は Raspberry Pi 側でベタ固定するより、ルータ側の DHCP 予約で固定化しておくほうが運用しやすい。

Overlay 前提の構成

Overlay File System を使う場合、root 配下への書き込みは RAM 上の一時変更になる。
そのため、圧縮済みログの保存先を root ファイルシステム上の普通のディレクトリに置くと、再起動で消える。

今回の構成は以下。

  • 一時ログ: /var/log/router-ram/router.log
  • 長期保存先: /var/log/router-archive/ にマウントした外部ストレージ
  • 受信デーモン: rsyslog
  • ローテート: logrotate
  • 実行タイミング: cron で毎時
  • root: Overlay File System を最後に有効化

構築の順番

Overlay File System を使うなら、最初に overlay を有効化してはいけない。

順番は以下で進める。

  1. 長期保存先の外部ストレージを用意して /var/log/router-archive へマウントする
  2. rsyslogcron など必要パッケージを入れる
  3. /var/log/router-ram を作って tmpfs でマウントする
  4. rsyslog の受信設定を入れる
  5. logrotatecron を設定する
  6. 受信とローテートを手動で確認する
  7. 最後に Overlay File System を有効化して再起動する

overlay 有効後に /etc へ加えた変更は再起動で消える。
そのため、パッケージ導入、fstabrsyslogcron の設定は全部 overlay を有効化する前に終わらせる。

長期保存先の外部ストレージを先に用意する

この記事では、USB ストレージを /var/log/router-archive にマウントする例にする。

接続されているデバイス確認:

lsblk -f

新規に使うストレージで中身を消してよい場合だけ、ext4 で初期化する。

sudo mkfs.ext4 -L ROUTERLOG /dev/sda1

/dev/sda1 は実際のデバイス名に読み替える。
このコマンドは中身を消すので、既存データがあるデバイスには実行しない。

マウントポイント作成:

sudo mkdir -p /var/log/router-archive

UUID を確認:

sudo blkid /dev/sda1

/etc/fstab に外部ストレージのマウント設定を追加する。

UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx /var/log/router-archive ext4 defaults,noatime,nofail 0 2

反映:

sudo mount -a
findmnt /var/log/router-archive
df -h /var/log/router-archive

nofail を付けておくと、外部ストレージが刺さっていない時でも Raspberry Pi 自体は起動できる。

パッケージを入れる

初期インストール直後は systemd-journald だけが動いていて、rsyslog が入っていないことがある。
先に状態を確認する。

systemctl status systemd-journald --no-pager
dpkg -l rsyslog

dpkg -l rsyslogno packages foundun が出る場合は、rsyslog を追加する。

Raspberry Pi OS は Debian ベースなので cron を使える。環境によっては既に動いているが、ここでは無ければ入る前提で進める。

sudo apt update
sudo apt install -y rsyslog logrotate cron
sudo systemctl enable --now rsyslog
sudo systemctl enable --now cron
sudo systemctl status rsyslog --no-pager
sudo systemctl status cron --no-pager

journald はそのまま残して問題ない。
この手順では、ローカルのシステムログは journald が持ちつつ、ルータから飛んでくるリモート Syslog を rsyslog で受ける。

RAM ディスクを作る

この作業は rsyslog の受信設定を入れる前に実施する。
受信開始前に tmpfs を作っておくことで、最初の書き込み先を RAM 側へ寄せられる。

まずは一時ログ用ディレクトリを作る。

sudo mkdir -p /var/log/router-ram

/etc/fstabtmpfs のマウント設定を追加する。

tmpfs /var/log/router-ram tmpfs defaults,noatime,size=128M,mode=0755,nosuid,nodev,noexec 0 0

反映:

sudo mount -a
df -h /var/log/router-ram

size=128M は目安。ルータの出力量が多いなら 256M 以上へ増やす。

rsyslog で UDP 受信する

/etc/rsyslog.d/30-router-udp.conf を作る。

ファイル名の先頭に付けた 30 は、/etc/rsyslog.d/ 配下での読み込み順を意識した番号。
rsyslog はこのディレクトリ内の設定ファイルをファイル名順で読むため、番号を付けておくと後から見た時に順番を把握しやすい。
今回はローカルの独自設定として、早すぎず遅すぎない位置に置く意図で 30 にしている。

module(load="imudp")

template(name="RouterLogFormat" type="string"
  string="%timegenerated:::date-rfc3339% %fromhost-ip% %syslogtag%%msg%\n"
)

ruleset(name="router_from_udp") {
  if ($fromhost-ip == "192.168.1.1") then {
    action(
      type="omfile"
      file="/var/log/router-ram/router.log"
      template="RouterLogFormat"
      fileCreateMode="0640"
      dirCreateMode="0755"
    )
  }
}

input(type="imudp" port="514" ruleset="router_from_udp")

192.168.1.1 はルータの IP に置き換える。

この設定だと、UDP/514 で受けたメッセージのうち、指定したルータ IP から来たものだけを RAM ディスク上の router.log に書く。

設定チェックと反映:

sudo rsyslogd -N1
sudo systemctl restart rsyslog
sudo ss -ulpn | grep ':514'

logrotate の設定を入れる

tmpfs と長期保存先は別ファイルシステムになる。
そのため olddir で外部ストレージ側へ逃がす場合は copytruncate を使う。

/etc/logrotate.d/router-ram を作る。

/var/log/router-ram/router.log {
    hourly
    minsize 10M
    rotate 720
    missingok
    notifempty
    compress
    delaycompress
    dateext
    dateformat -%Y%m%d-%H%M%S
    datehourago
    olddir /var/log/router-archive
    copytruncate
}

設定の意味は以下。

  • hourly: 毎時判定する
  • minsize 10M: 10MB 未満なら回さない
  • compress: 圧縮して保存する
  • olddir: 圧縮済みログを外部ストレージ側へ置く
  • copytruncate: rsyslog が開いたままのファイルを残したままローテートする
  • rotate 720: 最大 720 世代まで残す

保存期間は rotate の値で調整する。毎時必ず回るわけではなく、minsize を超えたときだけ世代が増える。

cron で毎時 logrotate する

hourly 指定だけでは足りず、logrotate 自体を毎時起動する必要がある。

Overlay File System を有効化すると、/var/lib も再起動で元に戻る。
そのため logrotate の状態ファイルも外部ストレージ側へ置く。

/etc/cron.d/router-logrotate を作る。

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

0 * * * * root /usr/sbin/logrotate -s /var/log/router-archive/logrotate.status /etc/logrotate.d/router-ram

権限を整えて、cron を読み直させる。

sudo chmod 644 /etc/cron.d/router-logrotate
sudo systemctl restart cron
sudo systemctl status cron --no-pager

毎時ちょうどに回したいので、ここでは @hourly ではなく 0 * * * * を使っている。

ルータ側の設定

ルータ側では Syslog の送信先を Raspberry Pi に向ける。

  • 送信先 IP: Raspberry Pi の固定 IP
  • プロトコル: UDP
  • ポート: 514

ファイアウォールを使っているなら、LAN 内のルータから UDP/514 を通す。

動作確認

まず、外部ストレージが正しくマウントされていることを確認する。

findmnt /var/log/router-archive

受信できているか確認する。

sudo tail -f /var/log/router-ram/router.log

ルータ側で Syslog 送信を有効化して、ログが流れてくれば受信成功。

次にローテート確認:

sudo ls -lh /var/log/router-archive

cron に登録された内容を確認したい場合:

sudo cat /etc/cron.d/router-logrotate

サイズ条件を無視して試験したい場合は -f で強制実行する。

sudo /usr/sbin/logrotate -f -s /var/log/router-archive/logrotate.status /etc/logrotate.d/router-ram

Overlay File System を最後に有効化する

ここまで問題なければ、最後に Overlay File System を有効化する。

sudo raspi-config

メニュー:

  1. 4 Performance Options
  2. P2 Overlay File System
  3. Would you like the overlay file system to be enabled?Yes
  4. Would you like the boot partition to be write-protected? は通常は No

この用途では、まず root の overlay だけ有効にして、/boot は書き込み可能のまま残すほうが保守しやすい。

設定後に再起動:

sudo reboot

再起動後の確認:

findmnt /
findmnt /var/log/router-archive
sudo systemctl status rsyslog --no-pager
sudo systemctl status cron --no-pager

運用メモ

  • Raspberry Pi が再起動した時点で、RAM ディスク上の未退避ログは消える
  • overlay 有効後に /etc/var/lib に加えた変更は再起動で消える
  • 設定変更や apt upgrade をしたい時は、一度 Overlay File System を無効化して再起動し、作業後に再度有効化する
  • ログ量が多い環境では tmpfs サイズと minsize を大きめにする
  • 長期保存先は USB SSD のほうが安定しやすい
  • この手順は「ルータのリモート Syslog 保存」に絞っているので、Pi 自身のローカルログ最適化までは含めていない

参考