【完全解説】Cloudflare+VPSシールドでWordPressを守る:GCP等の悪質データセンターボットを最前線で即時撃退(HTTP 444)する多重防護設計

この記事は約20分で読めます。
この記事が役立ったらブックマーク! あとで読み返したり、環境構築時のリファレンスに活用できます
B! はてなブックマークに追加

自宅サーバーで WordPress をセキュアに公開する際、Cloudflare の背後に「VPS リバースプロキシ(盾)」を挟む多重構成は非常に強力な防壁となります。
しかし、公開直後から立ちはだかるのが 「Google Cloud(GCP)や AWS などのデータセンター回線から執拗に飛んでくる admin-ajax.php へのスキャン攻撃」 です。これらは WAF を巧妙にかいくぐり、自宅サーバーの CPU やメモリを着実に削っていきます。

本稿では、一般ユーザーのダウンロード機能や各種認証を一切損なわずに、「悪質なクラウド・データセンター IP だけを VPS 最前面で即座に通信破棄(HTTP 444)するアーキテクチャ」 の設計と Nginx 設定を完全公開します。

1. 防御アーキテクチャの全体像

本システムのトラフィックフローは以下の 3 層構造をとっています。

Plaintext
[ 訪問者 / クラウドボット ]
           │
           ▼
[ Layer 1: Cloudflare Edge ] (DNS / CDN / エッジプロキシ)
           │ (CF-Connecting-IP を付与)
           ▼
[ Layer 2: 玄関 VPS (Shield Proxy) ] ★ここで悪質ボットを瞬殺
           │  ├─ データセンターIP ──▶ 【 HTTP 444 切断 (破棄) 】
           │  └─ 正規ユーザー   ──▶ 暗号化トンネル / 代替ポート
           ▼
[ Layer 3: 自宅サーバー (Origin) ] (WordOps / Nginx / PHP-FPM)
              └─ 管理画面(/wp-admin)は自宅IPのみ許可
Plaintext
[ Visitors / Cloud Bots ]
           │
           ▼
[ Layer 1: Cloudflare Edge ] (DNS / CDN / Edge Proxy)
           │ (Appends CF-Connecting-IP)
           ▼
[ Layer 2: Gateway VPS (Shield Proxy) ] ★ Instantly drops malicious bots here
           │  ├─ Datacenter IPs ──▶ [ HTTP 444 Drop / Reset ]
           │  └─ Legitimate Traffic ──▶ Encrypted Tunnel / Alternate Port
           ▼
[ Layer 3: Home Server (Origin) ] (WordOps / Nginx / PHP-FPM)
              └─ /wp-admin strictly restricted to home IPs

設計上の要件

  1. ピンポイント迎撃: クラウド事業者の IP アドレス帯からのアクセスのみを狙い撃ちにする。
  2. 一般機能の完全保護: 記事閲覧はもちろん、Ajax を用いるフロントエンド機能(WordPress Download Manager のダウンロード処理や reCAPTCHA トークン検証など)は無条件でパスさせる。
  3. 無駄なリソースの完全排除: 攻撃者には 403 Forbidden などの HTML レスポンスすら返さず、TCP コネクションをその場で強制断ち切る HTTP 444(No Response)で迎え撃つ。

2. クラウド・データセンター IP を判別するマップ定義

Cloudflare をプロキシモードで通過させると、Nginx の $remote_addr は Cloudflare のエッジ IP に書き換わってしまいます。
そのため、Cloudflare が元の接続元クライアント IP を格納して渡してくれる $http_cf_connecting_ip を利用して、高速な CIDR / プレフィックス判定マップを作成します。

VPS 側:/etc/nginx/conf.d/datacenter_block.conf

Nginx
# Cloudflare 経由の実クライアント IP を検査し、データセンター回線をフラグ付け
map $http_cf_connecting_ip $is_datacenter {
    default 0;

    # Google Cloud (GCP) 主要IP帯
    "~^34\."        1;
    "~^35\."        1;
    "~^104\.19[6-9]" 1;
    "~^205\.169\."  1;

    # 必要に応じて AWS やその他クラウド事業者の帯域を追加可能
    # "~^52\."     1;
    # "~^54\."     1;
}

