AIボットによる負荷を観測して対策を選ぶ

クロール制御の対象を分ける。目的を決める:検索・学習・利用者操作を区別、対象サービスの公式説明を確認する。制御方法を選ぶ:robots.txtや検証済みボットのルール、自己申告のUser-Agentだけに頼らない。影響を確認:必要なアクセスまで止めていないか、ログと公式仕様の変更を確認する
robots.txtはアクセス制御ではない。識別子の偽装も可能。

AIボットを含むアクセスがWorkersやオリジンの負荷になるかは、配信方式、プラン、リクエスト経路で異なる。まずAnalyticsと利用量を確認し、観測した負荷に応じて対策を選ぶ。

Meta、OpenAI、ByteDance(TikTok)、Perplexityといった企業は、自社のAIモデルの学習・改善のため、インターネット上の膨大なページを収集しています。厄介なのは、これらのボットがサーバーレス環境のリクエスト課金を全く気にせず、無制限にアクセスを繰り返すことです。

Workersの上限・超過時動作・課金はプランと時点で変わる。公式料金表とアカウントの利用量を確認し、固定のリクエスト数や費用を前提にしない。

対策を講じる上で、絶対に避けるべきはGooglebotやBingbotまで巻き込んでブロックすることです。検索エンジンのクローラーを締め出すと、サイトがインデックスから外れ、オーガニックトラフィックがゼロになるという致命的な事態を招きかねません。今回ご紹介する4つの対策はすべて、「AI学習ボットだけを効率的に弾き、検索エンジンは素通りさせる」ことを主眼に置いています。これらは負荷低減の選択肢であり、アクセス遮断や課金回避を保証しない。

対策1(最も効果的): 静的ページをprerender化してWorkersを呼ばせない

コスト削減の観点から言えば、そもそもWorkersが呼ばれなければコストは発生しない、というのが最も抜本的な解決策と言えるでしょう。

Astro 4.0以降のoutput: "server"モードにおいても、ページ単位でexport const prerender = trueを設定することで、そのページはビルド時に静的HTMLとして生成され、Cloudflare CDNから直接配信されます。データベースやユーザー情報を参照しないランディングページ、ブログ記事、法務ページ(プライバシーポリシーなど)は、すべてこの方法で対応可能です。

---
// src/pages/index.astro (Astro 4.0以降)
export const prerender = true;
import Base from "../layouts/Base.astro";
---

<Base title="トップページ">
  
  
</Base>

ユーザーログインやデータベース参照が必要な動的ページ(マイページ、APIなど)はSSRのままにし、そこには次の対策を適用します。

対策2: middlewareでUser-Agentをチェックし、即座に403を返却

SSRが必要なページへのボットアクセスに対しては、サーバー側で弾くのが極めて有効な手段となります。Astro + Cloudflare Workersの構成であれば、src/middleware.tsにわずか数行追加するだけで対応できます。

// src/middleware.ts
import type { MiddlewareHandler } from "astro";

// AI学習・大量クロールボット(Googlebot・Bingbotは含めない)
// ※一部User-Agentは公式には公開されていませんが、観測されているものをリストアップしています。
const AI_TRAINING_BOTS = [
  "GPTBot", "ChatGPT-User", "OAI-SearchBot",   // OpenAI
  "CCBot", "ClaudeBot", "Anthropic-AI",        // Anthropic (CCBotはCommon Crawl、Anthropicも利用)
  "Meta-ExternalAgent", "Meta-ExternalFetcher", // Meta
  "Bytespider",    // ByteDance(TikTok)
  "Amazonbot",     // Amazon(大量クロール目的)
  "cohere-ai",     // Cohere
  "PerplexityBot", // Perplexity
  "YouBot",        // You.com
  "Diffbot",       // Diffbot
  "Omgili",        // Webz.io
];

export const onRequest: MiddlewareHandler = async (context, next) => {
  const ua = context.request.headers.get("user-agent") ?? "";

  if (AI_TRAINING_BOTS.some((bot) => ua.toLowerCase().includes(bot.toLowerCase()))) {
    // Workersが呼ばれた瞬間に即返す
    return new Response("Forbidden", { status: 403 });
  }

  return next();
};

⚠️ 大文字・小文字の区別に注意

ua.includes(bot) は大文字小文字を区別するため、User-Agentが小文字で送信されるボットは素通りします。ua.toLowerCase().includes(bot.toLowerCase()) を使うことで、表記ゆれを減らせるが、User-Agentの偽装や未登録のボットは防げない。

肝となるのは「Workersが呼ばれた瞬間に即返す」という点です。データベースクエリや重い処理に到達する前に403を返すため、後続のアプリ処理を避けられる可能性はあるが、Workersへの到達と利用量の扱いはプラン・経路で確認する。

なお、prerender化された静的ページはCDNから直接配信されるため、このmiddlewareは動作しません(そもそもWorkersが起動しないため、この対策は不要です)。

対策3: robots.txtに主要AIボットを列挙する

robots.txtへの追記は、ルールを遵守するボットであればここでアクセスを止めるという「第一の関門」です。middlewareと組み合わせることで、robots.txtを遵守するボットとしないボットの両方をカバーできます。

