Apache2には特定の条件に基づいて通信帯域を制限(スロットリング)する機能が備わっています。
「特定のユーザ」をどのように定義するか(IPアドレス、認証済みのユーザ名、あるいは特定のヘッダを持っているか)によっていくつか方法がありますが、現在最も標準的で扱いやすいのは mod_ratelimit モジュールを使用する方法です。
1. mod_ratelimit を使用する方法
このモジュールは、環境変数 rate-limit が設定されている場合に、そのリクエストの転送速度を制限します。
ステップ1: モジュールの有効化
まずはモジュールを有効にしてApacheを再起動します。
sudo a2enmod ratelimit
sudo systemctl restart apache2
ステップ2: 特定のユーザを識別して制限をかける
SetEnvIf や RewriteRule を組み合わせて、条件に一致した時だけ環境変数をセットします。
パターンA:特定のIPアドレスを制限する場合
# 192.168.1.100 からのアクセスを 500KB/s に制限
SetEnvIf Remote_Addr "192.168.1.100" rate-limit=500
パターンB:Basic認証の特定のユーザ名を制限する場合
# ユーザ名 "guest_user" の場合のみ 100KB/s に制限
SetEnvIf Remote_User "guest_user" rate-limit=100
パターンC:特定のUser-Agent(特定のブラウザやBot)を制限する場合
# 特定のBotからのアクセスを 50KB/s に制限
SetEnvIf User-Agent "BadBot" rate-limit=50
2. もっと細かく制御したい場合 (mod_bw)
mod_ratelimit はシンプルですが、複雑な制御(合計帯域の制限や、同時接続数に応じた動的な制限など)には不向きです。より高度な設定が必要な場合は mod_bw(Bandwidth Mod)という外部モジュールを使う伝統的な手法もありますが、設定がやや複雑になります。
3. アプリケーション層(PHP)で制御する場合
もし「特定のユーザ」の判定ロジックがデータベースに依存していたり、もっと柔軟に(例:FXツールのプレミアム会員は無制限、無料会員は制限など)制御したい場合は、Apacheではなく PHP側で読み込み速度をコントロール するのも一つの手です。
// 簡易的なスロットリング例
public function download($request, $response) {
$file = 'path/to/large_file.zip';
$speed = 100; // KB/s
$stream = fopen($file, 'rb');
while (!feof($stream)) {
echo fread($stream, $speed * 1024);
flush();
sleep(1); // 1秒待機して速度を調整
}
}
💡 運用のヒント
- 単位に注意:
mod_ratelimitの数値は KiB/s です。 - 測定方法: 制限が効いているか確認するには、クライアント側で
wgetやcurlを使ってダウンロード速度を表示させるのが確実です。Bashcurl -o /dev/null http://your-server.com/testfile - パフォーマンスへの影響: 大量の同時接続がある環境でPHP側でスロットリングを行うと、PHPのプロセス(Worker)を長時間占有してしまうため、基本的には Apache(mod_ratelimit)で行うのが最も効率的 です。

コメント