天天看點

你需要知道的Nginx配置二三事

做服務端開發的,工作中難免會遇到處理Nginx配置相關問題。在配置Nginx時,我一直本着“照葫蘆畫瓢”的原則,複制已有的配置代碼,自己修修改改然後完成配置需求,當有人問起Nginx相關問題時,其實仍然一無所知。為此在工作之餘,花了一周的時間閱讀Nginx配置相關文章,整理成自己的學習筆記如下:

  • nginx是什麼?
  • nginx如何配置?
  • nginx中location部分url如何比對?
  • nginx中rewrite指令如何重寫url?
  • nginx中if判斷如何使用?
  • nginx變量如何使用?
  • nginx中一些常用的指令

nginx是什麼

Nginx是俄羅斯人Igor Sysoev基于C語言編寫的十分輕量級的HTTP伺服器,它主要有以下特點:

- 它是一個高性能的HTTP和反向代理伺服器,同時也是一個IMAP/POP3/SMTP 代理伺服器;

- Nginx使用異步事件驅動的方法來處理請求,Nginx的子產品化事件驅動架構可以在高負載下提供更可預測的性能;

- 作為Web伺服器,Nginx處理靜态檔案、索引檔案,自動索引的效率非常高

- 作為反向代理伺服器,Nginx可以實作反向代理加速,提高網站運作速度

- 作為負載均衡伺服器,Nginx既可以在内部直接支援Rails和PHP,也可以支援HTTP代理伺服器對外進行服務,同時還支援簡單的容錯和利用算法進行負載均衡

- Nginx是專門為性能優化而開發的,非常注重效率,Nginx在官方測試的結果中,能夠支援五萬個并行連接配接,而在實際的運作中,可以支援二萬至四萬個并行連結

- 在高可用性方面,Nginx支援熱部署,啟動速度特别迅速,是以可以在不間斷服務的情況下,對軟體版本或者配置進行更新

nginx如何配置?

Nginx的配置檔案預設存放路徑是etc/nginx/nginx.conf,可以在Nginx啟動時添加參數–conf-path=PATH來更改nginx.conf檔案的存放路徑。nginx.conf中的配置資訊主要包含以下五個部分:

  • main(全局設定):主要是包括Nginx工作程序,日志的配置以及server,location中一些共用的配置
  • events(連接配接設定):主要包括Nginx連接配接資訊的配置
  • server(主機設定):主要是包括主機名稱,Ip,路徑解析,http請求頭設定,反向代理等配置
  • upstream(上遊伺服器設定):主要為反向代理伺服器資訊、負載均衡等相關配置
  • location(URL比對):特定URL的比對設定

以上每部分包含若幹個條指令,他們之間的關系是:server繼承main,location繼承server,main部分設定的指令将影響其它所有部分的設定,server部分的設定将影響到location部分的設定。upstream既不會繼承指令也不會被繼承,它有自己的特殊指令,不需要在其他地方的應用。

以下是我整理的關于Nginx五個主要子產品的所有基礎參數設定,并用#注釋的方式對每個參數的含義做了詳細的闡述:

Nginx基礎配置參數詳解:

################################################################################################################## 
# main全局配置                                                                                                    #
##################################################################################################################

user  www www;  #預設為nobody
# 設定nginx工作程序的使用者

worker_processes  ; # 預設為1
# 設定worker角色的工作程序的個數,正常情況下可以設定成cpu的核心數,最多設定為8個;
# 也可以将worker_processes的值設為auto,這樣nginx會自動檢測CPU核數并打開相同數量的worker程序;
# 當nginx添加了SSL證書時,最好要打開多個worker程序。SSL握手會進行硬碟I/O操作。是以打開多個worker程序有利于性能的提升;

worker_cpu_affinity  ; 
# 通過設定cpu粘性來降低由于多CPU核切換造成的寄存器等現場重建帶來的性能損耗,上述設定表示第一個worker程序用第一個cpu,第二個worker程序程序使用第二個cpu

worker_rlimit_nofile; # 預設為作業系統的限制(65535)
# 設定每個worker程序的最大打開檔案數(句柄)限制

error_log  logs/error.log error;    
# 配置錯誤日志路徑以及列印級别(debug | info | notice | warn | error | crit | alert | emerg)
# 生産場景一般是warn | error | crit 這三個級别之一,級别太低會有太多IO消耗,影響效率

pid logs/nginx.pid; 
# pid檔案為文本檔案,内容隻有一行, 記錄了該程序的ID,根據PID檔案的内容,準确判斷程序是否正在運作,防止意外啟動多個程序執行個體。
# 隻有獲得pid檔案(固定路徑固定檔案名)寫入權限(F_WRLCK)的程序才能正常啟動并把自身的PID寫入該檔案中,其它同一個程式的多餘程序則自動退出。

################################################################################################################## 
# events子產品中包含nginx中所有處理連接配接的設定                                                                           #
##################################################################################################################