User-agent: *
Disallow: /api/


User-agent: GPTBot
Disallow: /

User-agent: ChatGPT-User
Disallow: /

User-agent: Meta-ExternalAgent
Disallow: /

User-agent: Meta-ExternalFetcher
Disallow: /

User-agent: Bytespider
Disallow: /

User-agent: ClaudeBot
Disallow: /

User-agent: CCBot
Disallow: /

User-agent: Anthropic-AI
Disallow: /

User-agent: PerplexityBot
Disallow: /

User-agent: Amazonbot
Disallow: /

User-agent: cohere-ai
Disallow: /

User-agent: YouBot
Disallow: /

User-agent: Diffbot
Disallow: /

注意点:robots.txtはあくまで「紳士協定」に過ぎず、悪意あるボットはこれを無視します。それでもGoogle、OpenAI、Anthropicなどのrobots.txtを尊重するボットには意思を伝えられるが、遵守は各クローラーの実装に委ねられる。

対策4(番外): Cloudflare Bot Fight Mode

前提:カスタムドメインをCloudflareに接続している場合のみ有効です。 *.pages.devのようなCloudflareのサブドメインだけを使っている段階では利用できません。

ドメインを取得してCloudflareに設定すると、ダッシュボードのSecurity → Bots → Bot Fight Modeをオンにするだけで、CDN層(Workersより手前)で既知のボットをブロックできます。コード変更は不要で、利用可否はプラン・契約・設定で変わるため、Cloudflareの現行ドキュメントで確認する。

ただし、ごく稀にGooglebotを巻き込んでしまうといった事象も確認されています(Cloudflareコミュニティでの議論例)。有効化後は、Google Search Consoleでクロールエラーを1週間ほど確認し、問題がないか慎重に監視することをおすすめします。

対策が効いているか確認する方法

実装後に「本当にボットを弾けているか」を確認するには、以下の方法が手軽に実施できます。

  1. ローカルからのUser-Agent偽装リクエスト:

    # AIボットのUser-Agentを偽装してリクエスト
    curl -A "GPTBot/1.1" https://your-app.pages.dev/
    
    # 期待するレスポンス: HTTP 403 Forbidden
    

    このコマンドで403が返ってくれば、middlewareが正しく機能している証拠です。

  2. Cloudflareダッシュボードでのリクエスト数確認:
    CloudflareダッシュボードのAnalytics → Workersでリクエスト数の推移を確認できます。対策前後でリクエスト数が明確に減っていれば、ボットがブロックされていることの間接的な証拠になります。例えば、対策後にリクエスト数が80%削減されたといった具体的な数値が見られれば、その効果は絶大です。

  3. Google Search Consoleでのクロール統計確認:
    Googlebotが正常にクロールできているかは、Google Search Console → インデックス → クロール統計で確認できます。ボットブロックの実装直後は、ここを数日見てクロールエラーが急増していないか確認するのが安全です。

この構成で対応できないボットもある

正直なところ、User-Agentを偽装する悪意あるボットを完全に防ぎきることは困難です。middlewareのUser-Agentチェックは「正直に名乗っているボット」しか止められません。

それでも、Meta、OpenAI、Bytespiderなど、大量クロールを引き起こしている主要なAI学習ボットのほとんどは、robots.txtとUser-Agentベースのブロックを守る傾向があります(学習データ収集ボットとしての信用維持が動機の一つと考えられます)。

完全に防ぎたい場合は、Cloudflare WAFのカスタムルール(有料プランが必要)やCloudflare Rate Limitingも選択肢になります。しかし、個人や副業レベルのサービスでそこまで必要になることは稀で、必要な対策は実際のアクセス、脅威、契約プランに応じて判断する。

優先順位のつけ方

すべてを一気に実装する必要はありません。段階的に進めるなら、コストとリターンのバランスを考慮して、この順で着手するとよいでしょう。

  1. robots.txt(所要時間: 5分): 最も低コストで、大手ボットが準拠するなら即効性が期待できます。
  2. prerender化(所要時間: 30分〜): 静的ページが多いサービスほど効果が大きく、SSRコストも根本的に削減できます。
  3. middleware User-Agentブロック(所要時間: 15分): コード追加だけでSSRページへのボットアクセスを効率的に封じられます。
  4. Bot Fight Mode(所要時間: 5分 / ドメイン必要): カスタムドメインを取得したタイミングで有効化すると良いでしょう。

まとめ:3つのコード対策 + 1つのダッシュボード設定

対策 対象 効果 SEOリスク
prerender化 静的ページ Workersコストをゼロに なし(高速化で有利)
middleware UAブロック SSRページ 403で即返す なし(検索エンジン除外)
robots.txt 全ページ 大手ボットが準拠 なし
Bot Fight Mode 全ページ(ドメイン必要) CDN層で遮断 要 Search Console監視

※静的ページはmiddlewareを経由しないため、UAブロックは効きません。

これら3つのコード対策をセットで実装しておけば、カスタムドメインなしでも今ある主要なAI学習ボットの大部分をカバーできます。副業でサーバーレスサービスを動かしているなら、次のアクションとしてまずrobots.txtから着手されることを強くお勧めします。わずか5分でできる割に、その効果は確実です。