投稿

iptables の hashlimit で HTTP DDoS を IP 単位にレート制限する

iptables の hashlimit で HTTP DDoS を IP 単位にレート制限する

⚠️ これはメモ書きです iptables / netfilter / hashlimit の挙動を完全に理解した上で書いた記事ではなく、自宅で食らった時に動いた設定を後追いで整理しただけのもの。 各オプションの意味は man と AI 説明に頼っていて、自分の中で「腹落ちした」状態には至っていない。 同じ状況で困っている人の取っ掛かりにはなるかもしれないが、本番投入する前に man と他の解説記事で必ず裏取りしてほしい。

まとめ

  • iptables の hashlimit モジュールで、送信元 IP ごとに独立したトークンバケットを持たせて HTTP/HTTPS をレート制限できる
  • ユーザー定義チェーンに「正常レートなら RETURN」「超過したら DROP」を 2 段で組むのが定番形
  • --hashlimit-burst を 100 くらい残しておくと、ブラウザの並列リクエストを潰さずに済む

想定するケース

自宅サーバや小規模 VPS の 80/443 に、じわじわ高頻度のリクエストが来ている。CDN や WAF を挟まずに、iptables だけで送信元 IP ごとのレート制限をかけたい。自宅で実際に食らった時にこの形で凌いだので、その手順をまとめる。

完成形

# 1. チェーン作成
iptables -N HTTP_DDOS

# 2. 正常レートの範囲内なら戻す
iptables -A HTTP_DDOS -p tcp -m multiport --dports 80,443 \
  -m hashlimit \
  --hashlimit 1/s \
  --hashlimit-burst 100 \
  --hashlimit-htable-expire 300000 \
  --hashlimit-mode srcip \
  --hashlimit-name t_HTTP_DDOS \
  -j RETURN

# 3. 超過分はログを残して落とす
iptables -A HTTP_DDOS -j LOG --log-prefix "HTTP_DDOS_DROP: " --log-level 4
iptables -A HTTP_DDOS -j DROP

# 4. INPUT から飛ばす
iptables -I INPUT -p tcp -m multiport --dports 80,443 -j HTTP_DDOS

各オプションの意味

マッチ条件

オプション 意味
-A HTTP_DDOS HTTP_DDOS チェーンの末尾に追加
-p tcp -m multiport --dports 80,443 TCP の宛先ポート 80 または 443

hashlimit パラメータ

hashlimit は標準の limit モジュールの上位版で、キーごとに独立したトークンバケットを持てる。

オプション 意味
--hashlimit 1/s バケットの補充レート。1 秒あたり 1 トークン
--hashlimit-burst 100 バケットの最大容量。100 トークンまで貯められる
--hashlimit-mode srcip 集計のキー。送信元 IP ごとに独立したバケットを持つ
--hashlimit-name t_HTTP_DDOS /proc/net/ipt_hashlimit/t_HTTP_DDOS で覗ける名前
--hashlimit-htable-expire 300000 300,000 ms = 5 分アイドルした IP のエントリを破棄

アクション

-j RETURN で、マッチしたパケット(=バケットにトークン残あり)は呼び出し元チェーンに戻る。落とすのは末尾の -j DROP に任せる。

動作イメージ

ある送信元 IP から HTTP パケットが届くと:

  1. その IP 用のバケット(容量 100、補充 1/s)を引く
  2. トークン残あり → -j RETURN でチェーンを抜けて通常処理へ
  3. トークン枯渇 → このルールにマッチしないので次のルール(LOG → DROP)に進む

なぜ burst を 100 にするのか

1/s だけだと「ブラウザが画像 10 個を並列に取りに行く」場面で即 DROP される。burst 100 は「平常時は 1 秒 1 リクエストで補充するけど、瞬間的には 100 まで貯められる」という意味。

つまり

  • ブラウザの並列読み込み → バースト枠でこなす
  • 持続的に毎秒数十リクエスト → 補充が追いつかず DROP

という棲み分けになる。実トラフィックに合わせて 50〜200 で調整する。自分の場合は 100 で実用上困らなかった。

動いているか確認する

/proc/net/ipt_hashlimit/t_HTTP_DDOS を見ると、現在保持されている IP ごとのトークン残量・最終アクセス時刻が確認できる。「特定の IP がブロックされ続けているか」を知りたい時はここが速い。

DROP 数は iptables -L HTTP_DDOS -v -n でルールごとのカウンタが取れる。

落とし穴

  • RETURN だけ書いて DROP を書き忘れると、超過パケットも結局チェーン末尾の暗黙 RETURN で抜けて通常処理に進んでしまう。これだとレート制限が効かない
  • IPv6 で HTTP を受けている環境では ip6tables 側にも同じ設定が要る
  • IP 単位の制限なので、NAT 配下の大規模ユーザー(モバイルキャリアや学校・企業)を巻き込んで巻き添え DROP する可能性がある。CDN 越しだと送信元 IP は CDN のものになるので、この設定はオリジンサーバ直撃のケース向き

トレンドのタグ