0%

[Nginx] Nginx 安裝及設定

Nginx

前言

Nginx 是一個 Web Server, 也可以用來作為 Reverse Proxy, Load Balancer 和 HTTP cache.
這一篇文章主要紀錄如何安裝以及設定 Nginx。

安裝

1
2
$ sudo apt-get update
$ sudo apt-get install nginx

常用指令

1
2
3
4
5
6
7
8
9
10
11
# 測試 Nginx config
$ sudo nginx -t

# 啟動 Nginx
$ sudo nginx -c <config_path>

# 關閉 Nginx
$ sudo nginx -s stop

# Reload
$ sudo nginx -s reload

Nginx 設定

資料夾結構

Nginx 主要的設定內容放在 /etc/nginx,資料夾結構如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/etc/nginx/
├─ conf.d/
├─ fastcgi.conf
├─ fastcgi_params
├─ koi-utf
├─ koi-win
├─ mime.types
├─ nginx.conf
├─ proxy.conf
├─ proxy_params
├─ scgi_params
├─ sites-available/
├─ sites-enabled/
├─ uwsgi_params
└─ win-utf

其中:

  • /etc/nginx/sites-available: 用來存放每個服務的設定檔
  • /etc/nginx/sites-enabled: 用來放要啟用的服務的設定檔,在此資料夾底下建立 symbolic link 連結到 /etc/nginx/sites-available 底下的設定檔

設定檔說明

Nginx 主要的設定檔是 /etc/nginx/nginx.conf,基本結構如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Global block: 設定 Nginx server 運行的相關配置,ex. worker_processes, pid

events {
# events block: 設定 Nginx server 和 client 的網路連結
}

http {
# http block: 包含 proxy, cache, log...等功能都在此區塊設定
server {
# server block: 通常會設定 server name, listen port...等
location / {
# location block: 設定針對不同路徑做不同的處理
}
}
}

基本範例:

/etc/nginx/nginx.conf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# Nginx user
#user nobody;

# 設定 worker process 的數量,通常會設定成 CPU 的核心數,或是也可以設成 auto 讓 Nginx 自動偵測
worker_processes 4;

#pid /var/run/nginx.pid;

events {
# 允許同一時間連線總數量
worker_connections 1024;

# 使用 epoll 效能較好
use epoll;
}

http {
include /etc/nginx/mime.types;
include /etc/nginx/proxy.conf;
default_type application/octet-stream;

# 不顯示 Nginx 版本,避免暴露出伺服器可能的弱點
server_tokens off;

# Log settings
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';

access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log;

sendfile on;
tcp_nopush on;
tcp_nodelay on;

keepalive_timeout 65;

# gzip 壓縮, 預設是不啟動
gzip on;
gzip_vary on;
gzip_disable "msie6";
gzip_min_length 1000;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain text/css text/javascript application/json
application/javascript application/x-javascript
text/xml application/xml image/png image/x-icon
image/x-jng image/svg+xml image/webp image/gif image/jpeg;

# 載入設定檔
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}

/etc/nginx/proxy.conf:

1
2
3
4
5
6
proxy_http_version  1.1;

proxy_set_header Connection "";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;

載入的 Server 設定檔(/etc/nginx/sites-available/api.conf)範例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
server {
listen 80;
server_name localhost;
root /home/user/web;

# 預設編碼,若未設定,讓網頁中 meta 或 header 會自行定義
#charset koi8-r;

# Access log 存放位置
#access_log /var/log/nginx/localhost.access.log;
#error_log /var/log/nginx/localhost.error.log;

# Cache 靜態檔案
location ~* \.(ico|jpg|jpeg|png|gif|js|css|svg)$ {
access_log off;
log_not_found off;

expires 1m;
add_header Cache-Control "public, no-transform";
}

location / {
index index.html index.htm;
try_files $uri $uri/ $uri.html =404;
}

# 禁止存取隱藏檔案
location ~ /\. {
access_log off;
log_not_found off;
deny all;
}
}

Location syntax

Location 有以下兩種語法:

  • location [ = | ~ | ~* | ^~ ] uri { ... }
  • location @name { ... }

這裡我們先以第一種語法為主,它的優先順序及說明如下:

  1. location = /url: Exactly matching
    • 比對成功後,會停止比對後面的規則
  2. location ^~ /url: The url must start with the specified pattern.
    • 一般字串比對
    • 比對成功後,會停止比對後面的規則
  3. location ~ /urllocation ~* /url: Regex matching
    • ~: case sensitive matching
    • ~*: case insensitive matching
  4. location /url: The url must start with the specified pattern.
  5. location /: 所有 request 都會比對到此規則

