[PR] 本記事にはプロモーションが含まれています。

【Cloudflare】WAFのカスタムルールで自宅サーバーのWordPressを守る|海外アクセス・ログイン画面・phpMyAdminの制限

Cloudflare

【2026年11月2日時点の情報です】

このブログは、自宅のサーバーからCloudflare Tunnelで公開しています。ルーターのポートは開けていませんが、Cloudflareまで届いたアクセスはそのままサーバーに渡るので、WordPressのログイン画面などは、世界中から試せる状態です。

そこで、CloudflareのWAF(Webアプリケーションファイアウォール)の「カスタムルール」を使い、怪しいアクセスにはサーバーに届く前にチャレンジ(人間かどうかの確認)をかけたり、ブロックしたりしています。

この記事では、よく使われる守り方と、その設定の例を紹介します。自分の設定をそのまま載せると、「どこから来れば通れるか」まで見せてしまうので、式は一般的な例にしています。そのかわり、自分で設定して気づいたことや、あとから直したところは、そのまま書きます。

Cloudflareのアカウント作成と、ドメインの登録は済んでいる前提です。

設定する場所とルールの数

カスタムルールは、Cloudflareのダッシュボードで対象のドメインを選び、「セキュリティ」→「セキュリティルール」→「ルールを作成」→「カスタムルール」から作ります(2026年11月時点の画面です。Cloudflareは画面の名前や場所がよく変わるので、見つからないときは「WAF」や「カスタムルール」で探してください)。

条件は画面の項目を選んで作ることもできますが、この記事では「式を編集」で入力する式の形で紹介します。式を貼り付けると、画面の項目にも反映されます。

無料プランで作れるカスタムルールは5つまでで、上から順に評価されます。アクションは、主に次の2つを使い分けます。

No.アクション動き向いているもの
1マネージドチャレンジ人間のブラウザなら自動で(ときどきチェックボックス1つで)通れ、プログラムによる機械的なアクセスは止まる自分が外出先から開くこともある場所(ログイン画面など)
2ブロック理由を問わず止める外から使うことのない場所(データベースの管理ツールなど)

このあとの式に出てくる 2001:db8:1234:5678::/64 は、自宅の回線のIPv6アドレス(プレフィックス)の例です(説明用に決められた、実際には使われないアドレスです)。使うときは、自分の回線の値に置き換えてください。自宅のIPv6プレフィックスは、自宅のパソコンで https://www.cloudflare.com/cdn-cgi/trace を開いたときの ip= の値の、先頭4ブロックで確かめられます。

守り方1:ログイン画面・管理画面を、自宅以外からは確認の画面にする

いちばん効くのが、WordPressのログイン画面と管理画面を、自宅以外から開いたときにチャレンジをかける守り方です。パスワードの総当たり(片っ端からパスワードを試す攻撃)を、サーバーに届く前に止められます。

対象によく入れるパスは、次のとおりです。

No.パス内容扱い
1/wp-login.phpWordPressのログイン画面対象
2/wp-admin で始まるものWordPressの管理画面対象
3/wp-admin/admin-ajax.php読者側のページからも使われる通信の窓口対象外
4/xmlrpc.php外部のアプリから記事を投稿する古い仕組み。総当たりによく使われる対象
5/.env設定ファイルを探すアクセス対象

式の例です(アクションは「マネージドチャレンジ」)。

((starts_with(http.request.uri.path, "/wp-admin") and http.request.uri.path ne "/wp-admin/admin-ajax.php") or http.request.uri.path eq "/wp-login.php" or http.request.uri.path eq "/xmlrpc.php" or http.request.uri.path eq "/.env") and not ip.src in {2001:db8:1234:5678::/64}
  • starts_with(http.request.uri.path, "/wp-admin"):
    パスが /wp-admin で始まる
  • http.request.uri.path ne "/wp-admin/admin-ajax.php":
    ただし admin-ajax.php は除く(ne は「等しくない」)
  • http.request.uri.path eq "/wp-login.php":
    パスがログイン画面と等しい
  • not ip.src in {…}:
    送り元が、かっこの中のアドレスの範囲(自宅)に入っていない

自分で設定していて、あとから直したところが3つあります。