events {
    use epoll;    
    # 用于設定處理用戶端請求的輪詢方法
    # 在Linux作業系統下,nginx預設使用epoll事件模型
    # 同時Nginx在OpenBSD或FreeBSD作業系統上采用類似于epoll的高效事件模型kqueue
    # 在作業系統不支援這些高效模型時才使用select

    worker_connections  ;  #預設為512
    # 設定可由一個worker程序同時打開的最大連接配接數。但不能超過worker_rlimit_nofile的設定

    accept_mutex on;  # 預設為on
    # 當一個新連接配接到達時,如果激活了accept_mutex,那麼多個Worker将以串行方式來處理,其中有一個Worker會被喚醒,其他的Worker繼續保持休眠狀态;
    # 如果沒有激活accept_mutex,那麼所有的Worker都會被喚醒,不過隻有一個Worker能擷取新連接配接,其它的Worker會重新進入休眠狀态,[thundering herd現象](https://en.wikipedia.org/wiki/Thundering_herd_problem)

    accept_mutex_delay ms; # 預設為500ms
    # 當accept_mutex功能啟用後,隻有一個持有mutex鎖的worker程序會接受并處理請求,其他worker程序等待。accept_mutex_delay指定的時間就是這些worker程序的等待時間,過了等待時間下一個worker程序便取得mutex鎖,處理請求。

    multi_accept on # 預設為off
    # multi_accept可以讓nginx worker程序盡可能多地接受請求,提高性能
    # 如果設定為on,可以讓worker程序一次性地接受監聽隊列裡的所有請求,然後處理
    # 如果multi_accept的值設為off,那麼worker程序必須一個一個地接受監聽隊列裡的請求
    # 如果web伺服器面對的是一個持續的請求流,那麼啟用multi_accept可能會造成worker程序一次接受的請求大于worker_connections指定可以接受的請求數。這就是overflow,這個overflow會造成性能損失,overflow這部分的請求不會受到處理
}

################################################################################################################## 
# 提供http服務相關的一些配置參數                                                                                      #
##################################################################################################################

