10G光クロス×MAP-Eサバイバル。ログの罠をハックして不正アクセスを自動爆破する「fail2ban」動的迎撃編

この記事は約12分で読めます。

前回のセキュリティ編では、最大の急所である wp-login.php をIP制限でガチガチに鍛え上げました。 自分以外のアクセスを「403 Forbidden」で一撃シャットアウトする静的防御は完璧です。
しかし、世界中の bot や攻撃者は諦めません。ログイン画面がダメなら、次は怪しい海外IPからサイト全体をスキャンしたり、他の脆弱性(xmlrpc.php など)を狙って執拗にアタックを仕掛けてきます。 これらをいちいち手動でブロックするのは不可能ですし、サーバーの無駄なリソースを消費させられるのも癪ですよね。

そこで今回は、ログをリアルタイムで監視し、怪しい動きをした IP を自動的に検知してファイアウォールで即座に遮断(BAN)する最強の動的迎撃ツール 「fail2ban」 を導入します。
ただし!例によって私たちの 【VPS中継+自宅WordOps】 という環境では、普通に導入すると「身代わりの中継 VPS がセルフ BAN され、サイトが完全沈黙する」という特大の罠があります。この罠の回避も含めて、美しい構築手順を解説します!

🚨 今回の致命的な罠:Nginx のログフォーマット問題

前回の設定で、Nginx の real_ip モジュールを使い、「本当のIP」を WordPress 側に渡せるようになりました。
しかし、ここに落とし穴があります。Nginx の標準設定のままだと、access.log(アクセスログ)に記録されるIPが、相変わらず 「中継元である VPS のIP」 のままになっているケースがあるのです。
この状態で fail2ban を起動し、「wp-login.php に何度もアタックしてくる悪質なIPを BAN せよ!」と命令すると、fail2ban はログに書かれている IP……つまり あなたの VPS の IP を「悪質な攻撃者」と誤認し、自宅サーバーから VPS との接続を完全に遮断(セルフ BAN)してしまいます。 結果、世界中からサイトへのアクセスが一切途絶えるという大惨事になります。
これを防ぐため、まずは 「Nginx のログ自体にも、本当の接続元IPを正しく刻印させる」 ハックから始めます。

🛠️ ステップ 1:Nginx のログに「本当のIP」を記録させる

1. Nginxのメイン設定を開く

まずは自宅 WordOps 側の Nginx 設定を修正し、ログの出力形式(log_format)で本当の IP($http_x_forwarded_for または real_ip 適用後の $remote_addr)が残るようにします。
WordOps の場合、メインの nginx.conf またはドメインごとの設定でログフォーマットが定義されています。今回は一番確実な、Nginx のメイン設定を確認・修正します。

Bash
sudo nano /etc/nginx/nginx.conf

2. ログフォーマットの書き換え

ファイル内を探すと、以下のような WordOps 標準のログ設定が見つかります。

Nginx
# 【変更前】WordOpsの標準設定
log_format rt_cache '$remote_addr $upstream_response_time $upstream_cache_status [$time_local] '
                    '$host "$request" $status $body_bytes_sent '
                    '"$http_referer" "$http_user_agent" "$server_protocol" "$http3"';

この先頭にある $remote_addr が曲者です。 前回の記事で real_ip モジュールを設定していれば、ここも自動的に「本物のIP」に差し替わりますが、環境やタイミングによっては中継 VPS のIPを掴んだままログに吐き出してしまうケースがあります。

確実に「伝票(X-Forwarded-For)に書かれた本物のIP」をログの先頭に刻印するため、以下のように $http_x_forwarded_for に書き換える、または追記して安全策を講じます。

Nginx
# 【変更後】先頭のIP取得元を「X-Forwarded-For」に明示的に書き換える
log_format rt_cache '$http_x_forwarded_for $upstream_response_time $upstream_cache_status [$time_local] '
                    '$host "$request" $status $body_bytes_sent '
                    '"$http_referer" "$http_user_agent" "$server_protocol" "$http3"';

※こうすることで、WordOps独自の高速化キャッシュログの仕組みを1ミリも壊すことなく、fail2ban専用の完璧な監視ログに変貌します

設定を変更したら、保存して Nginx をテスト&リロードします。

Bash
sudo nginx -t
sudo systemctl reload nginx

これで、tail -f /var/log/nginx/test-site.online.access.log を叩いたときに、VPS の IP ではなく、アクセスしてきたスマホや海外の bot の「本当のIP」がログの先頭に記録されるようになれば第一関門突破です!

🛠️ ステップ 2:fail2ban のインストールと設定

ログが綺麗になったら、いよいよ fail2ban を召喚します。

1. インストール

Bash
sudo apt update
sudo apt install fail2ban -y

2. ローカル設定ファイルの作成

