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) 止血(アプリ側でできる最小セット)
- GETのrerollを廃止:リロールはPOST化(URLを増やさない)。
- 過去URLの回収:
?reroll=が来たら 301でクエリ無しへ吸収(本丸)。 - choiceも吸収:
?choice=はCookie保存→ 302でクエリ無しへ。 - nofollow:choiceリンクに
rel="nofollow"を付与(保険)。
5) すぐできる確認方法(最短で勝ち判定)
-
ブラウザ直打ち:
/rese-deve-omikuji?reroll=123→ 301でクエリ無しへ戻る/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-omikuji を Managed Challenge/JS Challenge で守り、
オリジンに届く200をどこまで落とせるかを検証する。
※Cloudflare導入は、お名前.comレンタルサーバー/ドメイン側の設定変更を伴うため、ここで一度区切って記事化。
