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 を有効化してはいけない。
順番は以下で進める。
- 長期保存先の外部ストレージを用意して
/var/log/router-archiveへマウントする rsyslogとcronなど必要パッケージを入れる/var/log/router-ramを作ってtmpfsでマウントするrsyslogの受信設定を入れるlogrotateとcronを設定する- 受信とローテートを手動で確認する
- 最後に
Overlay File Systemを有効化して再起動する
overlay 有効後に /etc へ加えた変更は再起動で消える。
そのため、パッケージ導入、fstab、rsyslog、cron の設定は全部 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 rsyslog で no packages found や un が出る場合は、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/fstab に tmpfs のマウント設定を追加する。
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
メニュー:
4 Performance OptionsP2 Overlay File SystemWould you like the overlay file system to be enabled?にYesWould 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 自身のローカルログ最適化までは含めていない