這裡介紹如何設定 NGINX 網頁伺服器,加上密碼認證與限制可存取的 IP 位址,並控制頻寬與連線數。

在 NGINX 伺服器中若要限制只有特定的使用者可以瀏覽網頁的話,可以使用帳號與密碼認證的方式,或是設定可存取網頁的來源 IP 位址,以下是設定的步驟教學。

NGINX 帳號與密碼認證

auth_basic 可以啟用 HTTP Basic Authentication,讓使用者透過帳號與密碼進行認證,而儲存帳號與密碼的檔案則是使用 auth_basic_user_file 來指定:

location / {
  auth_basic           "closed site";
  auth_basic_user_file conf/htpasswd;
}

auth_basic_user_file 所指定的帳號與密碼檔案格式如下:

# 這是註解
name1:password1
name2:password2:這是註解
name3:password3

而密碼的部分要先經過編碼,可以使用 Apache 所提供的 htpasswd 指令來產生,或是使用 openssl

openssl passwd

執行這行指令之後,再輸入兩次要設定的密碼,就會產生經過編碼的密碼,例如 12345 經過編碼後會像這樣:

A5F0pZqTMG1ks

再把這個經過編碼的密碼放進帳號與密碼的檔案中,

gtwang:A5F0pZqTMG1ks

這樣就新增了一個 gtwang 帳號,而密碼為 12345

如果要整個網站都受到帳號與密碼的保護,但開放一些特定目錄可以不需要帳號與密碼,則可以在不需要帳號與密碼的路徑中把 auth_basic 設定為 off

server {
  auth_basic "closed website";
  auth_basic_user_file conf/htpasswd;

  location /public/ {
      auth_basic off;
  }
}

這樣使用者在瀏覽所有 /public/ 之下的網頁都不需要輸入帳號與密碼。

NGINX 限制可存取的 IP 位址

allowdeny 可以設定允許與禁止存取網頁的來源 IP 位址,設定的方式跟 Apache 一樣,列在上方的規則會優先執行:

location / {
  deny  192.168.1.2;
  allow 192.168.1.1/24;
  allow 127.0.0.1;
  deny  all;
}

這樣的設定會禁止 192.168.1.2 這個來源 IP 位址存取網頁,並允許其它所有 192.168.1.1/24 網段的 IP 位址的存取,另外也允許本機(127.0.0.1)存取,除了上述的來源之外,一律禁止存取。

除了 IPv4 之外,也可以使用 IPv6,用法皆相同:

location / {
  deny  192.168.1.1;
  allow 192.168.1.0/24;
  allow 10.1.1.0/16;
  allow 2001:0db8::/32;
  deny  all;
}

接下來要介紹 NGINX 的頻寬與連線數控制,請繼續閱讀下一頁。

NGINX 頻寬與連線數控制

對於負載量比較高的伺服器,可以設定每一位使用者可使用的資源上限,例如同時間最大連線數、連線頻率(每秒或每分鐘連線次數)以及下載速度。

同時間最大連線數

若要限制同時間最大連線數,首先要使用 limit_conn_zone 定義一個 key 與 zone 參數:

limit_conn_zone $binary_remote_addr zone=addr:10m;

這裡定義一個名為 addr 的 zone,空間大小是 10MB,worker 行程會使用這個 zone 所配置的共享記憶體空間來儲存 key 的計數值。這裡的我們使用 $binary_remote_addr 來作為判斷來源 IP 的依據(key),會使用這個二進位的變數來作為 key 是因為它跟一般的字串比起來,會比較省空間,如果 zone 所配置的共享記憶體空間用完了,那伺服器就會回傳 503(Service Temporarily Unavailable)的錯誤訊息。

接著再使用 limit_conn 指定一個 IP 同時間可以允許的最大連線數:

location /download/ {
  limit_conn addr 1;
}

以上的設定只有對於來源 IP 做限制,如果要設定整台伺服器所有連線的上限值,可以這樣設定:

http {
  limit_conn_zone $server_name zone=server:10m;

  server {
    limit_conn server 1000;
  }
}

這樣就可以把伺服器同時能夠接受的連線數上限設定為 1000

由於在 NAT 之內的所有設備會共享一個對外 IP 位址,若以 IP 位址限制使用資源的方式,會造成 NAT 之下的所有設備共享單一 IP 位址的資源限制,這一點在制定規則時需要納入考慮。

連線頻率

若要限制連線頻率,首先也是一樣要用 limit_req_zone 定義 key 與 zone 參數:

limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;

這裡除了定義 zone 的名稱與大小之外,還加上了一個 rate 指定連線頻率的上限,單位可以使用每秒的連線次數(r/s)或是每分鐘的連線次數(r/m),例如若要指定每分鐘不可超過 30 次連線,則設定為 30r/m

然後在需要限制連線頻率的地方加上 limit_req 的設定:

location /search/ {
  limit_req zone=one burst=5;
}

這裡的 zone 就指定成剛剛上面定義的 zone 名稱,如果使用者所發出的連線頻率超過上限時,多出來的連線會先被放在伺服器的佇列中,等候一小段時間之後再處理,維持整體的連線頻率不會超過設定的上限,而 burst 參數是設定這個佇列的長度,如果連線數多到連佇列都放不下時,就會產生 503 的錯誤。

如果不想讓放在佇列中的請求延遲處理,可以加上 nodelay

limit_req zone=one burst=5 nodelay;

下載速度

若要限制每個連線的頻寬,可以使用 limit_rate

location /download/ {
  limit_rate 50k;
}

在這樣的設定之下,每一個連線的下載速度最高不可超過每秒 50KB,但一個使用者可以同時開啟多條連線,如果需要限制連線數,可再加上 limit_conn 的限制條件:

location /download/ {
  limit_conn addr 1;
  limit_rate 50k;
}

如果要讓使用者可以先下載一部份的資料,再進行連線頻寬的限制,可以使用 limit_rate_after

limit_rate_after 500k;
limit_rate 20k;

這樣的設定可以讓使用者先下載 500KB 的資料之後,再進行限速,這通常會用在線上影音串流的網站,先讓使用者快速下載影音檔的表頭,然後再以正常的速度傳送串流資料,確認使用者是以串流的形式觀看,而不是直接下載。

以下是一個實際應用的範例,這個設定可讓一般的網頁同時可以接受 5 條連線(一般的瀏覽器通常最多使用 3 條),而在下載 /download/ 之下的檔案時,一次只能下載一個檔案,1MB 以下的檔案不限速,超過 1MB 的檔案則限速每秒 50KB。

http {
  limit_conn_zone $binary_remote_address zone=addr:10m

  server {
    root /www/data;
    limit_conn addr 5;

    location / {
    }

    location /download/ {
      limit_conn addr 1;
      limit_rate_after 1m;
      limit_rate 50k;
    }
  }
}

參考資料