http {

    #################################################################################### 
    # 基本配置                                                                          #
    ####################################################################################

    include  mime.types; 
    # include可以包含若幹子配置檔案,實作不同需求配置獨立,可以将不同的server配置在不同的conf檔案裡
    # mime.types檔案列出針對不同的請求檔案傳回的HTTP response的Content-Type的Accept值
    # 除非服務端Web程式手動設定了Content-Type,如果Web程式沒設定,則會從mime.types中比對傳回
    # 如果mime.types中也沒找到對應檔案的擴充名的話,就使用預設的default_type

    default_type  application/octet-stream; 
    # 如果在mime.types的配置中沒有找到響應請求檔案的格式,則走default_type

    types_hash_max_size ;
    # 設定散清單的沖突率。
    # types_hash_max_size越大,就會消耗更多的記憶體,但散列key的沖突率會降低,檢索速度就更快。
    # types_hash_max_size越小,消耗的記憶體就越小,但散列key的沖突率可能上升。

    server_tokens off;
    # 傳回錯誤頁面時是否在Server中注明Nginx版本

    server_names_hash_bucket_size ;
    # 為了提高快速尋找到相應server_name的能力,Nginx 使用散清單來存儲server_name,server_names_hash_bucket_size設定了每個散列桶占用的記憶體大小。

    server_name_in_redirect off;
    # 重定向主機名稱的處理.該配置需要配合server_name使用.
    # 設定為on時,表示在重定向請求時會使用stream裡配置的第一個主機名代替原先請求中的Host頭部,而當關閉時,表示在重定向請求時使用請求本身的Host頭部。



    #################################################################################### 
    # 日志配置                                                                         #
    ####################################################################################

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '   
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    # 定義日志nginx日志檔案的列印格式并命名為變量main

    access_log  logs/access.log  main;   
    # access_log指定nginx的通路日志的存放路徑檔案以及使用的日志檔案格式

    #access_log off;   
    # 為了提高效率,可以将通路日志關掉

    access_log /data/logs/nginx-access.log buffer=k flush=s;
    # buffer和flush可以設定緩存日志的刷盤政策,日志超過32k才刷盤,如果沒滿32k,但是超過5s也自動刷盤

    rewrite_log on; # 預設是off
    # 開啟或者關閉rewrite子產品指令執行的日志,如果開啟,則重寫将記錄下notice等級的日志到nginx 的error_log中

    #################################################################################### 
    # 高效檔案傳輸                                                                        #
    ####################################################################################

    sendfile on; 
    # 當一個程式需要傳輸檔案時,Linux核心首先将檔案資料緩沖,然後将檔案資料傳送給程式緩沖,最後程式将檔案資料傳輸到目的地。
    # Sendfile方法是一種資料傳輸的更高效的方法,資料在核心中的檔案描述符之間傳輸
    # 這種方法的結果是改善了對作業系統資源的利用,提高Nginx靜态資源托管效率,直接在核心空間完成檔案發送,不需要先read再write,沒有上下文切換開銷

    tcp_nopush on; 
    # TCP_NOPUSH是FreeBSD的一個socket選項,對應Linux的TCP_CORK,Nginx裡統一用tcp_nopush來控制它,并且隻有在啟用了sendfile之後才生效。
    # 啟用它之後,資料包會累計到一定大小之後才會發送,減小了額外開銷,提高網絡效率

    tcp_nodelay on;
    # TCP_NODELAY也是一個socket選項,啟用後會禁用Nagle算法,盡快發送資料,某些情況下可以節約200ms
    # Nagle算法原理是:在發出去的資料還未被确認之前,新生成的小資料先存起來,湊滿一個 MSS 或者等到收到确認後再發送
    # Nginx 隻會針對處于keep-alive狀态的TCP連接配接才會啟用tcp_nodelay

    keepalive_timeout  ; 

    # 一個keepalive連接配接在閑置超過一定時間後(預設的是75秒),會主動關閉這個長連接配接
    # 用戶端可以設定http服務要不要走長連接配接,通過設定請求頭Connection=keep-alive實作的,http1.0預設是關閉的,http1.1預設是打開的
    # 谷歌浏覽器同時最多有6個tcp連接配接
    # keepalive_timeout時間不能設定太長,因為太長會長時間占用tcp連接配接不釋放,導緻伺服器的tcp連接配接不夠用;也不能太短,如果太短會導緻一些大檔案上傳接口因為上傳一半而中斷;

    keepalive_requests ;
    # 設定同一個長連接配接上最多請求次數,超過這個次數,将主動關閉這個長連接配接

    #################################################################################### 
    # http_proxy 設定,client相關配置                                                    #
    ####################################################################################

    client_max_body_size   m;
    # 允許用戶端請求的最大單檔案位元組數限制。如果有上傳較大檔案的需求,盡量設定大一些

    client_body_buffer_size   k; 
    # 緩沖區代理使用者端請求的最大位元組數

    client_header_timeout ; 
    # 指定等待client發送一個請求頭的逾時時間,僅當在一次read中,沒有收到請求頭,才會算成逾時。如果在逾時時間内,client沒發送任何東西,nginx傳回HTTP狀态碼408(“Request timed out”)

    client_body_timeout ; 
    # 該指令設定請求體(request body)的讀逾時時間。僅當在一次readstep中,沒有得到請求體,就會設為逾時。逾時後,nginx傳回HTTP狀态碼408(“Request timed out”)

    #################################################################################### 
    # http_proxy 設定,server相關配置                                                    #
    ####################################################################################

    proxy_connect_timeout  ; 
    # 該指令設定與upstream server的連接配接逾時時間,有必要記住,這個逾時不能超過75秒

    proxy_send_timeout   ; 
    # 這個指定設定了發送請求給upstream伺服器的逾時時間。逾時設定不是為了整個發送期間,而是在兩次write操作期間。如果逾時後,upstream沒有收到新的資料,nginx會關閉連接配接

    proxy_read_timeout   ; 
    # 該指令設定與代理伺服器的讀逾時時間。它決定了nginx會等待多長時間來獲得請求的響應。這個時間不是獲得整個response的時間,而是兩次reading操作的時間,預設值60s

    proxy_upstream_fail_timeout ; 
    # Upstream子產品下server指令的參數,設定了某一個upstream後端失敗了指定次數(max_fails)後,該後端不可操作的時間,預設為10秒

    proxy_buffer_size   k; 
    # 設定代理伺服器(nginx)從後端realserver讀取并儲存使用者頭資訊的緩沖區大小,預設與proxy_buffers大小相同,其實可以将這個指令值設的小一點

    proxy_buffers    k; 
    # proxy_buffers緩沖區,4個緩存,每個大小限制為32k。

    proxy_busy_buffers_size   k; 
    # 高負荷下緩沖大小(proxy_buffers*2)

    proxy_temp_file_write_size  k; # 預設為1024M
    # 當proxy_buffers放不下後端伺服器的響應内容時,會将一部分儲存到硬碟的臨時檔案中,這個值用來設定最大臨時檔案大小,預設1024M
    # 它與proxy_cache沒有關系,大于這個值,将從upstream伺服器傳回。設定為0禁用

    proxy_temp_path   /usr/local/nginx/proxy_temp  ; 
    # 指定緩存寫到那個目錄

    #################################################################################### 
    # gzip壓縮功能設定                                                                   #
    ####################################################################################

    gzip on;      
    # 開啟gzip壓縮輸出,減少網絡傳輸,用戶端通過設定請求頭Accept-Encoding=gzip, deflate, br來支援gzip壓縮

    gzip_static on; 
    # nginx對于靜态檔案的處理子產品,該子產品可以讀取預先壓縮的gz檔案,這樣可以減少每次請求進行gzip壓縮的CPU資源消耗。
    # 該子產品啟用後,nginx首先檢查是否存在請求靜态檔案的gz結尾的檔案,如果有則直接傳回該gz檔案内容

    gzip_disable "msie[1-6].";  
    # IE6的某些版本對gzip的壓縮支援很不好,會造成頁面的假死,為了確定其它的IE6版本不出問題,是以建議加上gzip_disable的設定

    gzip_min_length k; 
    # 設定允許壓縮的頁面最小位元組數,頁面位元組數從header頭得content-length中進行擷取。預設值是20。建議設定成大于1k的位元組數,小于1k可能會越壓越大

    gzip_buffers     k; 
    # 設定系統擷取幾個機關的緩存用于存儲gzip的壓縮結果資料流。4 16k代表以16k為機關,安裝原始資料大小以16k為機關的4倍申請記憶體

    gzip_http_version ; 
    # 用于識别http協定的版本,早期的浏覽器不支援Gzip壓縮,使用者就會看到亂碼,是以為了支援前期版本加上了這個選項。
    # 如果你用了Nginx的反向代理并期望也啟用Gzip壓縮的話,由于末端通信是 http/1.0,故請設定為 1.0

    gzip_comp_level ; 
    # gzip壓縮比,1壓縮比最小處理速度最快,9壓縮比最大但處理速度最慢(傳輸快但比較消耗cpu)

    gzip_types text/html text/plain text/css text/javascript application/json application/javascript application/x-javascript
    application/xml; 
    # 比對mime類型進行壓縮,無論是否指定,”text/html”類型總是會被壓縮的

    gzip_vary on; 
    # 和http頭有關系,會在響應頭加個Vary:Accept-Encoding,可以讓前端的緩存伺服器緩存經過gzip壓縮的頁面,例如,用Squid緩存經過Nginx壓縮的資料

    gzip_proxied any 
    # Nginx作為反向代理的時候啟用,決定開啟或者關閉後端伺服器傳回的結果是否壓縮,比對的前提是後端伺服器必須要傳回包含”Via”的 header頭

    ################################################################################## 
    # FastCGI 設定,為了保證Nginx下PHP環境的高速穩定運作,需要添加一些FastCGI優化指令          #
    ##################################################################################

    fastcgi_cache_path /usr/local/nginx/fastcgi_cache levels=: keys_zone=TEST:m inactive=m; 
    # 為FastCGI緩存指定一個檔案路徑、目錄結構等級、關鍵字區域存儲時間和非活動删除時間

    fastcgi_connect_timeout ;  
    # 指定連接配接到後端FastCGI的逾時時間

    fastcgi_send_timeout ;     
    # 指定向FastCGI傳送請求的逾時時間,這個值是已經完成兩次握手後向FastCGI傳送請求的逾時時間 

    fastcgi_read_timeout ;     
    # 指定接收FastCGI應答的逾時時間,這個值是已經完成兩次握手後接收FastCGI應答的逾時時間

    fastcgi_buffer_size k;      
    # 用于指定讀取FastCGI應答第一部分需要多大的緩沖區,這個值表示将使用1個64KB的緩沖區讀取應答的第一部分(應答頭),可以設定為fastcgi_buffers選項指定的緩沖區大小

    fastcgi_buffers  k;     
    # 指定本地需要用多少和多大的緩沖區來緩沖FastCGI的應答請求。
    # 如果一個PHP腳本所産生的頁面大小為256KB,那麼會為其配置設定4個64KB的緩沖區來緩存;如果頁面大小大于256KB,那麼大于256KB的部分會緩存到fastcgi_temp指定的路徑中。
    # 一般這個值應該為站點中PHP腳本所産生的頁面大小的中間值,如果站點大部分腳本所産生的頁面大小為256KB,那麼可以把這個值設定為“16 16k”、“4 64k”等

    fastcgi_temp_file_write_size k; 
    # 表示在寫入緩存檔案時使用多大的資料塊,預設值是fastcgi_buffers的兩倍 

    fastcgi_cache TEST;  
    # 表示開啟FastCGI緩存并為其指定一個名稱。開啟緩存非常有用,可以有效降低CPU的負載,并且防止502錯誤的發生

    fastcgi_cache_valid   h;
    # 指定code為200,302的響應緩存為一小時 

    fastcgi_cache_valid  d;  
    # 指定code為301的緩存有效時間為1天

    fastcgi_cache_valid any m; 
    # 其它緩存有效時間都為1分鐘

    ################################################################################## 
    # 設定負載均衡背景伺服器清單                                                       #
    ################################################################################## 

    upstream  backend  { 
        keepalive 
        # 在開啟長連接配接的情況下,最多保持空閑長連接配接的個數,如果超過這個數量,最近最少使用的長連接配接将被關閉

        ip_hash;    # 預設為round-robin
        # 負載均衡處理方式,一共有三種方式:
        # (1)round-robin(輪訓請求方式)
        # (2)ip_hash(回話持久化方式,這個方法保證從同一個用戶端發起的請求總是定向到同一台伺服器)
        # (3)least_conn(最少連接配接方式,找連接配接最少的服務進行處理)

        server   : max_fails= fail_timeout=s weight=;
        server   : max_fails= fail_timeout=s weight=;
        server   : backup
        server   : down;
        # weight設定每個服務的命中幾率,預設是1;
        # backup表示備份服務,隻有所有的非備份不能使用時,會啟動該服務,down表示目前服務永遠不參與負載;
        # max_fails表示容許請求失敗的次數,當超過該次數時将暫停一定時間(fail_timeout)
    }

    ################################################################################## 
    # server虛拟主機配置                                                               #
    ##################################################################################

    server {
        ############################################ 
        # 基本配置                                   #
        ############################################

        listen   default_server; # 預設為80
        # 監聽端口設定,小于1024的要以root啟動,
        # default_server表示如果找不到對應端口的server_name,則預設走這個比對

        server_name  itoatest.example.com;
        # 一個nginx可以配置多個server,nginx通過檢查請求header中host來比對每個server的server_name決定走哪個server,
        # 如果沒有任何一個server可以比對,則會選擇第一個server做比對。預設比對可以通過listen中添加defalut_server來改變。
        # server_name有四種比對方式:
        # (1)精确比對(itoatest.example.com)
        # (2)星号開頭的最長的通配符名稱(*.example.org)
        # (3)星号結束的最長的通配符名稱(mail.*)
        # (4)正規表達式比對(~^www\d+\.example\.net$,正規表達式必須以~開頭)

        root   /apps/oaapp;
        # 見下文location講解

        allow ;
        allow /;
        # allow表示允許某個ip或ip段通路

        deny all
        # deny表示禁止某個ip或者ip段通路

        error_page        /x.html;
        error_page       http://example.com/forbidden.html;
        # 這個參數可以為錯誤代碼指定相應的錯誤頁面 

        charset utf-;
        # 設定http頭資訊的charset編碼

        if ($request_method = POST) {
            return ;
        } 
        # 關于if的使用請看下文[Nginx中如何使用變量?]

        ############################################ 
        # location特定的URL對應的一系列配置項          #
        ############################################
        location /i/ {       # 關于location中的路徑比對規則以及比對優先級請看下文[Nginx中location部分URL如何比對?]
            root   /apps/oaapp;   
            #alias  /apps/oaapp/;
            # root和alias都可以用來指定請求資源的真實路徑。
            # 差別是root最後得到的資源位址是root的值加上location的值,而alias正如其名,alias指定的路徑是location的别名,不管location的值怎麼寫,資源的真實路徑都是 alias 指定的路徑。
            # 比如當通路http://itoatest.example.com/i/hello.gif這個位址時,如果是root,資源的真實路徑是/apps/oaapp/i/hello.gif;如果是alias真實路徑是/apps/oaapp/hello.gif;
            # alias隻能作用在location中,而root可以存在server、http和location中
            # alias 後面必須要用 “/” 結束,否則會找不到檔案,而 root 則對 ”/” 可有可無

            index  index.jsp index.html index.htm;
            # 當使用者請求的是http://itoatest.example.com/i/這個位址時,就會自動在root配置指令指定的檔案系統目錄下依次尋找 index.jsp 和 index.html,index.htm這三個檔案,直到找到一個并傳回

            autoindex on; # 預設為off
            # 當index指定的檔案都找不到時,如果開啟autoindex,那麼則會生成一個root所指目錄下的“目錄索引”的html并傳回,如果沒有開啟,則會傳回forbidden

            autoindex_exact_size off # 預設為on
            # 隻有在autoindex開啟時才起作用,預設為on,顯示出檔案的确切大小,機關是bytes。改為off後,顯示出檔案的大概大小,機關是kB或者MB或者GB

            autoindex_localtime on # 預設為off
            # 隻有在autoindex開啟時才起作用,預設為off,顯示的檔案時間為GMT時間。改為on後,顯示的檔案時間為檔案的伺服器時間

            proxy_pass  http://backend;
            # 請求轉向某個upstream定義的負載均衡的伺服器清單,如果隻有一台伺服器的話,也可以直接寫成proxy_pass http://ip:port;

            rewrite ^/i/(.*) /$ break;
            # rewrite 的作用是修改 $uri,具體細節請看下文[rewrite如何重寫url?]

            proxy_redirect off; # 預設是default
            proxy_redirect http://:/i/wuman/ http://itoatest.example.com/i/wuman/
            # 如果需要修改從被代理伺服器傳來的應答頭中的"Location"和"Refresh"字段,可以用這個指令設定,分為三種情況:
            #(1)proxy_redirect off表示不修改服務端的redirect位址
            #(2)proxy_redirect default 将根據location和proxy_pass的設定來決定
            #(3)可以自己設定不同的替換規則

            proxy_set_header  Host  $host; #預設是$proxy_host
            # 可以通過三個變量對Host進行設定:
            #(1)$proxy_host,表示是反向代理後的host,就是proxy_pass後面跟的host
            # (2) $host首先從請求頭中擷取Host值,如果沒有則選擇server_name
            # (3) $http_host是直接從請求頭中擷取,是以可能為空,如果是非80/443端口的時候,$http_host = $host:$port

            proxy_set_header  X-Real-IP  $remote_addr;  
            # 由于在用戶端和web伺服器之間增加了中間層,是以web伺服器無法直接拿到用戶端的ip,通過$remote_addr變量拿到的将是反向代理伺服器的ip位址;
            # 是以我們可以設定一個請求頭X-Real-IP,通過擷取這個請求頭就可以拿到用戶端的真實ip

            proxy_set_header  X-Forwarded-For  $proxy_add_x_forwarded_for;
            # 上述的意思增加一個$proxy_add_x_forwarded_for到X-Forwarded-For裡去,注意是增加,而不是覆寫
            # 如果每次代理都使用上述配置,那麼X-Forwarded-For可以擷取到經過多次代理後的客戶多IP以及多層代理nginx的IP:IP0, IP1, IP2...
            # 是以proxy_set_header也是擷取真實用戶端ip的一種方法

            proxy_set_header X-Forwarded-Proto  https;
            # 請求标頭可幫助您識别用戶端與您的負載均衡器連接配接時所用的協定,并随後将标題傳遞到您的伺服器

            proxy_set_header X-Forwarded-Host $host
            # 可以幫助您識别用戶端與您的負載均衡器連接配接時所用的host,并随後将标題傳遞到您的伺服器

            proxy_set_header X-Forwarded-Host $port
            # 可以幫助您識别用戶端與您的負載均衡器連接配接時所用的port,并随後将标題傳遞到您的伺服器

            proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; # 預設是error timeout
            # 指定在什麼情況下将請求應傳遞到下一個伺服器,如果設定為off表示在任何情況下都不需要傳遞
            # error表示發生錯誤時,将請求傳遞到下一個伺服器
            # timeout表示發生請求或者響應逾時時,将請求傳遞給下一個伺服器
            # invalid_header表示伺服器傳回空響應或無效響應時,将請求傳遞給下一個伺服器
            # http_code表示伺服器傳回對應的code時将請求傳遞到下一個伺服器

            proxy_next_upstream_timeout  # 預設是0
            # 限制請求可以傳遞到下一個伺服器的時間,0表示關閉限制

            proxy_next_upstream_tries  # 預設為0
            # 限制将請求傳遞到下一個伺服器的可能嘗試次數, 0值關閉此限制

        }

        location ~ .*\.(gif|jpg|jpeg|bmp|png|ico|txt|js|css)$   
        {   
            root /apps/oaapp;

            expires      d;
            # 對于站點中不經常修改的靜态内容(如圖檔,JS,CSS),可以在伺服器中設定expires過期時間,控制浏覽器緩存,達到有效減小帶寬流量,降低伺服器壓力的目的
        }

        location = /x.html {
            root   html;
        }

        location = /video {
            directio m;  # 該路徑下所有大于4M的檔案不直接從磁盤讀取,不走緩存
            # Direct I/O是檔案系統的一個功能,它允許程式繞過核心緩存,直接在硬碟上讀寫資料
            # 這可以充分利用CPU頻數,改善緩存的有效性,Directo I/O适用于通路率少的資料。這些資料不需要緩存在任何位置
            # 在http, server和location當中都可以定義
            # 如果某個請求是通過directo I/O,那麼這個請求不能使用sendfile功能
        }
    }
}

           

