PV暴走の犯人は“無限URL”だった:おみくじ実験でボットを炙り出して止血した話(読み物+開発メモ)

PV暴走の犯人は“無限URL”だった:おみくじ実験でボットを炙り出して止血した話
(読み物トーン+開発メモトーンを1本に合体)

「PVが100万超え?」と笑っていたのに、ログを見ると笑えない量のアクセスが……。 本記事は、試験的に始めたおみくじページ(/rese-deve-omikuji)で起きた“PV暴走”を、GSCでは見えない領域まで掘って止血対策した記録です。
※Cloudflare導入は次章(導入前に区切りとしてこの記事を残す)。


ないしょ(秘密の履歴) (クリックで開閉)

状況:Live PVでおみくじ系の数字が異常に跳ねた。

観測:日付が変わって約2時間で A:168 / C:293 まで減少(効いてるが、まだ多い気もする)。

学び:GSCのクロール統計が落ち着いて見えても、“PV暴走の犯人”がGoogleとは限らない。

読み物トーン:未知の世界を征服したい

ある日、Live PVを見ていると「ん?」となる数値が出た。 おみくじは試験的に始めたページのはず。人気爆発する理由が薄い。 でも数字は跳ねる。しかも、GSCのクロール統計を見ると「落ち着いてるようにも見える」。

ここで考えられる対応を二択に絞る。 「試験ページだし消して終わり」にするか。 それとも「未知の世界を征服する」方向へ踏み込むか。 ……自分は後者が好きだ。

そして“征服”の入口は、いつも地味だ。 派手なダッシュボードより先に、access_log を開く。 そこには、PVグラフでは見えない真実が並んでいた。

叩かれていたのは、ほぼ1点。 /rese-deve-omikuji。 しかも、クエリが付いた無数のURL。 つまり「ページが人気」ではなく、URLが無限に増える構造が“燃料”になっていた。

対策は、派手な魔法じゃない。 “増殖するURL”をやめる。 “過去にばら撒かれたURL”は、301で吸収する。 それだけで世界が静かになる。 (ついでにCloudflare株を1株買った。これは物語として面白い。※投資助言ではない)

まだ戦いは終わっていない。 今度の相手は、クエリ無しの素URLを叩く分散ボット。 だから次章はCloudflare。 でも、ここまででPV暴走の物語を一度区切る。ここまででも“学び”は十分に濃いから。 途中放置とはいえ数か月を経過してしまった。AIが出した成果物が一発で成功する開発方法の教訓となった。


開発メモトーン:原因特定→止血→確認手順

1) 症状

  • Live PVで、おみくじ系が不自然に増える(“暴走っぽい”)。
  • GSCのクロール統計は落ち着いて見える日もあり、原因が見えにくい。

2) 原因の型(今回の核心)

「URLが無限に増殖する仕組み」があると、ボット/クローラが燃料にして暴走する。 典型例は ?reroll=time() のように、アクセスのたびに別URLを生成するパターン。

3) 解析:見るべきはGSCより access_log

  • 上位パス:特定の1URL/1パスに偏っていないか
  • クエリ有無reroll= / choice= が大量に出ていないか
  • ステータス200(正常) が大量か、301(恒久リダイレクト)/302(一時リダイレクト)に吸収できているか
  • Referer- だらけなら人間導線ではない可能性が高い
  • User-Agent:ボット系が上位に並ぶ(偽装UAも混ざる)

HTTPステータス(ログで見る数字)の意味

  • 200 OK:正常にページを返した(=サーバが“成功”として処理した)
  • 301 Moved Permanently:恒久リダイレクト(URLを“正しい場所に一本化”できる)
  • 302 Found:一時リダイレクト(処理後に元URLへ戻す、Cookie保存後の戻しなどに使う)
  • 304 Not Modified:キャッシュが有効で再取得不要(コンテンツを返さず軽く済む)
  • 403 Forbidden:拒否(WAFやルールでブロックされると出やすい)
  • 404 Not Found:存在しない(リンク切れ/削除など)
  • 429 Too Many Requests:アクセス過多(レート制限)
  • 5xx(例:503):サーバ側エラー(高負荷・一時障害など)

ざっくり言うと、“200が大量”=オリジンが仕事をしてしまっている“301が増える”=吸収に成功している、という見方ができる。

4) 止血(アプリ側でできる最小セット)

  1. GETのrerollを廃止:リロールはPOST化(URLを増やさない)。
  2. 過去URLの回収?reroll= が来たら 301でクエリ無しへ吸収(本丸)。
  3. choiceも吸収?choice= はCookie保存→ 302でクエリ無しへ
  4. nofollow:choiceリンクに rel="nofollow" を付与(保険)。

5) すぐできる確認方法(最短で勝ち判定)

  • ブラウザ直打ち:
    • /rese-deve-omikuji?reroll=123301でクエリ無しへ戻る
    • /rese-deve-omikuji?choice=先に連絡する302でクエリ無しへ戻り、選択はページ上に反映(Cookie)
  • ログ判定:
    • ?reroll=200が消えて301が増える
    • 素URL(クエリ無し)の200がまだ多いなら、次章(Cloudflare)で入口対策
  • Live PV判定(体感):
    • 日付変わって2時間で A/C が大きく減るなど、明らかな“落ち”が出る
    • ただし“まだ多い”場合は、素URLへの分散ボットが残っている可能性が高い

ページが動く=OKではなく、過去に拡散したクエリURLが 301/302で吸収されることを確認すると勝ち

6) 得られた教訓(再利用できる型)

  • GSCは万能じゃない:Google以外の巡回/ボットは別で動く。
  • 増殖URLは敵の燃料:まず“URLが増えない設計”へ寄せる。
  • 過去にばら撒かれたURLは301で回収:放置すると永遠に叩かれる。
  • 入口対策はCloudflareが強い:分散IP相手はオリジンで殴り合うとつらい。

次回予告:Cloudflareで“入口”を守る

今回の止血で「無限URL増殖」は抑えられた。 ただし、クエリ無しの素URLを叩く分散ボットが残る場合がある。 そこで次回はCloudflareを導入して、 /rese-deve-omikujiManaged Challenge/JS Challenge で守り、 オリジンに届く200をどこまで落とせるかを検証する。

※Cloudflare導入は、お名前.comレンタルサーバー/ドメイン側の設定変更を伴うため、ここで一度区切って記事化。


最終更新: 2026-01-09

決済はStripeで安全に処理されます。
Amazonで「url・クエリ」を検索
Amazonで探す

この記事の感想をこっそり教えてください(非公開)