設定ファイルを直接弄るとアップデートで上書きされるため、コピーを作って編集します。

Bash
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.local

3. VPS の IP を「絶対 BAN しないリスト」に入れる(超重要)

万が一の誤判定を防ぐため、[DEFAULT] セクションにある ignoreip に、あなたの VPS の IP自宅のローカル IP を必ず登録しておきます。
また、jail.local には最初から bantime などの設定行が存在しているため、新しく追記するのではなく、既存の行を探して数値を書き換える ようにしてください。(同じ設定が2つあると fail2ban が起動エラーを起こします)

ファイル内を少し下にスクロールしながら、以下の項目を書き換えます。

Bash
[DEFAULT]
# 【修正】ホワイトリストに自宅ローカルと VPS の IP をスペース区切りで追加
ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24 118.27.203.45 153.156.79.69 # ★あなたのVPSと自宅のIP

# 【修正】既存の行を探して、好みの数値に書き換える(追記はNG!)
bantime  = 1d  # 10m から 1d(1日間)などに変更
findtime = 10m # そのまま、または任意で変更
maxretry = 5   # そのまま、または任意で変更

⚔️ ステップ 3:WordPress アタック迎撃用の「フィルター」を作る

次に、「どんなログが来たら攻撃とみなすか」のルール(フィルター)を作ります。今回は一番狙われる wp-login.phpxmlrpc.php を狙い撃ちします。
当然、初期状態では WordPress 専用のフィルターは存在しないため、ここは新しくファイルを新規作成する形になります。

Bash
sudo nano /etc/fail2ban/filter.d/nginx-wp-admin.conf

以下の内容を貼り付けて保存します。

INI
[Definition]
failregex = ^<HOST> -.*"POST /(wp-login\.php|xmlrpc\.php) HTTP/.*" (200|403|401)
ignoreregex =

※前回のIP制限で 403 を返している場合でも、しつこく叩いてくる bot をログから検知してファイアウォール層で完全に黙らせる正規表現です

🛡️ ステップ 4:迎撃システム(Jail)を起動する

最後に、作ったフィルターとログファイルを紐付けます。再び jail.local を開くか、jail.d/ 下に設定を作ります。

Bash
sudo nano /etc/fail2ban/jail.d/nginx-wordpress.conf

以下を記述して保存します。

INI
[nginx-wordpress]
enabled  = true
port     = http,https
filter   = nginx-wp-admin
logpath  = /var/log/nginx/test-site.online.access.log
backend  = auto
maxretry = 3 # 3回連続でアタックしてきたらアウト

すべて完了したら、fail2ban を有効化して起動します!

Bash
sudo systemctl enable fail2ban
sudo systemctl start fail2ban

正しく動いているかは、以下のコマンドで確認できます。

Bash
sudo fail2ban-client status nginx-wordpress

正しく動作するとこのようなステータスが表示されます。

Plaintext
Status for the jail: nginx-wordpress
|- Filter
|  |- Currently failed: 0
|  |- Total failed:     0
|  `- File list:        /var/log/nginx/test-site.online.access.log
`- Actions
   |- Currently banned: 0
   |- Total banned:     0
   `- Banned IP list:

🔗 アタックが届く前に「無」に帰す

これで動的迎撃システムが完成しました!
悪意ある bot が wp-login.phpxmlrpc.php を執拗にスキャンすると、3回突っついた時点で fail2ban がログから検知。OS のファイアウォール(UFW等)に指令を出し、そのIPからの接続自体を自宅サーバーの入り口でバッサリと遮断します。
Nginx や WordPress に処理が到達する前に OS レベルで通信を「無」にするため、サーバーへの負荷はほぼゼロ。これぞインフラ屋の脳汁が出る瞬間です。

前回の「静的防御」と、今回の「動的迎撃」が揃ったことで、私たちの10G自宅サーバーは外部からの攻撃に対して文字通り鉄壁の要塞と化しました。しかし、セキュリティハックはこれで終わりではありません。
次回は、動的迎撃システムをさらに強固にするために、「そもそも怪しい通信を入り口ではじくアクセス制限系の追加設定」をお届けします。特定の海外IPの遮断やアクセス元制限など、さらに踏み込んだ要塞化を進めていきましょう。お楽しみに!

次の記事は2026年7月30日公開です。

10G光クロス×MAP-Eサバイバル。fail2banの次はこれ!WordPressのユーザー名露出とXML-RPCをNginxレイヤーで先行遮断するセキュリティ強化編
WordPressの不正アクセス対策として必須の「xmlrpc.php」と「REST API」のアクセス制限に関する備忘録。外部連携の利便性を維持したまま、攻撃の足がかりをスマートに封鎖する具体的な運用のコツをまとめました。

コメント

タイトルとURLをコピーしました