nginx中location部分url如何比對?

location主要是比對url中除去server_name(主機名)後的部分,其中關于url的比對規則有以下幾種:

- 精确比對:以“=”開頭表示精确比對

- 開頭比對:^~ 表示uri以某個正常字元串開頭,不是正則比對

- 區分大小寫的正則比對:~開頭表示區分大小寫的正則比對

- 不區分大小寫的正則比對:~* 開頭表示不區分大小寫的正則比對

- 通用比對:比對url的前面部分

對于上述五類比對,它們之間的比對順序和優先級關系如下:

- 不同類型之間比對和location的順序無關,隻和優先級有關,各種比對規則的優先級關系是: [精确比對] > [開頭比對] > [正則比對] > [通用比對];

- 除了通用比對,開頭比對以外,相同類型的比對優先級隻和順序有關,排在前面的優先比對;

- 通用比對和開頭比對的優先級與通用比對的最長字元串有關,通用字元串越長,比對優先級越高;

下面是我設定的幾個location,并測試和驗證以上比對規則:

server {
    listen        default_server;
    server_name  dev.zdp.com;

    # 通用比對  [比對規則0]
    location  /
    {
        return  https://dashboard.youdata.com;
    }

    # 通用比對  [比對規則1]
    location  /hello
    {
        return  https://dashboard.youdata.com;
    }

    # 通用比對  [比對規則2]
    location  /hello/no
    {
        return  https://dev.youdata.com;
    }

    # 不區分大小寫的正則比對  [比對規則3]
    location ~* /hello/y[a-e][a-z][-]
    {
        return  https://test.youdata.com;
    }

    # 區分大小寫的正則比對  [比對規則4]
    location ~ /hello/y[A-E][E-Z][-]
    {
        return  https://pre.youdata.com;
    }

    # 區分大小寫的正則比對  [比對規則5]
    location ~ /hello/y[a-e][e-z]
    {
        return  https://pre163.youdata.com;
    }

    # 開頭比對  [比對規則6]
    location ^~ /hello/yes
    {
        return   https://youdata.netease.com;
    }

    # 開頭比對  [比對規則7]
    location ^~ /hello/yesno
    {
        return   https://youdata.163.com;
    }

    # 精确比對 [比對規則8]
    location = /hello
    {
        return   https://www.baidu.com;    
    }

}
           

