自宅サーバーのアクセスとファイル変更を監視するPHPモニターを作った話

少し前の記事「8インチタブレットで擬似的にFold7を再現してみる」で8インチタブレットの画面を分割して、画面の上1/3をBlack Screenで黒くする設定にしていたのですが、ただの黒い画面ではもったいない気がして、端末のステータスを表示するダッシュボード的なアプリを表示しようと考えました。

いろいろアプリを探したのですが、これだというアプリを見つけることができず、途中で自宅サーバーの状況を表示するアプリはないかと探し始めました。

探しているうちに一つ、SSH接続でサーバーに接続して、情報を拾って表示できるアプリ「Server Glance」を見つけて表示してみたところ、まあまあいい感じになりました。

で、CPUやRAMの使用率を見るには十分だったのですが、どうせならアクセスログなども見れたらいいなと思い始めて、だったら自分のサーバー環境に合わせて、PHPだけで動く簡単な監視ページを作ったらいいのでは、という結論に至りました。

何年か前にWordpressへの攻撃を受けて、知らない間にファイルを置かれた経験があったので、リアルタイムに近い形でログをみることができて、なんなら.env、.git、wp-config.php、xmlrpc.php、phpmyadminなどを探しているようなアクセスや、存在しないPHPファイルを次々に試しているアクセスなどを「要注意アクセス」として抽出できたらいいかもと思い、その方向で監視用のWebページを作り始めました。さらに、アクセスログだけではなく、WordPressのファイル変更も検出できるようにしました。

最終的には、アクセス状況とファイル変更を一つの画面から確認できる、自宅サーバー用の簡易監視モニターになりました。

今回は、少しずつ機能を追加・修正しながら、最終的にどのような監視画面になったのかをまとめておきます。

なお、この記事ではドメイン名は site1.example.com、site2.example.com などに、サーバー上のディレクトリは /home/web/html/site1、/home/web/html/site2 などに匿名化しています。匿名化されている箇所は、自分の環境に合わせて書き換える必要があります。


どんなモニターを作ったか

作成したのは、Apacheのアクセスログを読み込んで表示するシンプルなPHPページです。

主な機能は次のとおりです。

  • 本日のアクセス数を表示
  • 要注意アクセス数を表示
  • 404の件数を表示
  • 本日のBAN件数を表示
  • 最終更新時刻を表示
  • 24時間のアクセスグラフを表示
  • 最新100件のアクセスログを表示
  • 直近100件の要注意アクセスログを抽出して表示
  • ログのリストにはHTTP Methodを表示
  • HTTPステータスコードも表示
  • どのドメインへのアクセスか表示
  • 直近100件のBANしたIPと時刻、BAN理由を一覧で表示
  • WordPressのファイル変更を監視
  • ファイルの新規作成・削除を検出
  • 5分ごとに自動更新
  • 選択中のタブを保持
  • ログイン認証を追加
  • 一度ログインすると30日間ログイン状態を保持

監視ページそのものは、サーバーに新しい監視用ソフトウェアをインストールするのではなく、PHPと既存のApacheログだけで動作する構成にしました。

1.まずはアクセスログを見るための画面

最初に作ったのは、ApacheのアクセスログをPHPで読み込んで表示するだけの画面です。

監視対象のログは、実際の環境ではApacheのログファイルですが、この記事ではサーバー固有のパスは伏せていますが、イメージとしてはこんな感じです。

/var/log/httpd/access_log
/var/log/httpd/ssl_access_log

PHPでは、この2つのログを読み込みます。

$logFiles = [
    '/var/log/httpd/access_log',
    '/var/log/httpd/ssl_access_log'
];

アクセスログには、例えば次のような記録があります。

2026/09/27 20:42:48 site1.example.com 192.0.2.10 PROPFIND /remote.php/dav/files/example/ 207
2026/09/27 20:45:17 site1.example.com 198.51.100.20 GET /flamini.php 404

PHP側では正規表現を使って、

  • 日時
  • ドメイン
  • IPアドレス
  • Method
  • アクセス先(サブドメインを含めて、どのサイトへのアクセスか)
  • HTTPステータス

に分解しています。

PHPの処理はこんな感じです。

if (
    !preg_match(
        '/^(\d{4}\/\d{2}\/\d{2}\s+\d{2}:\d{2}:\d{2})\s+' .
        '(\S+)\s+' .
        '(\S+)\s+' .
        '(\S+)\s+' .
        '(\S+)\s+' .
        '(\d{3})$/',
        $line,
        $m
    )
) {
    continue;
}

これで、ブラウザ上ではアクセスログを表形式で確認できるようになりました。

ただ、実際に使ってみると、この方法にはいくつか問題がありました。

複数のログファイルをPHP側で読み込む必要があり、監視対象のドメインが増えると、PHP側で扱うログも増えていきます。

また、ログの形式が統一されていない場合には、PHP側の処理も複雑になります。

そこで、PHP側で複数のApacheログを直接読むのではなく、Apache側で監視専用のログを一つ作り、それをPHPから読む構成に変更することにしました。


2.監視専用ログを作る

複数のApacheログをPHP側で直接読む方法でも、アクセスを表示すること自体はできます。

しかし、監視対象のドメインが増えたり、HTTPとHTTPSでログが分かれていたりすると、PHP側で複数のログファイルを読み込んで処理する必要があります。

そこで、PHP側の処理をシンプルにするため、Apache側で監視専用のアクセスログを一つ作ることにしました。

構成としては、次のようになります。

Apache
  │
  ├─ 通常のアクセスログ
  │
  └─ monitor_access_log
           │
           ▼
      PHP監視ページ

通常のアクセスログはこれまでどおり残しておきます。

そのうえで、監視ページで使用するログだけを別に作ります。

Apacheのログ形式を決める

まず、監視専用ログに記録する情報を決めます。

今回必要なのは、

  • 日時
  • ドメイン
  • IPアドレス
  • HTTP Method
  • アクセス先
  • HTTPステータス

の6項目です。

Apacheでは、LogFormatを使ってログの形式を指定できます。

今回使用した設定は次のとおりです。

LogFormat "%{%Y/%m/%d %H:%M:%S}t %v %a %m %U %>s" monitor_format

それぞれの指定には、次のような意味があります。

%{%Y/%m/%d %H:%M:%S}t  → 日時
%v                       → ドメイン名
%a                       → IPアドレス
%m                       → HTTP Method
%U                       → アクセス先
%>s                      → 最終的なHTTPステータスコード

この形式にしておくことで、ログ1行が、

日時 ドメイン IP Method アクセス先 ステータス

というシンプルな形になります。

例えば、

2026/09/27 20:45:17 site1.example.com 198.51.100.20 GET /flamini.php 404

という記録になります。

Apacheの設定ファイルに追加する

今回の環境では、ApacheのVirtualHost設定を記述している設定ファイルに、このログ形式を追加しました。

例えば、

/etc/httpd/conf.d/virtual.conf

です。

実際の環境では設定ファイルの場所やファイル名が異なる場合があります。

まず、LogFormatを設定ファイルに追加します。

LogFormat "%{%Y/%m/%d %H:%M:%S}t %v %a %m %U %>s" monitor_format

次に、監視対象のVirtualHostそれぞれにCustomLogを追加します。

例えば、site1.example.comを監視対象にする場合は、

CustomLog /var/log/httpd/monitor_access_log monitor_format

とします。

他の監視対象ドメインについても、同じCustomLogを追加します。

つまり、複数のVirtualHostがあっても、出力先はすべて同じです。

site1.example.com ─┐
site2.example.com ─┤
site3.example.com ─┼→ /var/log/httpd/monitor_access_log
site4.example.com ─┘

こうすることで、複数のサイトへのアクセスを一つのログにまとめることができます。

