說明

本篇文章介紹 Nginx 的限制連線數模組 ngx_http_limit_conn_module,說明可用指令和基本範例。限制連線數通常用來防止 DDOS 等惡意攻擊,該模組有以下指令:

  • limit_conn_zone
  • limit_conn
  • limit_conn_dry_run
  • limit_conn_log_level
  • limit_conn_status

指令

limit_conn_zone

標題內容
語法limit_conn_zone key zone=name:size;
預設值-
Contexthttp

這個指令是定義規則,相關的參數如下

  • key:可以視為符合的條件,例如照 IP、Server Name 或國家等等不同條件,參考最後的範例。
  • name:唯一名稱。
  • size:配置多少記憶體。

簡單的例子

1
limit_conn_zone $binary_remote_addr zone=perip:10m;

limit_conn

標題內容
語法limit_conn zone number;
預設值-
Contexthttp, server, location

設定連線數,相關的參數如下

  • zone:limit_conn_zone 自訂的名稱
  • number:連線數

limit_conn_dry_run

標題內容
語法limit_conn_dry_run on | off;
預設值off
Contexthttp, server, location

測試模式,可以在 log 中看到規則生效的訊息,但實際上不會真的擋掉連線。Log 大概如下:

1
2024/06/20 14:44:32 [error] 2473#2473: *8287599 limiting connections, dry run, by zone "perip", client: 123.123.123.123, server: example.com, request: "GET /mypath HTTP/1.1", host: "example.com"

會看到有 dry run 的字樣。

limit_conn_log_level

標題內容
語法limit_conn_log_level info | notice | warn | error;
預設值error
Contexthttp, server, location

設定限制連線相關 Log 的等級,相關 log 都會輸出到 error.log 中。由於預設 error.log 只記錄 error 等級,所以這邊如果改成 warn 的話預設會看不到。要搭配修改 error_log,例如:

1
2
3
error_log /var/log/nginx/error.log warn;

limit_conn_log_level warn;

就會看到相關 log 變成 warn

1
2024/06/20 14:44:32 [warn] 2473#2473: *8287599 limiting connections, ...

limit_conn_status

標題內容
語法limit_conn_status code
預設值503
Contexthttp, server, location

設定限制連線發生時回應的 HTTP Status Code。只能設定 400 - 599 之間。否則會看到下面錯誤:

1
nginx: [emerg] value must be between 400 and 599 in /etc/nginx/sites-enabled/example:16

範例

限制 IP

每個 IP 10 個連線

1
2
3
4
5
limit_conn_zone $binary_remote_addr zone=perip:10m;

server {
limit_conn perip 10;
}

限制 Server Name

每個 Server name 100 個連線

1
2
3
4
5
limit_conn_zone $server_name zone=perserver:10m;

server {
limit_conn perserver 100;
}

特定 Path

一次只能下載一個,可巢狀

1
2
3
4
5
6
7
server {
limit_conn perip 10;

location /download/ {
limit_conn perip 1;
}
}

限制 Socket 連線數,例如 ActionCable:

1
2
3
4
5
6
7
server {
location /cable {
passenger_app_group_name my_action_cable_group_name;
passenger_force_max_concurrent_requests_per_process 0;
limit_conn perip 10;
}
}

多重條件

可同時多組

1
2
3
4
server {
limit_conn perip 10;
limit_conn perserver 100;
}

白名單 / 黑名單

limit_conn 不能用在 if 下,也不能用變數,沒辦法直接做出不同 IP 給不同連線數的設定。但 limit_conn_zone 可以用變數,下面的寫法為指定 IP 為白名單,不限制連線:

1
2
3
4
5
6
7
8
9
10
map $remote_addr $not_whitelist {
default $binary_remote_addr;
123.123.123.123 '';
}

limit_conn_zone $not_whitelist zone=not_whitelist:10m;

server {
limit_conn not_whitelist 10;
}

利用這個機制可以做出不同 IP 不同連線:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
map $remote_addr $not_whitelist {
default $binary_remote_addr;
123.123.123.123 '';
}
map $remote_addr $whitelist {
default '';
123.123.123.123 $binary_remote_addr;
}

limit_conn_zone $not_whitelist zone=not_whitelist:10m;
limit_conn_zone $whitelist zone=whitelist:10m;

server {
limit_conn not_whitelist 10;
limit_conn whitelist 100;
}

反過來用也可以作為黑名單使用。

設定建議

建議可以限制 WebSocket 和下載等,會長時間連線的地方,避免被惡意地佔滿連線。連線數上限可參考 Rails ActionCable 效能測試

延伸閱讀

Nginx 限制請求速率 (ngx_http_limit_req_module)
Rails ActionCable 效能測試