location用例測試:

- “http://dev.zdp.com/hello” ——- 精确比對優先,命中[比對規則8]

- “http://dev.zdp.com/hello/yesnoOk” ——- 開頭比對優先,開頭比對同時滿足條件時,長優先,命中[比對規則7]

- “http://dev.zdp.com/hello/yesOk” ——- 開頭比對優先,命中[比對規則6]

- “http://dev.zdp.com/hello/yaz” ——- 正則比對,命中[比對規則5]

- “http://dev.zdp.com/hello/yAZ3” ——- 正則比對,按照location順序比對,命中[比對規則3]

- “http://dev.zdp.com/hello/no” ——- 通用比對,按照比對長度優先,命中[比對規則2]

- “http://dev.zdp.com/hello/Ok” ——- 通用比對,命中[比對規則1]

- “http://dev.zdp.com/everyone” ——- 通用比對,所有其它比對不滿足時,命中[比對規則0]

nginx中rewrite指令如何重寫url?

rewrite功能就是,使用nginx提供的全局變量或自己設定的變量,結合正規表達式和标志位實作url重寫以及重定向。rewrite隻能放在server{},location{}中,并且隻能對域名後邊的除去傳遞的參數外的字元串起作用,例如:

http://dev.zdp.com/a/we/index.php?id=1&u=str => rewrite隻能對/a/we/index.php部分重寫