既存のCustomLogは削除しない

ここで注意したいのは、既存のCustomLogを置き換えるのではなく、監視用のCustomLogを追加するということです。

例えば、これまで、

CustomLog /var/log/httpd/access_log combined

となっていた場合でも、これはそのまま残します。

その下などに、

CustomLog /var/log/httpd/monitor_access_log monitor_format

を追加します。

これで、

通常のApacheログ
        ↓
access_logなど

監視用ログ
        ↓
monitor_access_log

という2系統になります。

通常のApacheログを残しておけば、既存のログ解析やトラブル調査にも影響しません。

Apacheの設定を確認する

設定を変更したら、いきなりApacheを再起動するのではなく、まず設定に問題がないか確認します。

apachectl configtest

問題がなければ、

Syntax OK

と表示されます。

問題がなければApacheをリロードします。

systemctl reload httpd

リロードなら、Apacheを完全に停止して起動し直す必要がありません。

監視専用ログが作成されたか確認する

Apacheをリロードしたら、監視専用ログが作成されているか確認します。

ls -l /var/log/httpd/monitor_access_log

ファイルが存在すれば、監視専用ログの準備は完了です。

実際にWebサイトへアクセスしたあと、

tail -n 20 /var/log/httpd/monitor_access_log

としてみます。

例えば、

2026/09/27 20:45:17 site1.example.com 198.51.100.20 GET /flamini.php 404

のような記録が出ていれば、Apache側で監視専用ログを正常に出力できています。

ここまでできれば、PHP側では複数のApacheログを読む必要がありません。

Apache
   │
   │ 監視対象のアクセスを集約
   ▼
monitor_access_log
   │
   ▼
PHP監視ページ

以降は、このmonitor_access_logだけをPHPから読み込んで、アクセス数や要注意アクセスなどを集計・表示していきます。


3.PHPから監視専用ログを読む

Apache側で監視専用ログを作ることができたので、次はこのログをPHPから読み込んで表示します。

今回作成する監視ページは、

/var/www/html/monitor/index.php

に置きました。

監視専用ログを指定する

PHPで読み込むログファイルを指定します。

$logFiles = [
    '/var/log/httpd/monitor_access_log'
];

今回は監視専用ログを一つにまとめているので、PHP側ではこの1ファイルだけを指定すれば済みます。

site1.example.comやsite2.example.comなど複数のドメインへのアクセスも、すべてこのログに記録されます。

そのため、PHP側でドメインごとにログファイルを指定する必要はありません。

ログを1行ずつ読み込む

ログファイルを開いて、1行ずつ読み込みます。

foreach ($logFiles as $logFile) {
    if (!file_exists($logFile)) {
        continue;
    }

    $lines = file($logFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);

    foreach ($lines as $line) {
        // ここでログ1行を処理する
    }
}

file()を使うと、ログファイルの内容を1行ずつ配列として取得できます。

例えば、

2026/09/27 20:45:17 site1.example.com 198.51.100.20 GET /flamini.php 404

という1行を取得したら、ここから必要な情報を取り出します。

正規表現でログを分解する

監視専用ログは、前章で設定した形式になっています。

日時 ドメイン IP Method アクセス先 ステータス

そこで、正規表現を使って6つの項目に分解します。

if (
    !preg_match(
        '/^(\d{4}\/\d{2}\/\d{2}\s+\d{2}:\d{2}:\d{2})\s+' .
        '(\S+)\s+' .
        '(\S+)\s+' .
        '(\S+)\s+' .
        '(\S+)\s+' .
        '(\d{3})$/',
        $line,
        $m
    )
) {
    continue;
}

Apacheのログ上では、

$m[1] → 日時
$m[2] → ドメイン
$m[3] → IPアドレス
$m[4] → HTTP Method
$m[5] → アクセス先
$m[6] → HTTPステータス

として取り出せます。

例えば、

2026/09/27 20:45:17 site1.example.com 198.51.100.20 GET /flamini.php 404

であれば、

$m[1] → 2026/09/27 20:45:17
$m[2] → site1.example.com
$m[3] → 198.51.100.20
$m[4] → GET
$m[5] → /flamini.php
$m[6] → 404

となります。

画面では見やすい順番にする

ログの記録形式と、画面に表示する順番は同じである必要はありません。

今回の監視画面では、最終的に次の順番で表示するようにしました。

日時 IPアドレス ステータス ドメイン アクセス先 Method

例えば、

2026/09/27 20:45:17 198.51.100.20 404 site1 /flamini.php GET

という表示になります。

Apacheのログにはsite1.example.comのような完全なドメイン名が記録されていますが、監視画面では一覧を見やすくするため、ドメイン名をsite1のような省略形で表示するようにしました。

つまり、

ログに記録される値
site1.example.com

↓

画面に表示する値
site1

という関係です。

ドメインそのものをログから削っているわけではないので、必要であれば元のドメイン情報を使って処理することもできます。

このように、Apacheでは必要な情報を記録し、PHP側で監視画面に適した表示形式へ変換する構成にしています。

この段階では、まだアクセスを「正常」「要注意」といった分類はしていません。

まずはApacheのログをPHPで読み込み、必要な情報を取り出してブラウザに表示できるところまでを確認します。

ここまでできれば、次はこの中から、.envや.git、wp-config.phpなどを探しているようなアクセスや、存在しないPHPファイルを試しているアクセスを**「要注意アクセス」として抽出する処理**を追加できます。


4.「要注意アクセス」を抽出する

アクセスログをブラウザで確認できるようになったので、次は大量に記録されるアクセスの中から、気になるものだけを見つけられるようにします。

Webサイトを公開していると、存在しないページへのアクセスや、WordPressなどでよく使われるファイルを探すようなアクセスが発生することがあります。

そこで、今回の監視ページでは、特定のパターンに該当するアクセスを「要注意アクセス」として抽出することにしました。

まずは特定のファイルやディレクトリを探すアクセス

例えば、次のようなパスへのアクセスです。

/.env
/.git/
/wp-config.php
/xmlrpc.php
/phpmyadmin/
/pma/
/adminer/
/server-status
/server-info
/.aws/
/.ssh/

これらは、Webサイトの設定ファイルや管理用ページ、認証情報などを探している可能性があります。

もちろん、これらのパスにアクセスされたからといって、必ず攻撃が成功しているわけではありません。

例えば、

GET /.env 404

であれば、.envというファイルを探しに来たものの、サーバーには存在しなかったということです。

そのため、今回の監視ページでは「攻撃された」と断定するのではなく、確認しておいた方がよいアクセスとして表示しています。

存在しないPHPファイルへのアクセスも確認する

もう一つ、実際のアクセスログを見ていて気になったのが、存在しないPHPファイルを次々に試しているようなアクセスです。

例えば、

GET /flamini.php 404
GET /wp-content/plugins/xxxx.php 404
GET /old.php 404

といったアクセスです。

もちろん、404のアクセスがすべて怪しいわけではありません。

URLの打ち間違いや、古いリンクが残っているだけの場合もあります。

しかし、短時間に存在しないPHPファイルへ繰り返しアクセスしている場合は、何らかのスキャンを行っている可能性があります。

そこで今回は、404で、かつアクセス先がPHPファイルになっているものも「要注意アクセス」として扱うことにしました。

404だから「要注意」というわけではない

ここは少し注意が必要です。

HTTPステータスが404だからといって、それだけで危険なアクセスとは判断していません。

例えば、

GET /favicon.ico 404

のようなアクセスは、単にそのファイルが存在しないだけかもしれません。

そのため、今回の判定では、

特定のパスへのアクセス

または、

404 + PHPファイルへのアクセス

といった条件を組み合わせています。

XML-RPCも確認対象にする

WordPressのxmlrpc.phpについては、少し扱いが異なります。