以上就是 location 的基本語法,另外可以到 Nginx location match tester 去測試 location 的設定~

Proxy 設定範例

此範例是由 localhost:6000 接收到 request 後, 轉發到設定的 api server.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
upstream api {
server server.com:8000;
keepalive 64;
}

server {
listen 6000;
server_name localhost;

# HTTP authentication
auth_basic "Auth";
auth_basic_user_file /path/to/password/file;

# 設定 body 長度限制
client_max_body_size 100M;

location ~* \.(ico|jpg|jpeg|png|gif|js|css|svg)$ {
access_log off;
log_not_found off;

expires 1m;
add_header Cache-Control "public, no-transform";
}

location / {
proxy_pass http://api;
proxy_connect_timeout 10s;
proxy_read_timeout 60s;
}

# 禁止存取隱藏檔案
location ~ /\. {
access_log off;
log_not_found off;
deny all;
}
}

其中 upstream block 定義了要將 request proxy 過去的 application, keepalive 是設定閒置的連線最大數量,當超過此上限時,將會關閉最近使用最少的連線,假設目前有100個閒置的連線,而我們設定 keepalive=64,所以最近最少使用的36個連線會被關閉,這個參數要小心設定,如果設太小,會造成 Nginx 一直關閉、開啟和後端的連線,會出現大量的 TIME_WAIT 的情況。另外要讓 Nginx 可以使用 keepalive 和後端連線必須要使用 HTTP 1.1,因此需要設定 proxy_http_version 1.1,同時也記得設定 proxy_set_header Connection "" 清理 header.

auth_basicauth_basic_user_file 則是設定 Nginx 使用 HTTP authentication, auth_basic_user_file 為 password file.

client_max_body_size 設定 Body 最大長度限制,超過限制則會出現 HTTP ERROR: 413 Request Entity Too Large 的錯誤訊息。

最後使用 proxy_pass 設定轉發到 updstream api server.

Proxy as failover 設定範例

在此設定範例中,如果第一個 server fail(proxy_connect_timeout)次數超過 max_fails (預設為1), 第二個 server 將會用來取代 server1,持續的時間為 fail_timeout

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
upstream api {
server server1.com:8000 fail_timeout=60s max_fails=1;
server server2.com:8080 backup;
keepalive 256;
}

server {
listen 6000;
server_name localhost;

location / {
proxy_pass http://api;
proxy_connect_timeout 10s;
proxy_read_timeout 60s;
}
}

Load balancing 設定範例

Nginx 提供以下三種 load balancing 方法:

  • round-robin: 會將請求輪流平均分配到每台伺服器上 (預設)
  • least_conn: 將請求分配到目前連線數最少的伺服器上
  • ip-hash: 利用 hash function 來決定使用者要被分配到哪個伺服器,此方法可以達到同一使用者(IP address)每次連結的伺服器是相同的

此範例是將 Nginx 作為 Load Balancer, 並設定 load balancing 方式為 least_conn,將 request 分配至使用連線數最少的 server:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
upstream api {
least_conn;
server server1.com;
server server2.com;
server server3.com;
keepalive 64;
}

server {
listen 6000;
server_name localhost;

location / {
proxy_pass http://api;
proxy_connect_timeout 10s;
proxy_read_timeout 60s;
}
}

另外也可以設定分配的權重(weight),weight 預設為 1,以下範例表示如果有 5 個新的請求,則會有 3 次被分配到 server1, server2 和 server3 各一次:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
upstream api {
server server1.com weight=3;
server server2.com;
server server3.com;
keepalive 64;
}

server {
listen 6000;
server_name localhost;

location / {
proxy_pass http://api;
proxy_connect_timeout 10s;
proxy_read_timeout 60s;
}
}

HTTPS

現在多數的服務都會使用 HTTPS,在設定 HTTPS 之前,需要先申請 SSL 憑證,可以參考: [SSL] Nginx + Let’s encrypt SSL 憑證,依照此文章設定完成後,可以在 nginx.conf 的 http block 中加上以下內容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# ...

http {
# ...

# SSL settings
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDH+AESGCM:EDCH+AES256:ECDH+AES128:!MD5:!aNULL;
# Enable SSL cache
ssl_session_cache shared:SSL:30m;
ssl_session_tickets on;
ssl_session_timeout 1h;
# Enable OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;

# ...
}

參考資料