重寫用法:

server {
    rewrite 規則 定向路徑 重寫flag;
}

location {
    rewrite 規則 定向路徑 重寫flag;
}
           
rewrite的執行順序
  • 執行server塊的rewrite指令;
  • 執行location比對;
  • 執行標明的location中的rewrite指令,如果location中rewrite指令沒有break的flag,則會根據目前rewrite路徑重新比對location;
  • 如果其中某步URI被重寫,則重新循環執行1-3,直到找到真實存在的檔案,循環最多不會超過10次;
rewrite的flag标志
  • last: 停止處理目前location中的ngx_http_rewrite_module指令集(rewrite,return等),并開始重新搜尋與更改後的URI相比對的location
  • break : 停止處理目前location中的ngx_http_rewrite_module指令集(rewrite,return等),不會重新搜尋
  • redirect : 傳回302臨時重定向,位址欄會顯示跳轉後的位址
  • permanent : 傳回301永久重定向,位址欄會顯示跳轉後的位址
  • default: 預設标志,繼續會處理目前location中的ngx_http_rewrite_module指令集(rewrite,return等),如果沒有return,會開始重新搜尋與更改後的URI相比對的location
rewrite的測試用例
server {
    listen        default_server;
    server_name  dev.zdp.com;

    set $flag="default";

    # 當我們通路http://dev.zdp.com/test1/helloworld時,對于不同flag變量傳回的結果如下:
    # 當$flag="default"時,會執行後續的ngx_http_rewrite_module指令,是以會重定向到https://newke.com;
    # 當$flag="last"時,不會執行後續的ngx_http_rewrite_module指令,但是會重新比對location,是以重定向到https://www.baidu.com;
    # 當$flag="break"時,不會執行後續的ngx_http_rewrite_module指令,是以沒有找到比對,失敗
    location /test1
    {
        rewrite ^/test1\/([^\/]+?) /test2/$1 $flag;
        return  https://newke.com;
    }

    location /test2
    {
        return  https://www.baidu.com;
    }

    location /
    {

        # 通路 /permanent.html 的時候,頁面直接302定向到https://www.baidu.com
        rewrite /permanent.html https://www.baidu.com redirect;

        # 把 /html/*.html => /post/*.html ,301定向
        rewrite ^/html/(.+?).html$ /post/$1.html permanent;

        # 把 /search/key => /search.html?keyword=key
        rewrite ^/search\/([^\/]+?)(\/|$) /search.html?keyword=$1 permanent;
    }
}
           