XML-RPCはWordPressが実際に利用する機能なので、xmlrpc.phpへのアクセスがあっただけで不正なアクセスとはいえません。

一方で、XML-RPCは攻撃やスキャンの対象になることもあるため、今回は監視画面で確認できるように「要注意アクセス」の対象にしました。

つまり、今回の「要注意」は、

危険なアクセスを断定するものではなく、ログを確認するきっかけになるアクセス

という位置付けです。

この判定処理をPHPに組み込むことで、通常のアクセスログをすべて確認しなくても、気になるアクセスだけを一覧で確認できるようになりました。

次は、通常のアクセスと要注意アクセスを同じ一覧に詰め込むのではなく、それぞれを分けて表示するようにします。


5.最新アクセスと要注意アクセスを分ける

要注意アクセスを抽出できるようになったので、次は通常のアクセスログと分けて表示することにしました。

すべてのアクセスを一つの一覧にしてしまうと、通常のアクセスに混ざって要注意アクセスが埋もれてしまいます。

そこで監視画面では、

  • 最新のアクセスログ
  • 要注意アクセス

を別々に表示するようにしました。

最新アクセスは100件に絞る

まず、通常のアクセスログについては、最新の100件だけを表示します。

アクセスログは時間が経つほど増えていくので、すべて読み込んで画面に表示すると、ログが多い環境では処理量も増えてしまいます。

そこで、PHPでログを読み込んだあと、表示する件数を100件に制限しました。

画面には、例えば次のような形で表示されます。

2026/09/27 20:45:17  198.51.100.20  404  site1  /flamini.php  GET
2026/09/27 20:44:51  203.0.113.15   200  site1  /           GET
2026/09/27 20:44:32  198.51.100.30  200  site2  /           GET

表示する項目は、

日時 IPアドレス ステータス ドメイン アクセス先 Method

です。

ドメインについては、実際のログには

site1.example.com

のように完全なドメイン名を記録していますが、画面上では

site1

のように短く表示しています。

一方、アクセス先については省略せず、

/flamini.php
/wp-login.php
/remote.php/dav/files/example/

のように、そのまま表示します。

これによって、一覧をコンパクトにしながら、どのURLにアクセスされたのかは確認できるようにしました。

要注意アクセスも100件に絞る

要注意アクセスについても、通常のアクセスとは別に直近100件を表示します。

例えば、

2026/09/27 20:45:17  198.51.100.20  404  site1  /flamini.php  GET
2026/09/27 20:43:02  203.0.113.45   404  site2  /.env          GET
2026/09/27 20:41:28  192.0.2.50     404  site1  /wp-config.php GET

といったアクセスが、要注意アクセスの一覧に入ります。

通常のアクセス一覧とは分けておくことで、普段どの程度アクセスがあるのかを見る画面と、「何か変なアクセスが来ていないか」を確認する画面を分けることができます。

404の件数も表示する

ここで、要注意アクセスとは別に、HTTPステータスコードが404だったアクセスの件数も集計して表示することにしました。

404は、要求されたページやファイルが見つからなかった場合に返されるステータスコードです。

例えば、

2026/09/27 20:45:17 site1.example.com 198.51.100.20 GET /flamini.php 404

というアクセスがあれば、通常のアクセスとしてカウントすると同時に、404の件数にも加算します。

監視画面では、こうした集計結果を、

今日のアクセス       1,284
要注意アクセス          17
404                     35
BAN                       3

のように表示します。

ここで重要なのは、404の件数と要注意アクセス数は別の数字だということです。

404は、存在しないURLへのアクセスであれば通常の閲覧でも発生します。

例えば、古いページへのリンクを開いた場合や、URLを間違えて入力した場合にも404になります。

そのため、404が発生したからといって、それだけで要注意アクセスとしているわけではありません。

一方で、存在しないPHPファイルを探しているようなアクセスや、.env、.git、wp-config.phpなどを探しているアクセスについては、4章で説明した条件に該当すれば要注意アクセスとして別に抽出します。

つまり、

404件数
 → 404が何件発生したか

要注意アクセス
 → 監視対象として確認したほうがよさそうなアクセスが何件あったか

という違いがあります。

404だけを単純に要注意にしない

ここで少し注意したのが、404をすべて要注意アクセスとして扱わないことです。

例えば、ユーザーが存在しないURLを入力した場合や、古いリンクを開いた場合にも404は発生します。

そのため、

404 = 攻撃

という判定にはしていません。

今回の監視では、アクセス先のパターンやMethod、ステータスコードなどを組み合わせて、監視対象として拾うようにしています。

例えば、存在しないPHPファイルを何度も探しているようなアクセスや、.env、.git、wp-config.phpなど、通常の閲覧ではあまりアクセスする必要のない場所を探しているアクセスは、要注意アクセスとして一覧に表示します。

なぜ「要注意」という名前にしたか

ここで表示している「要注意アクセス」は、PHPが「これは攻撃だ」と断定しているわけではありません。

あくまで、

「このアクセスは一度確認しておいたほうがよさそう」

というものを抽出しています。

例えば、WordPressのxmlrpc.phpは通常のWordPressでも使用されるファイルなので、アクセスがあっただけで不正アクセスとは判断できません。

一方で、同じIPアドレスから短時間に多数の存在しないPHPファイルを試していたり、.envや.gitなどを探していたりする場合には、ログを確認するきっかけになります。

そのため、画面上では「攻撃」「侵入」などと断定する表現ではなく、「要注意アクセス」として扱うことにしました。

最新100件と要注意100件を並べて見る

最終的には、監視画面の中で通常のアクセスと要注意アクセスを別々に確認できるようにしました。

これなら、普段のアクセス状況を確認しながら、同時に「何か変なアクセスが来ていないか」も確認できます。

また、後からBANしたIPアドレスの一覧も追加したため、

アクセス状況
 ↓
要注意アクセス
 ↓
BANされたIP

という流れで確認できるようになっていきました。

ここまででログを見るための基本的な画面ができたので、次は「数字だけではなく、アクセスが時間帯によってどのように変化しているのか」も分かるように、24時間のアクセス数をグラフで表示することにしました。


6.アクセス状況をグラフで見る

アクセスログを一覧で確認できるようになると、今度は「今日はどのくらいアクセスがあったのか」「どの時間帯にアクセスが集中しているのか」も、ひと目で分かるようにしたくなりました。

そこで、監視画面に24時間分のアクセス数をグラフで表示することにしました。

1時間単位でアクセス数を集計する

グラフは、本日のアクセスログを1時間単位で集計しています。

例えば、

00時  12件
01時  5件
02時  3件
03時  2件
04時  1件
05時  4件
06時  15件
07時  28件
...

というように、0時から現在までのアクセス数を時間ごとに数えます。

これなら、個々のアクセスログを一件ずつ確認しなくても、

  • 深夜にアクセスが多い
  • 朝から増えている
  • 特定の時間帯にアクセスが集中している
  • ほとんどアクセスがない

といった状況を視覚的に確認できます。

ログの日時を使って集計する

今回の監視専用ログでは、先頭に

2026/09/27 20:45:17

のような日時を記録しています。

PHPでは、この日時を読み取って「何時のアクセスなのか」を判定し、時間ごとの件数を加算していきます。

例えば20時45分のアクセスなら、

20時 → +1

として集計します。

同じ20時台にさらに10件のアクセスがあれば、

20時 → 11

となります。

この処理をログ全体について行うことで、24時間分のアクセス数を作ります。

現在時刻より未来の時間も0件で表示する

ここで少し工夫したのが、まだ到達していない時間帯もグラフの項目として用意しておくことです。

例えば現在が20時30分なら、

00  12
01   5
02   3
...
19  28
20  11
21   0
22   0
23   0