Nginx の map モジュールはハッシュテーブルまたは内部ツリーで処理されるため、大量のリクエストが押し寄せても CPU 負荷を極めて低く抑えたまま瞬時に判定が完了します。

3. 急所(admin-ajax.php)でのピンポイント即時切断(HTTP 444)

WordPress の admin-ajax.php は、管理画面内だけでなくフロントエンド(表側)の動的処理にも使われるため、全体を IP 制限することはできません。
そこで、VPS 側の server ブロック内で以下のようにハンドリングします。

VPS 側:/etc/nginx/sites-available/shield.conf

Nginx
server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name example.com www.example.com;

    # SSL証明書・基本設定(割愛)...

    # =========================================================
    # 🛡️ admin-ajax.php 防衛ライン
    # =========================================================
    location = /wp-admin/admin-ajax.php {
        # データセンターIPからのアクセスであれば即時通信遮断
        if ($is_datacenter = 1) {
            return 444;
        }

        # 正規のアクセスは自宅サーバーの代替ポートへプロキシ転送
        proxy_pass https://YOUR_HOME_SERVER_IP:8443;
        
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $http_cf_connecting_ip;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # バッファ・タイムアウト設定
        proxy_connect_timeout 30s;
        proxy_read_timeout 60s;
        proxy_buffer_size 64k;
        proxy_buffers 4 128k;
    }

    # =========================================================
    # 通常のトラフィック転送
    # =========================================================
    location / {
        proxy_pass https://YOUR_HOME_SERVER_IP:8443;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $http_cf_connecting_ip;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
  • return 444; の強み: HTTP ヘッダーすら返さず、カーネルレベルで TCP コネクションを即座に DROP します。攻撃者側のスクリプトはタイムアウトまたは接続リセットで停止し、こちらのサーバーリソースは 1 バイトたりとも無駄になりません。

4. 診断・テスト時の落とし穴:DNS ループバック(IPv6 迷子)問題

この構成をテスト・検証する際、多くのエンジニアがハマる罠が存在します。それが 「名前解決による迂回自爆」 です。

実際に直面したトラブル

VPS に遮断ルールを設定し、自宅サーバー内から curl -I

(https://example.com/wp-admin/admin-ajax.php) を叩いて動作検証を行っていたところ、VPS のアクセスログに一切記録が残らず、自宅サーバー側から直接 HTTP 400 Bad Request が返ってくる という不可解な現象が起きました。

原因の究明

自宅サーバー(home-origin)で名前解決の挙動を確認したところ:

Bash
getent hosts example.com
# 出力: 2400:4051:xxxx:xxxx::1  example.com

自ホストの環境で、自ドメインが 「自宅ルーターまたは自マシンのグローバル IPv6」 に直接名前解決されていました。 その結果、通信が外部(Cloudflare や VPS)に出ることなく、自分自身の Nginx の IPv6 リスナーへ直接ループバック接続 していたため、VPS シールドが完全にバイパスされていたのです。

正しい検証手法:--resolve で経路を固定する

リバースプロキシの動作テストを行う際は、OS の DNS リゾルバに頼ってはいけません。curl の --resolve オプションを使い、宛先 IP を強制的に VPS に固定してテストパケットを流します。

Bash
# GCPのIPを模倣したヘッダーを乗せ、強制的にVPSへリクエストを流す
curl -I -k \
  --resolve example.com:443:YOUR_VPS_IP \
  -H "Host: example.com" \
  -H "CF-Connecting-IP: 34.120.50.10" \
  https://example.com/wp-admin/admin-ajax.php

検証結果の判定

  • 成功: curl: (52) Empty reply from server や curl: (92) HTTP/2 stream was not closed cleanly before end of the underlying stream(Nginx が 444 でコネクションを即時切断した証拠)が返れば、シールドが正常に稼働しています。
  • 一般アクセスのテスト: -H "CF-Connecting-IP: 118.7.xxx.xxx" など通常プロバイダの IP を渡した場合は、正しく自宅サーバーへ転送され 200 OK や適切なレスポンスが返ることを確認します。

5. 自宅サーバー本丸側でのダメ押し防御(RealIP & 多重ホワイトリスト)

万が一、VPS の前段をすり抜けて直接アクセスが試みられた場合に備え、自宅サーバー(home-origin)側でも多重の防御線を敷いておきます。

自宅側 Nginx:/etc/nginx/sites-available/example.com

Nginx
# 1. 玄関VPSからの通信のみ実IPとして復元
set_real_ip_from YOUR_VPS_IP;
real_ip_header X-Forwarded-For;
real_ip_recursive on;

# 2. 本丸の管理画面(/wp-admin)は自宅IPのみ完全排他
location ~* ^/(wp-login\.php|wp-admin) {
    allow 192.168.1.0/24;       # 宅内LAN
    allow 118.7.101.0/24;       # 自宅固定IPv4
    allow 2400:4051:b961::/48;  # 自宅プロバイダIPv6全体
    allow YOUR_VPS_IP;          # VPS転送IP
    allow 127.0.0.1;
    allow ::1;
    deny all;

    # PHP 実行ハンドラー...
}
  • VPS 側で $is_datacenter による足切りを行い、自宅側では厳格なホワイトリストで管理画面を完全封鎖することで、外部からの不正アクセスや脆弱性スキャンの侵入経路を完全に遮断します。

導入効果と実稼働実績

本システムを導入してわずか数時間後、fail2ban がどのように機能したかの実稼働証拠です。
狙い通り、return 444 の罠に触れた悪質なボット群(特にGCPデータセンターIP)が、次々と OS 層の監獄(ファイアウォールのブラックリスト)へ叩き込まれているのが確認できます。

証拠:fail2ban 実稼働ログ(vm-39444a79-0c)

Plaintext
root@Shield-VPS:~# sudo fail2ban-client status nginx-444
Status for the jail: nginx-444
|- Filter
|  |- Currently failed: 4
|  |- Total failed:     372
|  `- File list:        /var/log/nginx/nanka-yoshi.access.log ...
`- Actions
   |- Currently banned: 38
   |- Total banned:     40
   `- Banned IP list:   159.65.141.118 34.64.246.250 79.127.129.211 143.110.220.164 129.159.56.14 79.127.129.229 35.187.175.49 23.251.146.115 77.88.9.142 34.62.149.220 34.73.24.34 77.88.9.144 35.236.143.155 35.231.32.21 136.65.251.127 220.181.108.156 93.152.209.7 205.169.39.50 34.72.176.129 34.123.170.104 104.197.69.115 34.122.147.229 35.231.174.87 34.44.142.114 34.46.138.166 34.31.203.120 118.193.44.112 123.58.213.118 34.44.196.215 34.122.173.216 103.218.241.7 152.32.173.15 93.152.205.174 35.221.212.76 220.181.108.176 118.193.36.107 165.154.162.212 165.154.206.139

このログを見ると、「Total failed: 372」(372回の攻撃試行)に対し、Nginx と fail2ban が連携して 38のIPアドレスを完全に遮断(Banned) しています。もし無防備であれば、この372回すべてが WordPress(PHP・DB)まで到達し、自宅サーバーの貴重な CPU・メモリ・ディスク I/O を浪費させていたことになります。
BANリスト内の 34.x / 35.x / 104.19x といった IP 帯は、Google Cloud(GCP)データセンターのものです。まさに「脆弱性探索ハニーポット」が機能し、悪質なクラウドクローラーを最前線で一網打尽にできた証拠と言えます。

まとめ

  1. 多重防御の役割分担: Cloudflare で大まかな DDoS・悪質帯域を抑え、VPS(Nginx map)でクラウドボットのピンポイント急所攻撃を 444 瞬殺し、自宅サーバー本丸は許可 IP 以外に対して完全沈黙を保つ。
  2. 正規トラフィックを犠牲にしない: 全体遮断ではなく $http_cf_connecting_ip を見た admin-ajax.php 単位の条件付き切断にすることで、ダウンロードプラグインや Ajax 処理の利便性を完全に両立。
  3. テストは --resolve が必須: 多重ネットワークでは自ホストの DNS ループバック(IPv6 直結)による「テストの錯覚」が起きやすいため、疎通確認は必ず IP アドレスを明示的に指定して実施する。

この構成を導入して以来、GCP や海外クラウドからの無駄なスキャンリクエストは VPS 最前線で 0 秒撃墜され、自宅サーバー側の CPU 使用率とログ容量は極めてクリーンな状態を維持し続けています。

コメント

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