nginx中if判斷如何使用?

隻是上面的簡單重寫很多時候滿足不了需求,比如需要判斷當檔案不存在時、當路徑包含xx時等條件,則需要用到if

Nginx中if文法為:if(condition){…},對給定的條件condition進行判斷。如果為真,大括号内指令将被執行

if判斷規則
  • 當表達式隻是一個變量時,如果值為空或任何以0開頭的字元串都會當做false
  • 直接比較變量和内容時,使用=或!=
  • ~正規表達式比對,~*不區分大小寫的比對,!~區分大小寫的正規表達式不比對,滿足條件傳回true
  • -f和!-f用來判斷是否存在檔案
  • -d和!-d用來判斷是否存在目錄
  • -e和!-e用來判斷是否存在檔案或目錄
  • -x和!-x用來判斷檔案是否可執行
if使用舉例

if條件中一般會使用到一些變量,這些變量有些是使用者定義的,有些是系統本身存在的,關于變量相關内容請看下文[Nginx中如何使用變量?]

server {
    if ($http_user_agent ~ MSIE) {
        rewrite ^(.*)$ /msie/$1 break;
    } 
    # 如果UA包含"MSIE",rewrite請求到/msid/目錄下

    if ($http_cookie ~* "id=([^;]+)(?:;|$)") {
        set $id $1;
    } 
    # 如果cookie比對正則,設定變量$id等于正則引用部分

    if ($request_method = POST) {
        return ;
    } 
    # 如果送出方法為POST,則傳回狀态405(Method not allowed)。return不能傳回301,302

    if ($slow) {
        limit_rate k;
    } 
    # 限速,$slow可以通過 set 指令設定

    if (!-f $request_filename){
        break;
        proxy_pass  http://.; 
    } 
    # 如果請求的檔案名不存在,則反向代理到localhost 。這裡的break也是停止rewrite檢查

    if ($args ~ post=){
        rewrite ^ http://example.com/ permanent;
    } 
    # 如果query string中包含"post=140",永久重定向到example.com

    location ~* \.(gif|jpg|png|swf|flv)$ {
        valid_referers none blocked www.jefflei.com www.leizhenfang.com;
        if ($invalid_referer) {
            return ;
        } 
        # 防盜鍊
    }
}
           