のように、21時以降も0件として扱います。

こうしておくことで、毎時間ごとにグラフの幅や項目数が変わることなく、常に0時から23時までの24時間を表示できます。

アクセス数をグラフで確認する

一覧表示だけの場合は、アクセスが増えたことをログの件数として確認することになります。

グラフを追加すると、

「いつアクセスが増えたのか」

という時間的な変化も分かるようになります。

特に、普段のアクセス数をある程度把握しておけば、突然アクセスが増えたときに気付きやすくなります。

ただし、アクセス数が増えたからといって、それだけで攻撃や異常が発生したとは限りません。

検索エンジンのクロールや通常の閲覧でもアクセス数は変化するため、グラフはあくまで全体の状況を把握するためのものとして使います。

数字とログを組み合わせる

ここまで作ると、監視画面の上部で、

今日のアクセス       1,284
要注意アクセス          17
404                     35
BAN                       3

のような全体の数字を確認し、その下で24時間のアクセス推移を確認できます。

さらに、その下に最新のアクセスログや要注意アクセスの一覧を表示すれば、

全体の数字
    ↓
時間ごとの変化
    ↓
個々のアクセスログ

という順番で確認できます。

単純にログファイルを表示するだけだったページが、少しずつ「監視画面」らしくなってきました。

そして、ここまで作っているうちに、アクセスログだけではなく「実際にWordPressのファイルが変更されていないか」も確認できたほうがいいと思うようになりました。

そこで次は、アクセスログとは別に、Webサイトのファイルそのものを監視する機能を追加することにしました。


7.Webファイルの変更も監視する

アクセスログを確認できるようになってくると、もう一つ気になることが出てきました。

それは、

「アクセスされたことは分かっても、実際にWebサイトのファイルが変更されていないかまでは分からない」

ということです。

以前、WordPressへの攻撃を受けた際に、知らない間にファイルを置かれた経験があったこともあり、アクセスログだけではなく、Webサイトのファイルそのものも監視したいと考えました。

そこで、WordPressのファイルを定期的に確認して、新しく作られたファイル、削除されたファイル、変更されたファイルを検出する機能を追加しました。

監視対象のディレクトリを決める

まず、監視するWebサイトのディレクトリを決めます。

例えば、次のような構成です。

/home/web/html/site1
/home/web/html/site2

それぞれのディレクトリ以下にあるファイルを監視します。

例えば、

/home/web/html/site1/wp-config.php
/home/web/html/site1/index.php
/home/web/html/site1/wp-content/...

などが対象になります。

ディレクトリそのものではなく、その中にあるファイルを対象にするという考え方です。

ファイルの一覧を作る

ファイルの変更を検出するには、現在の状態と以前の状態を比較する必要があります。

そこで最初に、監視対象ディレクトリに存在するファイルを一覧にします。

例えば、次のようなコマンドを使います。

find /home/web/html/site1 -type f -printf '%p|%T@|%s\n' > /var/www/html/monitor/data/site1_files.txt

このコマンドでは、

  • %p → ファイルのパス
  • %T@ → ファイルの更新時刻
  • %s → ファイルサイズ

を取得しています。

その結果、

/home/web/html/site1/index.php|1758961234.123456|5821
/home/web/html/site1/wp-config.php|1758961201.654321|3456

のような情報をファイルに保存できます。

ここで保存しているのはファイルの内容そのものではなく、

「どのファイルが、いつ、何バイトだったか」

という情報です。

サイトごとに監視データを分ける

複数のWebサイトを運用しているため、監視データもサイトごとに分けます。

例えば、

/var/www/html/monitor/data/site1_files.txt
/var/www/html/monitor/data/site2_files.txt

という形です。

こうしておけば、どのサイトでファイル変更が発生したのかを画面上でも区別できます。

実際の環境では、監視対象のサイトを追加する場合も、同じように対象ディレクトリと保存する一覧ファイルを追加していく構成にできます。

現在の状態と以前の状態を比較する

ファイル監視の基本的な考え方はシンプルです。

まず以前保存したファイル一覧を読み込みます。

次に、現在のWebサイトをfindで調べるのと同じ考え方で、PHPから現在存在するファイルを取得します。

そして、

以前の一覧
    ↓
現在のファイル一覧
    ↓
比較

という処理を行います。

例えば、以前の一覧にはなかったファイルが現在存在していれば、

新規作成

と判断できます。

逆に、以前は存在していたファイルが現在なくなっていれば、

削除

です。

さらに、ファイル自体は存在していても、更新時刻やサイズが変わっていれば、

変更

として扱います。

変更されたファイルを一覧で確認する

監視画面では、こうした変化をサイトごとに確認できるようにしました。

例えば、

site1

[新規]
/home/web/html/site1/wp-content/uploads/xxxx.php

[変更]
/home/web/html/site1/wp-config.php

[削除]
/home/web/html/site1/old.php

のような形です。

特に、新しく作られたPHPファイルなどは、アクセスログと合わせて確認することで、何らかの操作が行われていないかを調べるきっかけになります。

ただし、ファイルが変更されたこと自体が異常とは限りません。

WordPress本体やプラグインの更新、テーマの変更、画像のアップロードなど、通常のサイト運用でもファイルは作成・変更・削除されます。

そのため、この機能も「変更があったら即座に不正アクセス」と判断するものではなく、変更されたファイルを見つけやすくするための監視機能として考えています。

ファイルの内容ではなく、状態を監視する

今回の仕組みでは、ファイルの内容をハッシュ化して比較する方法ではなく、

  • ファイルパス
  • 更新時刻
  • ファイルサイズ

を比較しています。

そのため、非常に複雑な仕組みにはせず、PHPからでも比較的簡単に処理できます。

一方で、ファイルの内容そのものが変更されても、更新時刻やサイズが同じになるようなケースまでは検出できません。

今回は、自宅サーバーの状況を手軽に確認するための監視ページという目的なので、まずはこの方式で実装することにしました。

ここまでで、アクセスログだけではなく、Webサイト側で発生したファイルの変化も確認できるようになりました。

ただ、ここで一つ問題がありました。

「現在の状態」と比較するためには、最初に正常な状態を保存しておく必要があります。

そこで次は、監視開始時点のファイル一覧を「正常な状態」として保存し、それを基準に変更を検出する仕組みを作ります。


8.固定ベースラインを作る

7章では、Webサイトのファイルについて、

以前の状態
    ↓
現在の状態
    ↓
比較

することで、新規作成・削除・変更を検出する仕組みを作りました。

しかし、ここで問題になるのが「以前の状態を何にするか」です。

監視ページを開くたびに、その直前の状態を保存してしまうと、ファイルが変更された瞬間にそれが「正常な状態」として記録されてしまいます。

例えば、

正常な状態
    ↓
不正なファイルが追加される
    ↓
その状態を新しい基準として保存
    ↓
次回の比較では「変更なし」

となってしまいます。

これでは、本来検出したかったファイルの追加を見逃してしまいます。

そこで、監視を開始した時点のファイル一覧を**基準となる状態(ベースライン)**として保存し、その後はそのベースラインと現在の状態を比較する方式にしました。

最初に正常な状態を保存する

まず、監視対象のWebサイトについて、現在存在するファイルを一覧にします。

例えば、site1の場合は次のようにします。

find /home/web/html/site1 -type f -printf '%p|%T@|%s\n' > /var/www/html/monitor/data/site1_files.txt

site2についても同じように一覧を作ります。

find /home/web/html/site2 -type f -printf '%p|%T@|%s\n' > /var/www/html/monitor/data/site2_files.txt

この時点で作成されたsite1_files.txtやsite2_files.txtが、監視の基準になります。

例えば、

/home/web/html/site1/index.php|1758961234|5821
/home/web/html/site1/wp-config.php|1758961201|3456
/home/web/html/site1/wp-login.php|1758961190|7231

