💡 Tips

Cloudflare WorkersでAPIをレート制限する方法|標準Rate Limiting APIとKV自前実装を比較【個人開発2025】

結論:個人開発なら標準のRate Limiting APIから始める

個人開発のAPIを不正アクセスや過剰リクエストから守るなら、まずCloudflare Workers標準の「Rate Limiting API(RATELIMITバインディング)」を使うのが最短ルートだ。

  • 追加のストレージ設計が不要
  • 数行のコードで導入できる
  • KVより低レイテンシで判定できる

一方で、ユーザー単位の複雑な制御(プラン別の上限、月次カウントなど)が必要になったらKVやDurable Objectsでの自前実装に切り替える、という段階的な判断が現実的だ。料金プランや制限値の詳細は変わりやすいため、実装前に必ず公式ドキュメントの最新情報を確認してほしい。

なぜAPIにレート制限が必要なのか

個人開発のAPIでよくある被害は以下の3パターンだ。

  1. スクレイピングボットによる連続リクエストで無料枠の呼び出し回数を消費される
  2. 総当たり攻撃(ブルートフォース)でログインAPIが叩かれる
  3. フロントのバグや無限ループで自分自身が意図せず高頻度リクエストを送ってしまう

Cloudflare Workersは従量課金のため、放置すると想定外の請求につながるリスクもある。実装コストが低いうちに最低限の防御を入れておく価値は大きい。

方式比較:標準Rate Limiting API vs KV自前実装

項目標準Rate Limiting APIKV自前実装
実装コスト低い(数行)中〜高(カウント設計が必要)
判定単位IPやカスタムキーで固定窓任意のキー・任意のロジック
精度おおよその制限(内部実装は非公開)自分で厳密に制御可能
追加費用wrangler.tomlの設定のみKV書き込み回数分の課金対象
ユーザー別プラン対応不向き対応しやすい
おすすめ用途単純な流量制限・簡易DoS対策課金プラン別の上限管理など

標準APIは「大まかに間引く」ためのもの、KV実装は「厳密に数える」ためのもの、と役割で分けて考えるとわかりやすい。

手順1:標準Rate Limiting APIを設定する

まずwrangler.toml(またはwrangler.jsonc)にバインディングを追加する。

[[unsafe.bindings]]
name = "RATELIMIT"
type = "ratelimit"
namespace_id = "1001"
simple = { limit = 100, period = 60 }

limitとperiodの単位や設定方法はベータ機能として変更が入りやすいため、導入時は公式の最新の構文を必ず確認すること。

Workers側の実装例は次のようになる。

export interface Env {
  RATELIMIT: RateLimit;
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const ip = request.headers.get("CF-Connecting-IP") ?? "unknown";
    const { success } = await env.RATELIMIT.limit({ key: ip });

    if (!success) {
      return new Response("Too Many Requests", { status: 429 });
    }

    return new Response("OK");
  },
};

IPだけでなく、APIキーやユーザーIDをkeyに渡せば、エンドポイントごと・利用者ごとの制限にも応用できる。

手順2:KVでプラン別の制限を自前実装する

「無料プランは1日100回まで」のような要件が出てきたら、KVでカウンタを持つ実装に切り替える。

async function checkRateLimit(env: Env, userId: string, limit: number): Promise<boolean> {
  const key = `ratelimit:${userId}:${new Date().toISOString().slice(0, 10)}`;
  const current = await env.RATE_KV.get(key);
  const count = current ? parseInt(current, 10) : 0;

  if (count >= limit) {
    return false;
  }

  await env.RATE_KV.put(key, String(count + 1), { expirationTtl: 60 * 60 * 24 });
  return true;
}

注意点は2つある。

  • KVは結果整合性のストレージのため、同時多発リクエストではカウントに多少のズレが出る。厳密な排他制御が必要ならDurable Objectsの検討が必要
  • 書き込みごとに課金が発生するため、リクエスト頻度が高いAPIではコストを試算してから採用する

個人開発の範囲であれば、多少のズレは許容してKVで十分なケースが多い。コスト試算の考え方はCloudflare Workers無料枠のコストシミュレーションも参考になる。

個人開発API向けの最小構成

結論として、次の組み合わせが多くの個人開発案件に合う。

  1. 全エンドポイント共通でIPベースの標準Rate Limiting APIをかける(DoS的な流量を粗く間引く)
  2. ログインなど重要エンドポイントだけKVで厳密なカウントを追加する
  3. 429を返したらRetry-Afterヘッダーを付けてクライアント側の再試行を制御する
return new Response("Too Many Requests", {
  status: 429,
  headers: { "Retry-After": "60" },
});

いきなり複雑な設計を作り込まず、まず標準APIで粗い防御を敷き、必要になった箇所だけKVで補強する順序がコストと開発時間のバランスがいい。

まとめ

  • 個人開発APIの防御は、まず標準Rate Limiting APIで粗く間引く
  • プラン別上限などの厳密な制御はKVで補う(コストと整合性の注意点あり)
  • 制限値・料金・API仕様は変更が入りやすいため、実装前後で公式の最新情報を確認する習慣をつける

ログの監視まで含めて自動化したい場合は、Cloudflare Workersのログ監視・エラー通知もあわせて整備すると、レート制限をすり抜けた異常アクセスにも気づきやすくなる。