nginx變量如何使用?

Nginx也可以使用變量,變量分為系統變量和自定義變量

變量特點
  • Nginx變量的建立隻能發生在Nginx配置加載的時候,或者說Nginx啟動的時候;
  • Nginx變量的指派操作則隻會發生在請求實際處理的時候;
  • 每個請求都有所有變量的獨立副本,或者說都有各變量用來存放值的容器的獨立副本,它們之間的值彼此互不幹擾;
自定義變量

自定義變量通過set指令初始化和指派,變量名前需要加$符号作為區分

# 設定變量$a = "helloworld";
 set $a hello world;

 # 設定變量$b = "helloworld, helloworld";
 set $b "$a, $a";
           
系統變量

Nginx中的系統變量如下:

$args              # 這個變量等于請求行中的參數,同$query_string
$content_length    # 請求頭中的Content-length字段。
$content_type      # 請求頭中的Content-Type字段。
$document_root     # 目前請求在root指令中指定的值。
$host              # 請求主機頭字段,如果不存在則為伺服器名稱。
$http_user_agent   # 用戶端agent資訊
$http_cookie       # 用戶端cookie資訊
$limit_rate        # 這個變量可以限制連接配接速率。
$request_method    # 用戶端請求的動作,通常為GET或POST。
$remote_addr       # 用戶端的IP位址。
$remote_port       # 用戶端的端口。
$remote_user       # 已經經過Auth Basic Module驗證的使用者名。
$request_filename  # 目前請求的檔案路徑,由root或alias指令與URI請求生成。
$scheme            # HTTP方法(如http,https)。
$server_protocol   # 請求使用的協定,通常是HTTP/1.0或HTTP/1.1。
$server_addr       # 伺服器位址,在完成一次系統調用後可以确定這個值。
$server_name       # 伺服器名稱。
$server_port       # 請求到達伺服器的端口号。
$request_uri       # 包含請求參數的原始URI,不包含主機名,如:”/foo/bar.php?arg=baz”。
$uri               # 不帶請求參數的目前URI,$uri不包含主機名,如”/foo/bar.html”。
$document_uri      # 與$uri相同。
           

nginx中一些常用的指令

  • nginx -t 檢查配置是否可用
  • nginx -s reload 重新開機nginx

參考文獻

  • nginx伺服器安裝及配置檔案詳解
  • pid 檔案有哪些作用?
  • nginx access_log日志
  • Nginx錯誤日志(error_log)配置及資訊詳解
  • 本部落格 Nginx 配置之性能篇
  • Nginx 啟用gzip網站内容壓縮
  • nginx做負載均衡器以及proxy緩存配置
  • NGINX配置逾時時間
  • CGI、FastCGI和PHP-FPM關系圖解
  • 優化Nginx中FastCGI參數的執行個體
  • Nginx伺服器性能優化的三大方面
  • Nginx配置upstream實作負載均衡
  • Nginx配置中的 root 與 alias 指令的差別
  • Nginx 配置指令的執行順序(六)
  • 關于nginx中host, server_name, http_host的差別
  • 使用nginx後如何在web應用中擷取使用者ip及原了解釋
  • HTTP 标頭和 傳統負載均衡器
  • nginx proxy_next_upstream
  • nginx配置location總結及rewrite規則寫法
  • nginx配置url重寫
  • 搞懂nginx的rewrite子產品