のように、ファイルごとのパス、更新時刻、サイズが記録されています。

ベースラインは自動的に更新しない

ここで重要なのは、このファイルを監視ページのアクセスごとに作り直さないことです。

ベースラインは、

「この状態を正常な状態として監視する」

という基準だからです。

そのため、WordPress本体を更新したり、プラグインを追加したりして意図的にファイルが変更された場合には、その変更を確認したうえで、必要に応じてベースラインを作り直します。

例えば、

WordPressを更新
    ↓
ファイル変更を検出
    ↓
変更内容を確認
    ↓
問題がなければベースラインを更新

という流れです。

こうしておけば、意図しない変更はそのまま検出対象として残すことができます。

PHPで現在の状態を取得する

監視ページでは、保存してあるベースラインを読み込み、現在のファイル一覧と比較します。

現在のファイルについては、PHPからfindを実行して取得します。

例えば、次のようなイメージです。

ベースライン
    ├─ index.php
    ├─ wp-config.php
    └─ wp-login.php

現在の状態
    ├─ index.php
    ├─ wp-config.php
    ├─ wp-login.php
    └─ unknown.php

この場合、unknown.phpはベースラインには存在しないため、

[新規]
unknown.php

として検出できます。

逆に、

ベースライン
    ├─ index.php
    ├─ wp-config.php
    └─ wp-login.php

現在の状態
    ├─ index.php
    └─ wp-login.php

であれば、wp-config.phpがなくなっているので、

[削除]
wp-config.php

と判断できます。

さらに、ファイルは存在しているものの、保存されている更新時刻やサイズと現在の値が異なっていれば、

[変更]
wp-config.php

として扱います。

更新時刻の小数部分をそろえる

ここで、実際に比較するときに一つ注意する点があります。

findの%T@で取得する更新時刻には、小数部分が含まれる場合があります。

例えば、

/home/web/html/site1/index.php|1758961234.123456|5821

のような値です。

一方、PHPのファイル情報から取得する更新時刻は整数として扱われます。

そこで、比較するときには%T@の値を整数部分にそろえてから比較します。

例えば、

$mtime = (int)floor((float)$parts[1]);

という形で処理します。

これによって、同じファイルについて小数部分の違いだけで「変更された」と判定してしまうことを防ぎます。

ベースラインを使うことで「変更」を追跡できる

この仕組みにすると、単純に「現在ファイルが存在するか」を見るだけではなく、

新規作成
変更
削除

という変化として確認できるようになります。

また、ベースラインを固定しておくことで、監視ページを何度更新しても基準が勝手に変わることがありません。

今回作った監視ページでは、このベースラインを使ってWordPressのファイル変更をチェックし、アクセスログと同じ画面から確認できるようにしました。

ここまでで、アクセスログとファイル変更という二つの情報を監視できるようになりました。

次は、これらを一つの画面で確認しやすくするために、表示方法や自動更新など、監視画面そのものの使い勝手を整えていきます。


9.監視画面をダッシュボードとして整える

ここまでで、アクセスログやファイル変更を確認できるようになりました。

ただ、機能が増えてくると、単純に情報を並べるだけでは見づらくなってきます。

今回の監視ページは、もともとタブレットで常時表示しておくことを想定して作っていたので、最終的には普通のログ表示ページではなく、サーバーの状況を一目で確認できるダッシュボードのような画面に整理しました。

画面上部に基本情報をまとめる

画面の最上部は、監視ページを開いたときにすぐ分かるように、シンプルなヘッダーにしました。

Server Monitor | グラフ | ログアウト

左側にページのタイトルである「Server Monitor」を表示し、右側には24時間のアクセスグラフを確認するための「グラフ」と、ログアウトボタンを配置しています。

ログアウトボタンについては、後の章で説明するログイン機能と合わせて追加したものです。

その下には、

更新日時

を表示します。

監視画面では自動更新を行うため、現在表示されている情報がいつ更新されたものなのか分かるようにしています。

4つの件数をサマリーとして表示する

更新日時の下には、その日のサーバーの状況を数字で確認できるようにしました。

本日のアクセス件数|要注意アクセス件数|404件数|本日のBAN件数

それぞれ、

  • 本日のアクセス件数
  • 要注意アクセス件数
  • 404件数
  • 本日のBAN件数

を表示します。

例えば、

本日のアクセス       1,284
要注意アクセス          17
404                     35
本日のBAN                3

のような形です。

監視ページを開いたときに、まずこの4つの数字を見ることで、その日のアクセス状況をざっくり把握できます。

詳細情報はタブで切り替える

件数のサマリーの下には、詳細情報を確認するためのタブを配置しました。

本日のアクセス|要注意アクセス|ファイル変更|BAN履歴

それぞれ、

  • 本日のアクセス
    今日のアクセスログを確認
  • 要注意アクセス
    監視対象として抽出したアクセスを確認
  • ファイル変更
    Webサイトのファイルに発生した新規作成・変更・削除を確認
  • BAN履歴
    BANされたIPアドレスの履歴を確認

という役割にしています。

上段では数字で全体を把握し、その下のタブでは必要な情報を詳しく確認する、という構成です。

タブレットで常時表示することを前提にする

この監視ページを作ったきっかけがタブレットで表示することだったので、PCの大きな画面だけを基準にしてレイアウトを決めるのではなく、比較的狭い画面でも確認できることを重視しました。

特に、ログ一覧は日時、IPアドレス、ステータス、ドメイン、アクセス先、Methodなど表示する項目が多いため、横幅を無駄に使わないようにしています。

一方で、必要な情報を削りすぎるとログを見る意味がなくなるため、

日時
IPアドレス
ステータス
ドメイン
アクセス先
Method

という基本的な情報は残しました。

スマートフォンではテーブルを横スクロールする

スマートフォンなど画面幅が狭い端末でも、ログの項目を削ったり、無理に折り返したりするのではなく、テーブルそのものを横方向にスクロールできるようにしました。

例えばアクセスログには、

日時|IPアドレス|ステータス|ドメイン|アクセス先|Method

と複数の項目があります。

これらをスマートフォンの画面幅に無理に収めようとすると、文字が小さくなったり、列の幅が狭くなったりして、かえって見づらくなります。

そこで、テーブルは必要な幅を確保したまま、画面の外側にはみ出す部分を横スクロールして確認できるようにしました。

これなら、PCやタブレットではそのまま一覧を確認でき、スマートフォンでは左右にスクロールすることで、同じ情報を確認できます。

つまり、

画面全体
 ↓
画面幅に合わせてレスポンシブ表示

テーブル
 ↓
必要な幅を確保
 ↓
狭い画面では横スクロール

という考え方です。

ログのように列数が多い情報については、無理に縦長のレイアウトへ変更するより、この方法のほうが確認しやすいと考えました。

5分ごとに自動更新する

監視ページなので、ページを開いたままにしておけば、できるだけ新しい情報が表示されるようにしました。

そこで、ページを5分ごとに自動更新します。

HTMLでは、次のような設定です。

<meta http-equiv="refresh" content="300">

300秒なので、5分ごとにページが再読み込みされます。

これなら、タブレットに監視画面を表示したままにしておいても、定期的に最新のログへ更新されます。

選択中のタブを維持する

ここで一つ問題になったのが、自動更新です。

例えば「要注意アクセス」タブを開いて監視していても、5分ごとのページ更新によって毎回「本日のアクセス」に戻ってしまうと使いにくくなります。

そこで、現在選択しているタブをブラウザのlocalStorageに保存するようにしました。

localStorage.setItem('monitorActiveTab', tabName);

ページが更新されたときには保存されているタブを読み込み、更新前と同じタブを表示します。