1つ目は、ログイン画面の /wp-login.php を入れ忘れていたことです。はじめは /wp-admin で始まるパスだけを対象にしていましたが、WordPressのログイン画面は /wp-login.php なので、肝心のログイン画面は誰でも何度でも試せる状態でした。あわせて /xmlrpc.php も足しました。WordPressのスマホアプリなど、外部のアプリから投稿している場合は、/xmlrpc.php は外してください。

2つ目は、/wp-admin/admin-ajax.php を対象から外したことです。名前に wp-admin と入っていますが、読者が見るページからも使われます。このブログでは、商品リンクのプラグイン(ポチップ)やポップアップのプラグインがこれを使っているので、チャレンジがかかると、読者のブラウザで裏の通信が失敗するおそれがありました。

3つ目は、式の「and」と「or」の順番です。Cloudflareの式では、「and」が「or」より先に計算されます。はじめは、自宅の除外を条件ごとに書いていて、どこまでがひとまとまりなのか分かりにくくなっていました。今は、対象のパスを丸かっこでまとめて、最後に1回だけ「自宅以外」をかける形にしています。

守り方2:phpMyAdmin のような管理ツールはブロックする

データベースを管理する phpMyAdmin のように、外から使うことのない管理ツールは、自宅以外からはブロックします。

式の例です(アクションは「ブロック」)。

(starts_with(lower(http.request.uri.path), "/phpmyadmin") and not ip.src in {2001:db8:1234:5678::/64})
  • lower(http.request.uri.path):
    パスを小文字にしてからくらべる。phpMyAdmin は /phpMyAdmin と /phpmyadmin のどちらでも開けることが多く、lower() を使わないと大文字のほうが素通りになる
  • starts_with(…, "/phpmyadmin"):
    パスが /phpmyadmin で始まる

はじめは、ほかと同じマネージドチャレンジにしていました。ところが、ルールの一覧でCSR(チャレンジを通過した割合)を見ると6.67%で、15件のうち1件は確認の画面を通過していました。チャレンジは人間なら通れるので、ログイン画面までは来られてしまいます。外から使うことはないので、ブロックに変えました。

ただし、ブログのデータが全部入っている場所なので、Cloudflareだけに頼るのはおすすめしません。私はサーバーのApacheの側でも、自宅のLANからしか開けないように制限しています。その手順は「phpMyAdmin インストールと Cloudflare 経由のアクセス制限」にまとめています。

守り方3:海外からのアクセスに確認の画面を出す

日本語のブログなら、読者はほぼ国内にいます。一方で、管理画面や設定ファイルを探すような機械的なアクセスは、海外から来ることが多くあります。そこで、日本以外からのアクセスで、トップページ以外を開こうとしたものにチャレンジをかける守り方です。

式の例です(アクションは「マネージドチャレンジ」)。

(ip.src.country ne "JP" and http.request.uri.path ne "/" and not cf.client.bot)
  • ip.src.country ne "JP":
    アクセス元の国が日本ではない
  • http.request.uri.path ne "/":
    パスがトップページではない
  • not cf.client.bot:
    Cloudflare が確かめた検索エンジンなどのロボット(確認済みのボット)ではない

注意点が2つあります。

  • 海外の読者にもチャレンジが出る:
    海外旅行中の人や、海外の VPN を使っている人は、記事を開くたびに確認の画面が出ます。日本語のブログなら影響は小さいと考えていますが、気になる場合は使わない選択もあります
  • 画像を配信しているサブドメインに注意:
    記事の中で、同じドメインのサブドメインから画像を読み込んでいる場合、海外の読者には画像が出なくなります。その場合は and http.host ne "img.example.com" のように、そのサブドメインを外す条件を足します

名前(User-Agent)で通す条件は入れない

はじめ、私はこの式に「User-Agent に Googlebot や Amazon などの名前が入っていたら通す」という条件を足していました。広告やアフィリエイトの審査のロボットが止まらないように、という念のためでした。

ところが、User-Agent は、アクセスする側が自分で名乗るだけの文字です。誰でも「Googlebot」と名乗れるので、この条件は名乗るだけで通れる抜け道になります。本物の検索エンジンのロボットは、not cf.client.bot(確認済みのボット)の判定で、名前ではなく Cloudflare の確かめで通るので、名前の条件は要りません。2026年10月に外しました。

この守り方を有効にしたきっかけ(広告のクリックの記録に、海外のサーバーからのクリックが混ざっていた件)は、「海外からのクリックを WAF で止めた記事」にまとめています。