これによって、監視画面を開いたままにしていても、5分ごとの自動更新で表示している情報が勝手に切り替わらないようにしました。

ダッシュボードとして全体を確認する

最終的には、画面全体を次のような構成にしました。

┌────────────────────────────────────┐
│ Server Monitor  グラフ  ログアウト │
├────────────────────────────────────┤
│ 更新日時                             │
├────────────────────────────────────┤
│ 本日のアクセス │ 要注意 │ 404 │ 本日のBAN │
├────────────────────────────────────┤
│ 本日のアクセス │ 要注意 │ ファイル変更 │ BAN履歴 │
├────────────────────────────────────┤
│                                    │
│        選択したタブのテーブル          │
│       ← 横スクロールで確認 →           │
│                                    │
└────────────────────────────────────┘

つまり、

上段で「今どういう状態なのか」を数字で確認し、その下のタブで「何が起きているのか」を詳しく見る

という構成です。

また、テーブルについては画面幅に合わせて無理に縮小するのではなく、必要な情報を維持したまま、狭い画面では横スクロールして確認できるようにしました。

この形にしたことで、タブレットを常時表示する場合だけでなく、スマートフォンから確認するときにも、ブラウザの表示領域を大きくはみ出すことなく監視ページを利用できるようになりました。

ここまでで、監視するための機能だけでなく、実際に毎日使えるダッシュボードとしての画面も整ってきました。

次は、実際にファイルを作成したりアクセスを発生させたりして、ここまで作った監視機能が期待どおり検出できるかをテストしていきます。


10.実際の動作をテストする

ここまでで、アクセスログ、要注意アクセス、ファイル変更、BAN履歴などを一つの監視画面から確認できるようになりました。

ただ、監視ページは「表示できる」だけでは意味がありません。

実際にアクセスを発生させたり、ファイルを変更したりして、想定したとおりに検出できるかを確認しました。

アクセスログが表示されるか確認する

まず、通常のWebページへアクセスして、監視画面の「本日のアクセス」に表示されるかを確認します。

ブラウザからWebサイトへアクセスすると、Apacheのアクセスログに記録され、その内容が監視専用ログにも記録されます。

監視ページを更新すると、

日時|IPアドレス|ステータス|ドメイン|アクセス先|Method

という形でアクセスが表示されます。

例えば、

2026/09/27 20:45:17  198.51.100.20  404  site1  /flamini.php  GET

のようなログが表示されれば、アクセスログの取得と表示が正常に動作しています。

404アクセスを確認する

次に、存在しないURLへアクセスして、404として記録されるかを確認します。

例えば、

/flamini.php

のような存在しないPHPファイルへアクセスすると、

GET 404 /flamini.php

として記録されます。

同時に、本日の404件数にも加算されます。

ここでは、404になったことだけで要注意アクセスと判断するのではなく、4章で設定した条件に該当する場合に要注意アクセスとして抽出されることも確認します。

要注意アクセスの検出を確認する

次に、監視対象として設定したURLへアクセスして、要注意アクセスとして抽出されるか確認します。

例えば、

/.env
/wp-config.php
/.git/
/phpmyadmin/

などです。

これらにアクセスした場合、存在しなければ404になりますが、通常の404とは区別して、要注意アクセスの一覧にも表示されます。

例えば、

2026/09/27 20:45:17  198.51.100.20  404  site1  /.env  GET

のように表示されれば、要注意アクセスの抽出が正常に動作しています。

ファイルの新規作成をテストする

次に、ファイル監視を確認します。

実際のWebサイトのファイルを変更するのではなく、テスト用のファイルを一つ作成します。

例えば、

touch /home/web/html/site1/monitor_test.txt

として、監視対象ディレクトリにテストファイルを作成します。

その後、監視ページを更新すると、ベースラインには存在しなかったファイルなので、

[新規]
/home/web/html/site1/monitor_test.txt

のように表示されます。

これで、新しく作られたファイルを検出できることを確認できます。

ファイルの変更をテストする

続いて、既存のファイルを変更した場合に検出できるかを確認します。

例えば、テスト用ファイルの内容を変更すると、ファイルの更新時刻やサイズが変化します。

監視ページでは、ベースラインに保存されている値と現在の値を比較するため、

[変更]
/home/web/html/site1/monitor_test.txt

として検出されます。

今回はファイルの内容そのものではなく、更新時刻とサイズを比較しているため、この方法で変更を検出できます。

テストファイルの削除を確認する

最後に、テスト用ファイルを削除します。

rm /home/web/html/site1/monitor_test.txt

ベースラインにはファイルが残っているため、現在の状態と比較すると、

[削除]
/home/web/html/site1/monitor_test.txt

として検出されます。

これで、

新規作成
 ↓
変更
 ↓
削除

の3種類をそれぞれ検出できることを確認しました。

アクセスログとファイル変更を組み合わせて見る

ここまでテストしてみると、アクセスログとファイル監視を組み合わせることの意味が分かってきます。

例えば、

要注意アクセス
    ↓
特定のPHPファイルへのアクセス
    ↓
同じ時間帯に新しいPHPファイルが作成される

という状況があれば、アクセスログとファイル変更を関連付けて確認できます。

もちろん、これだけで不正アクセスが成功したと判断することはできません。

しかし、

「怪しいアクセスがあった」

という情報と、

「その直後にファイルが追加された」

という情報を別々に見るより、同じ監視画面から確認できるほうが、調査のきっかけをつかみやすくなります。

実際に監視画面を使ってみる

一通りテストが終わったことで、監視ページとして最低限必要な機能が動作することを確認できました。

通常のアクセスは「本日のアクセス」で確認し、気になるアクセスがあれば「要注意アクセス」を確認します。

ファイルに変化があれば「ファイル変更」を確認し、BANされたIPについては「BAN履歴」を確認します。

また、上部の件数表示を見ることで、細かいログを見る前に、その日の状況をざっくり把握できます。

ここまでで、監視ページとして一通り使える状態になりました。

ただし、ここで一つ気になる点がありました。

このページにはサーバーのアクセスログやファイル変更の情報が表示されるため、誰でも見られる状態にしておくのは避けたほうがよいということです。

そこで次に、監視ページそのものにログイン認証を追加することにしました。


11.監視画面にログイン機能を付ける

ここまでで、アクセスログやファイル変更を一つの画面から確認できるようになりました。

ただし、この監視画面にはアクセス元のIPアドレスや、サーバー上のファイル名なども表示されます。

そのため、監視ページ自体を誰でも見られる状態にはせず、ログイン認証を付けることにしました。

今回の構成では、PHPのセッションを利用してログイン状態を管理しています。

パスワードはハッシュ化して保存する

パスワードそのものをPHPファイルに書いて比較するのではなく、PHPの password_hash() を使ってハッシュ化した値を使用します。

ハッシュ値は、サーバー上で次のように作成できます。

php -r "echo password_hash('ここにパスワード', PASSWORD_DEFAULT), PHP_EOL;"

ここで表示された文字列を、監視ページ側の認証処理で使用します。

実際のパスワードやハッシュ値は記事には掲載せず、匿名化しています。

PHPでは、入力されたパスワードが正しいかどうかを password_verify() で確認します。

この方法なら、PHPのソースコードに平文のパスワードを書いておく必要がありません。

ログイン状態をセッションで保持する

ログインに成功したら、PHPのセッションにログイン済みであることを記録します。

$_SESSION['monitor_logged_in'] = true;

以降のページ表示では、この値を確認して、ログイン済みの場合だけ監視画面を表示します。

逆に、ログインしていない状態で監視ページへアクセスした場合は、ログイン画面を表示するようにします。

つまり、処理の流れは単純です。

監視ページへアクセス
        ↓
ログイン済み?
   ↓ YES       ↓ NO
監視画面      ログイン画面

ログイン状態は30日間保持する

この監視ページは自宅サーバーの状態を確認するためのものなので、毎回パスワードを入力するのは少し面倒です。

そこで、セッションのCookieの有効期間を30日間に設定しました。

session_set_cookie_params([
    'lifetime' => 60 * 60 * 24 * 30,
    'path' => '/',
    'secure' => isset($_SERVER['HTTPS']),
    ...
]);

これによって、一度ログインすると30日間はログイン状態を維持できる構成にしています。

もちろん、ログアウトすれば、そのセッションを終了してログイン状態を解除できます。

ヘッダーにログアウトボタンを追加する

9章で作ったダッシュボードのヘッダーには、

Server Monitor  グラフ  ログアウト

という構成でログアウトボタンを配置しました。

ログアウトするとセッションを破棄し、再び監視画面を見るにはログインが必要になります。

これで、監視画面を閉じたりブラウザを終了したりした後でも、30日以内であれば再ログインせずに確認できます。

監視ページへのアクセスを認証で保護する

最終的には、監視ページを表示する前にログイン状態を確認する形にしました。

そのため、

  • 未ログイン → ログイン画面
  • ログイン成功 → 監視画面
  • ログイン済み → そのまま監視画面
  • ログアウト → ログイン画面に戻る

というシンプルな構成になっています。

これで、アクセスログ、要注意アクセス、BAN履歴、ファイル変更などの情報を、認証された状態で確認できるようになりました。

ここまで来ると、単なる「Apacheログを表示するPHPページ」ではなく、サーバーの状態を確認するための小さな監視画面らしくなってきました。

そして、ここからさらに一歩進めて、監視しているアクセスログそのものを、実際のアクセス制御にも利用することにしました。 


12.監視ログをFail2Banにも利用する

監視画面を作ってアクセスの様子を確認できるようになると、次に気になってくるのが、要注意アクセスを自動的にブロックできないかということです。

そこで、すでに作っていた monitor_access_log を、Fail2Banの監視対象としても利用することにしました。

監視用ログをそのままFail2Banに渡す

今回の構成では、Apacheのアクセスログを直接Fail2Banで解析するのではなく、監視用に作った

/var/log/httpd/monitor_access_log

をFail2Banにも読み込ませます。

構成としては、次のようになります。

Apache
  │
  ├─ 通常のアクセスログ
  │
  └─ monitor_access_log
          │
          ├─ PHP Monitorで表示
          │
          └─ Fail2Banで監視
                  │
                  └─ 条件に一致したIPをBAN

こうしておくと、PHPの監視画面とFail2Banで別々のログを解析する必要がありません。

一つの監視用ログを、「見るため」と「防御するため」の両方に利用できます。

どのようなアクセスをBAN対象にするか

Fail2Banでは、監視用ログの中から特定のパターンに一致するアクセスを検出します。

たとえば、WordPressやWebサーバーを狙って、

/.env
/.git/
/wp-config.php
/xmlrpc.php
/phpmyadmin/
/pma/
/adminer/

などを繰り返し探しているアクセスや、存在しないPHPファイルを次々に試しているようなアクセスを対象にしました。

ただし、ここで注意したいのは、これらのパスへのアクセスが一度あっただけで、必ずしも攻撃が成功したという意味ではないことです。

そのため、監視画面では「要注意アクセス」として確認できるようにし、Fail2Ban側では設定した条件に一致した場合にBANする、という役割分担にしています。

BANされたIPも監視画面で確認する

Fail2Banを導入すると、実際にどのIPがBANされたのかも確認したくなります。

そこで監視画面には、

本日のBAN件数

を追加し、さらに「BAN履歴」タブから、

日時
IPアドレス
BAN理由

を確認できるようにしました。

これによって、

アクセスされる
      ↓
monitor_access_logに記録
      ↓
PHP Monitorで確認
      ↓
条件に一致
      ↓
Fail2BanがBAN
      ↓
BAN履歴に記録

という一連の流れを、監視画面から追えるようになりました。

監視と防御を分けて考える

今回の構成で意識したのは、PHP Monitorそのものにアクセス制御機能を持たせるのではなく、

  • PHP Monitor → 状況を確認する
  • Apache → アクセスを記録する
  • Fail2Ban → 条件に一致したIPをBANする

というように、それぞれの役割を分けることです。

PHP側で無理にIPをブロックする仕組みにせず、既存のFail2Banを利用することで、監視画面はあくまで「見るためのもの」としてシンプルに保つことができます。

これで、監視画面を見るだけだった状態から、アクセスの検出と自動BANまで含めた構成になりました。

ここまでの機能を整理すると、最終的なServer Monitorはかなり小さなサーバー監視システムらしい形になっています。


14.監視ログのログローテーション

ここまでで監視画面はほぼ完成しましたが、もう一つ考えておく必要があるのが、監視ログそのものの管理です。

今回作った monitor_access_log は、Apacheへのアクセスがあるたびに記録されていきます。

そのままにしておけばログファイルはどんどん大きくなっていくため、一定期間で古いログをローテーションするようにしました。

ログローテーションとは

ログローテーションは、簡単にいうと「古くなったログを別のファイルに退避して、新しいログファイルを使い始める」仕組みです。

例えば、

monitor_access_log
monitor_access_log.1
monitor_access_log.2
monitor_access_log.3

のように、現在のログと過去のログを分けて保存できます。

これによって、現在使用しているログファイルが際限なく大きくなることを防ぎます。

今回の環境では logrotate を利用しています。

基本的には、

weekly
rotate 4

という設定です。

weekly は週単位でログをローテーションする設定で、rotate 4 はローテーションしたログを4世代分残す設定です。

そのため、イメージとしては、

現在のログ
    ↓
1世代前
    ↓
2世代前
    ↓
3世代前
    ↓
4世代前
    ↓
それより古いログは削除

という形になります。

週単位で4世代を保持するため、過去のログについてもおおむね4週間程度は確認できる構成です。

monitor_access_logもローテーション対象にする

今回作成した監視専用ログも、通常のApacheログと同じように logrotate の対象にしました。

対象となるログは、

/var/log/httpd/monitor_access_log

です。

ここで重要なのは、単純にファイルを移動するだけではなく、Apacheが新しいログファイルへ書き込みを続けられるようにすることです。

そのため、ログローテーション後にはApacheにログファイルを再オープンさせる処理を行います。

監視画面とログローテーションの関係

ここで一つ注意したいのは、PHP Monitorが表示している「最新100件」などの情報と、ログローテーションによる保存期間は別の話だということです。

監視画面では現在のログから最新のアクセスを取得して表示しています。

一方、ログローテーションはサーバー上にログをどれだけ残しておくかを管理する仕組みです。

つまり、

Apache
  ↓
monitor_access_log
  ↓
PHP Monitor
  ├─ 最新アクセス
  ├─ 要注意アクセス
  └─ 各種集計

logrotate
  ↓
古いログを順次ローテーション
  ↓
一定世代を超えたログを削除

という、それぞれ別の役割になっています。

Server Monitor側は現在のログファイルを読み込むだけなので、ログローテーションそのものをPHP側で管理する必要はありません。

ログの保存や整理は logrotate に任せ、Server Monitorはログの読み取りと表示に専念させています。

これで、監視画面だけでなく、その裏側で使っている監視ログについても継続的に運用できる状態になりました。


15.まとめ

今回は、自宅サーバーのアクセス状況やWordPressのファイル変更を確認するために、PHPで簡単な監視モニターを作ってみました。

最初は、8インチタブレットの空いた画面に表示するものを探していただけでした。

そこからServer Glanceを試し、CPUやRAMの使用率だけでなく、せっかくなら自分のサーバーへのアクセス状況も見られたらいいのではないかと思い、少しずつ自作する方向に進んでいきました。