検索エンジンを止めないために

守りを強くするほど、気になるのが検索エンジンのロボットです。止めてしまうと、記事が検索に出なくなります。

No.やり方考え
1「確認済みのボット」(cf.client.bot)で通すCloudflare が、本物の検索エンジンかを確かめてくれる。いちばん安心
2名前(User-Agent)で通す名乗るだけで通れるので、おすすめしない(上のとおり)
3ネットワークの番号(AS 番号)でまとめて通す会社のネットワーク全体を通すことになる。検索のロボットだけでなく、その会社のクラウドを借りた誰かのアクセスまで通ることがあるので、使うなら、管理画面などの守りたいパスには効かないように式を組む

もう1つ、数字を入れるルールは、保存したあとに「一致した件数」が増えているかを一度見ておくと安心です。私は以前、ルールの数字を1桁打ちまちがえていて、そのルールが一度も働いていなかったことがありました。件数が0のままだったことで気づきました。

Cloudflare が自動でかける盾(マネージドルール)

カスタムルールとは別に、Cloudflare は、大きな弱点が見つかったときに、その攻撃を止める「マネージドルール」を自動でかけることがあります。2026年10月には、PHP の弱点(通称 php2shell)が見つかり、このブログにも、それを止めるルールが自動でかかりました。

ただし、これは Cloudflare を通るアクセスだけを守る、一時的な盾です。サーバーの PHP そのものは弱いままなので、PHP の更新は別に行いました。WAF は入り口の見張りで、中身の更新の代わりにはなりません。

設定したあとの確認方法

ルールが効いているかは、自宅以外の回線から実際にアクセスして確かめます。スマホのモバイル回線(Wi-Fi を切った状態)や、自宅の外にあるサーバーなどから確かめると分かりやすいです。

1つ目は、ログイン画面にチャレンジがかかるかの確認です。

curl -sI https://example.com/wp-login.php | grep -iE "^HTTP|cf-mitigated"
  • curl -sI:
    ページを取りに行き、中身ではなく返事の見出し(ヘッダー)だけを出す
  • grep -iE "^HTTP|cf-mitigated":
    返事の番号の行と、Cloudflare が止めたことを表す cf-mitigated の行だけを出す

次のように 403 と cf-mitigated: challenge が出れば、チャレンジがかかっています(表示例)。

HTTP/2 403
cf-mitigated: challenge

2つ目は、admin-ajax.php が止められていないかの確認です。

curl -s -o /dev/null -w "%{http_code}\n" https://example.com/wp-admin/admin-ajax.php
  • -o /dev/null:
    中身は捨てる
  • -w "%{http_code}\n":
    返事の番号だけを出す

400 が出れば正常です。これは WordPress が「処理の指定がない」と返している状態で、Cloudflare には止められず、サーバーまで届いています。403 が出る場合は、admin-ajax.php の除外がうまく入っていません。

最後に、自宅のパソコンのブラウザで WordPress にログインして、チャレンジなしで管理画面に入れることも確かめます。

どのルールがどれだけ働いているかは、Cloudflare の「セキュリティ」→「イベント」(分析)で見られます。ルールごとに一致した件数が出るので、件数が0のままのルールは、条件の書きまちがいを疑ってみてください。

まとめ

No.守り方アクションポイント
1ログイン画面・管理画面マネージドチャレンジ/wp-login.php を忘れない。admin-ajax.php は外す。and と or の順番に気をつける
2phpMyAdmin などの管理ツールブロックlower() で大文字も対象に。サーバーの側でも制限する
3海外からのアクセスマネージドチャレンジ名前(User-Agent)で通す条件は入れない。検索エンジンは確認済みのボットの判定で通す

無料プランのカスタムルールだけでも、ログイン画面や管理ツールへの機械的なアクセスは、サーバーに届く前にかなり減らせます。ただし、WAF はあくまで入り口の見張りです。WordPress のパスワードを長く複雑にすることや、WordPress 本体・プラグイン・PHP の更新は、これまでどおり欠かせません。

また、ルールを強くしすぎると、読者や検索エンジンのロボットまで止めてしまいます。設定を変えたら、確認のコマンドとセキュリティイベントで、止めたいものだけが止まっているかを見ておくと安心です。

関連記事

コメント