最初に作ったのは、Apacheのアクセスログを読み込んで表示するだけのシンプルなPHPページでした。

そこから、

  • 監視専用のアクセスログを作る
  • 最新のアクセスを表示する
  • 要注意アクセスを抽出する
  • 404を集計する
  • 24時間のアクセス状況をグラフ化する
  • WordPressのファイル変更を監視する
  • 固定ベースラインと比較して新規・変更・削除を検出する
  • タブレットでも見やすいダッシュボードにする
  • 5分ごとに自動更新する
  • 選択中のタブを保持する
  • ログイン認証を付ける
  • Fail2Banと連携してBAN状況を確認する
  • ログローテーションで監視ログを管理する

といった機能を順番に追加していきました。

最終的には、こんな感じの構成になっています。

             Apache
                │
                ▼
       monitor_access_log
          │           │
          │           └────────────┐
          ▼                        ▼
    PHP Monitor                 Fail2Ban
          │                        │
          │                        ▼
          │                       BAN
          │
          ├─ アクセス状況
          ├─ 要注意アクセス
          ├─ 24時間グラフ
          ├─ ファイル変更
          └─ BAN履歴

        WordPress
             │
             ▼
       ファイル変更監視
             │
             ▼
        固定ベースライン

        logrotate
             │
             ▼
       過去ログを管理

専用の大規模な監視システムを導入したわけではありません。

Apacheがもともと持っているアクセスログ、Linuxの logrotate、Fail2Ban、そしてPHPを組み合わせて、自分のサーバー環境で「これが見たい」と思った情報だけを表示するようにしました。

特に、以前WordPressへの攻撃で知らない間にファイルを置かれた経験があったので、単にアクセス数を見るだけではなく、アクセスログとファイル変更の両方を確認できるようにしたのは今回の大きなポイントでした。

もちろん、このモニターがあれば不正アクセスを完全に防げるわけではありません。

「要注意アクセス」として表示されたものが必ず攻撃とは限りませんし、ファイル変更があったからといって、それだけで不正な変更とも限りません。

あくまで、普段と違う動きに気付きやすくするための監視画面です。

それでも、以前ならSSHでサーバーに接続してログを確認したり、いくつかのコマンドを実行したりしなければ分からなかったことが、タブレットを開いて監視画面を見るだけで確認できるようになりました。

結果として、最初に考えていた「タブレットの空いた画面に何か表示したい」というところから、思った以上に実用的な自宅サーバー用のモニターを作ることができました。

自分の環境に必要なものだけを、自分で少しずつ追加していけるのは、自作する面白さの一つだと思います。


16.おまけ:はまったところ、工夫したところ

ここからはおまけとして、実際にServer Monitorを作っていて、途中で少しはまったところや、使ってみて工夫したところをまとめておきます。

最初から完成形を決めて作ったわけではなく、実際に画面を確認しながら少しずつ修正していきました。

グラフは絶対値ではなく、当日の相対値にした

24時間のアクセスグラフを作るとき、最初は1時間ごとのアクセス数をそのまま棒の高さにしようと考えました。

しかし、アクセス数が少ない時間帯は棒がほとんど見えなくなってしまいます。

そこで、1日の中で最もアクセスが多かった時間帯を最大値として、それぞれの時間帯を相対的な高さで表示することにしました。

例えば、

10時  10件
11時  20件
12時  40件
13時  80件

なら、グラフではおおよそ、

10時  █
11時  ██
12時  ████
13時  ████████

という表示になります。

このグラフは、棒の高さから正確なアクセス件数を読み取るためのものではなく、

「1日の中で、いつアクセスが集中しているのかを見る」

ためのものと割り切っています。

正確な件数については、画面に表示されるアクセス一覧や集計値で確認します。

404は別のグラフにせず、アクセスの中に積み上げた

404についても、単純にアクセス数とは別の棒として表示するのではなく、アクセス総数の中に積み上げて表示するようにしました。

例えば、ある時間帯に100件のアクセスがあり、そのうち5件が404だった場合、

┌──────────┐
│          │
│          │
│          │
│          │
│          │
│          │
│          │
│          │
│          │
│    404   │
└──────────┘

というように、アクセス総数の一部として404を表示します。

これなら、

「この時間帯はアクセスが多かった」

ということと、

「その中に404がどの程度含まれていたか」

を同時に見ることができます。

ただ、404が1件や2件しかない場合、そのままだとグラフ上ではほとんど見えません。

そこで、404が存在する場合は最低2px程度の高さを確保して、少ない件数でも「404があった」ことが分かるようにしました。

こういう細かい部分は、実際に画面を見ながら調整していったところです。

「表示する件数」と「集計する件数」を混ぜてしまった

今回、一番はまったのがここでした。

あるとき監視画面を見ると、

本日のアクセス

142

要注意アクセス

1,112

404

2

という、明らかにおかしな数字になっていました。

「今日のアクセスが142件なのに、要注意アクセスが1,112件?」

という状態です。

原因を調べてみると、要注意アクセスを入れている配列には過去のログも含まれていたのに、その配列の件数をそのまま「本日の要注意アクセス」として表示していました。

当初は、

count($suspicious)

で要注意アクセスの件数を表示していました。

ところが、この $suspicious には今日より前のログも含まれています。

一方、画面に表示する一覧については、

$suspicious = array_slice(
    $suspicious,
    0,
    100
);

として、最新100件だけに制限していました。

つまり、

「一覧に何件表示するか」と「今日何件発生したか」という2つの処理が混ざっていた

わけです。

そこで、集計用の変数を別に用意しました。

$totalToday = 0;
$total404 = 0;
$totalSuspicious = 0;
$today = date('Y/m/d');

要注意アクセスと判定したときには、今日のログかどうかを確認してカウントします。

if ($isSuspicious) {
    $suspicious[] = $item;

    /*
     * 本日の要注意アクセス
     */
    if (
        strpos(
            $m[1],
            $today . ' '
        ) === 0
    ) {
        $totalSuspicious++;
    }
}

そして、

$suspicious = array_slice(
    $suspicious,
    0,
    100
);

は、あくまで画面に表示する一覧を100件に制限するために使います。

これで、

本日のアクセス    → 今日のアクセス数
要注意アクセス    → 今日の要注意アクセス数
404               → 今日の404件数

アクセス一覧      → 最新100件
要注意一覧        → 最新100件

と、それぞれの意味を分けることができました。

これは今回作っていて、かなり分かりやすい「はまりどころ」でした。

実際に使ってみてから分かることも多かった

今回のServer Monitorは、最初からすべての仕様を決めて、その通りに完成させたものではありません。

まずログを表示して、そこから、

「Methodも表示したい」

「ステータスコードも見たい」

「404の件数も分かるようにしたい」

「時間帯ごとのアクセスも見たい」

「ファイルの変更も監視したい」

という具合に、実際に使いながら少しずつ機能を追加していきました。

その過程で、今回のように「表示そのものはできているけれど、集計の意味がおかしい」という問題も見つかりました。

最終的には、単に機能を増やすだけではなく、

「この数字は何を表しているのか」

「この一覧は何を表示しているのか」

を分けて考えることが大切だと分かりました。

自分で使うための小さな監視ページだからこそ、実際の画面を見ながら調整できたのは、今回作ってみて面白かったところです。

🗂  サーバー

↓

Getting Started

記事は右側のリストメニューから探せます。
初めての方は下のおすすめ記事からどうぞ。

Quote of the Day

「俗物(ぞくぶつ)」とは、

世間的な名誉、地位、金銭などの物質的な利益ばかりを追い求め、
精神的なゆとりや教養、芸術の情趣を解さない、
つまらない人物やもののことです。

— google検索でのAIによる回答
↑