寫給大忙人的nginx核心配置詳解(匹配&重寫、集羣、環境變量&上下文)

因爲當前不少應該都是先後端分離了,同時大量的基於http的分佈式和微服務架構,使得不少時候應用和不一樣項目組之間的系統相互來回調用,關係複雜。若是使用傳統的作法,都在應用中進行各類處理和判斷,不只維護複雜、容易出錯,還大大增長開發、調試的工做量,在nginx中,有很多的非功能類實際上是能夠幫咱們處理掉的,因此,對於現代開發人員來講,有必要對nginx的location比較熟悉,以便達到事半功倍的效果,好比說,平常的圖片上傳就是個例子,咱們能夠將圖片上傳到特定的目錄,而後配置nginx對於用戶上傳的圖片,都轉發到特定的目錄,該目錄不必定是nginx的html目錄,甚至是掛載的盤,這樣對於通常的應用來講,既能夠按應用規劃設置文件服務器,也避免了須要安裝和維護ftp服務器軟件的工做。php

 nginx配置

由於Nginx是模塊化架構,每一個模塊都會有一系列本身引入的指令,這些指令一般包含在指令塊中,好比events模塊,就有一個events塊。以下所示:html

events {
	worker_connections 1024;
}

對於最經常使用的部分,指令塊一般層層嵌套。例如:linux

http {
	server {
		listen 80;
		server_name example.com;
		access_log /var/log/nginx/example.com.log;
		location ^~ /admin/ {
			index index.php;
		}
	}
}

默認狀況下,之塊會繼承父塊中聲明的設置,除非明確覆蓋。nginx

在nginx的配置中,語法比較複雜,並且不一樣的指令,可能規則徹底不一樣。git

好比root僅接受一個字符,聲明服務於網站的文件的根路徑。github

模塊中一般定義了能夠用於指令中的變量,變量以$開頭。某些指令中不容許使用變量,好比error_log,此時它會被當作字面量處理。web

指令的值能夠帶雙引號、帶單引號、不帶引號,除非使用了特殊符號,此時須要用引號括起來以免nginx解析誤解,對於特殊符號須要當作字面量使用的,須要用\,好比$。正則表達式

 

nginx的基本模塊包括Core、Events(主要是聲明網絡機制,某些參數對系統的性能影響較大)、Configuration,這三個模塊提供了整個基礎架構。spring

nginx使用多進程架構。sql

核心模塊的主要指令:

  • error_log:聲明日誌文件的位置,error_log /file/path level;格式,默認是logs/error.log error。main,http, server,location級別均可以自定義。
  • thread_pool:聲明一個可供aio指令使用的線程池。主要用於服務於異步較大的文件請求時提升性能,thread_pool name threads=number [max_
  • queue=number];默認爲thread_pool default threads=32 max_queue=65536;。
  • worker_processes:聲明實際工做進程數,默認狀況下,nginx會使用檢測到的cpu數量而不是1,這一點現代系統基本上都是動態判斷,不像早期同樣默認爲單核,甚至內存都是動態本身判斷和設置。
  • worker_cpu_affinity:聲明進程跟cpu的親和關係,通常僅在多核下使用,格式worker_cpu_affinity 1000 0100 0010 0001;每組表明一個進程,每組中的1表明第幾個核心。

 

events模塊的主要指令包括(這些指令必須聲明在events塊中):

  • use:聲明使用的事件模型,現代linux通常都應該使用epoll。
  • worker_connections:聲明工做進程能夠同時處理的併發鏈接數。

 

配置模塊的主要指令包括:

  • include指令,在聲明的位置插入指定文件的內容,跟spring的import/mybatis的sql同樣。nginx內置模塊化的文件包括nginx.conf、mime.types、fastcgi_params、proxy.conf、sites.conf,include的值支持通配符。

HTTP Core模塊

HTTP Core模塊包含了HTTP服務器的全部基礎塊、指令以及變量,其默認啓用,實際上它也是最重要的一個模塊。它包含三個主要的塊:http,server,location。

  • http塊位於最高層,定義了全部和http相關的指令和塊。
  • server塊聲明一個網站,必須聲明在http塊內。
  • location塊聲明應用於網站內特定路徑的一組設置,能夠聲明在server塊內,或者嵌套在其餘location內。

一個典型的http配置結構以下:

主要指令包括:

  • listen:聲明監聽的地址,listen [address][:port] [additional options];應用於server塊。
  • server_name:爲server定義一個或多個主機名,server_name hostname1 [hostname2…];若是一個nginx服務提供多個網站時,該值能夠用來進行區分。應用於server塊。
  • tcp_nopush:啓用或者禁用TCP_NOPUSH (FreeBSD)/TCP_CORK(Linux) socket選項,僅在sendfile啓用時有效,其做用是nginx儘可能在一個tcp包中傳輸全部HTTP響應頭。應用於全部塊。
  • sendfile:若是啓用,nginx會使用sendfile內核調用處理文件傳輸,不然nginx會本身傳輸。應用於全部塊。

路徑相關指令包括:

  • root:定義服務客戶端請求的根目錄,默認爲html。應用於全部塊以及if。
  • alias:聲明用來提取文件時的別名路徑,根路徑不變,應該主要是用於對外公共接口的內部地址變了。
  • error_page:聲明特定HTTP返回碼的替換頁面。格式爲error_page code1 [code2…] [=replacement code] [=@block | URI]。應用於全部塊以及if。
  • index:定義nginx的默認頁面,默認爲index.html,能夠聲明多個。應用於全部塊。

客戶端請求相關的指令包括:

  • keepalive_requests:一個長鏈接最多能夠請求的數量,默認100,可應用於http, server, location。
  • keepalive_timeout:定義長鏈接的超時時間,默認75,第二個參數的值會經過http包頭傳給客戶端,格式:keepalive_timeout time1 [time2];應用於http, server, location。
  • send_timeout:聲明nginx多久後關閉未活動鏈接,客戶端中止傳輸數據開始計算未活動,默認60秒。
  • client_body_buffer_size:聲明用於存放客戶端請求體的緩存大小,默認8k或者16k,具體是系統架構而定。

限制相關的指令包括:

  • limit_except:設置僅支持哪些HTTP方法。應用於location。例如:
location /admin/ {
	limit_except GET {
		allow 192.168.1.0/24;
		deny all;
	}
}

格式爲:

limit_except METHOD1 [METHOD2…] {
	allow | deny | auth_basic | auth_basic_user_file | proxy_pass | perl;
}
  • limit_rate:設置每連接每秒鐘的流量,默認不限,應用於http, server, location, if。
  • internal:聲明本location僅適用於內部訪問,也就是必須經過rewrite才能訪問。

文件和緩存相關的指令:

  • directio:當文件超過特定大小時,使用Direct I/O系統機制直接從存儲設備讀取。應用於http, server, location。

其餘指令:

  • merge_slashes:是否合併連續的/爲單個/,好比將http://website.com//documents/轉換爲http://website.com/documents/,默認狀況下會報404。應用於http, server, location。
  • resolver:聲明nginx使用的自定義的DNS服務器。
  • underscores_in_headers:聲明自定義HTTP請求頭中是否容許下劃線名字,默認爲不容許,http頭中通常爲-分隔。
  • post_action:聲明請求執行完成後,nginx調用的uri,特殊狀況下可用,好比PV統計。

模塊變量

HTTP Core模塊包含了不少的變量,分爲三類:第一類是在Http請求頭中傳遞的,第二類是http響應頭中的,第三類是徹底nginx生成的。參考nginx http server第三版 90頁。

nginx容許用戶聲明樣式匹配指定的uri,location的語法爲:
location [=|~|~*|^~|@] pattern { ... }
第一個可選的參數是修飾符,各修飾符詳解以下:

  • =修飾符:徹底匹配,也就是直接常量比較。
  • 無修飾符:必須以聲明的樣式開頭,也就是like 'pattern%',一般servlet上下文匹配就是無修飾符的模式。
  • ~修飾符:請求的URI必須大小寫敏感的匹配聲明樣式的正則表達式。如:
server {
	server_name website.com;
	location ~ ^/abcd$ {
		[…]
	}
}
  • ~*修飾符:請求的URI必須大小寫不敏感的匹配聲明樣式的正則表達式。
  • ^~修飾符:和無修飾符相似,區別在於若是當前location匹配請求,則不會繼續搜索其餘的location。
  • @修飾符:定義一個命名location塊,這些塊不對外開放訪問,僅用於內部轉發。

搜索順序和location匹配優先級

不少時候,咱們定義的不止一個location,一般至少會有兩個,一個是根自己,一個指向後端服務。因此咱們須要理解nginx接收到一個請求以後,它如何肯定匹配的location。定義在配置文件中的location順序對於一個請求是否優先匹配沒有關係,nginx搜索匹配的樣式的順序以下:

  1. =修飾符的location
  2. 無修飾符的location(若是精確匹配的話)
  3. ^~修飾符的location
  4. ~/~*修飾符的location
  5. 無修飾符的location(若是前綴匹配的話)

Rewrite模塊

這個模塊的目的就是爲了URL重寫,URL重寫是SEO的關鍵元素之一。URL重寫由rewrite指令執行,它接收一個樣式和一個替換URI。

正則表達式規則參考nginx http server第三版P103。
注意,由於正則表達式的{}和nginx指令塊衝突,因此若是要使用,必須放到引號中。
捕獲,正則表達式中用()括起來的內容會被捕獲到一個個內置變量中,$N,N爲捕獲的索引,從1開始。捕獲的變量能夠做爲指令的值。()也一般和|一塊兒使用,二選一。命名捕獲使用?<name>語法設置,例如^/(?<folder>[^/]+)/(?<file>.*)$。
在nginx中,在正則表達式中捕獲的值,能夠在後續指令中使用,只要不被覆蓋便可。

server {
	server_name website.com;
	location ~* ^/(downloads|files)/(.*)$ {
		add_header Capture1 $1;
		add_header Capture2 $2;
	}
}

nginx區份內外部請求,內部請求由error_page, index, rewrite,try_files, add_before_body, add_after_body生成。內部請求還分兩類:

  • 內部重定向(Internal redirects):最多見的內部重定向是rewrite。
  • 子請求(Sub-requests):內部自動觸發,通常用的少。

簡單的重定向以下:

server {
	server_name website.com;
	root /var/www/vhosts/website.com/httpdocs/;
	location /storage/ {
		internal;
		alias /var/www/storage/;
	}
	location /documents/ {
		rewrite ^/documents/(.*)$ /storage/$1;
	}
}

Rewrite模塊的指令包括:

  • rewrite:爲當前請求重寫URI,格式爲rewrite regexp replacement [flag];flag的取值以及含義爲:
    • last:當前的重寫規則是最後一個,當前重寫應用以後,就去尋找新匹配的location。
    • break:當前重寫規則應用以後,再也不找新的location。
    • redirect:返回302以及新的URI地址。
    • permanent:返回301以及新的URI地址。

    若是聲明的URI以http://開頭,nginx自動使用redirect標誌。

    可應用於server,location,if。

  • break:用來防止後續重寫,後面的重寫都會被忽略。
  • return:停止處理請求,返回聲明的狀態碼或聲明的文本。狀態碼爲204, 400, 402 to 406, 408, 410, 411, 413, 416, and 500 to 504。
  • set:初始化或定義變量。
  • uninitialized_variable_warn:若是爲on,nginx爲每一個遇到的未初始化的變量記錄日誌。
  • rewrite_log:若是爲on,Nginx爲每一次重寫記錄notice級別的日誌。

upstream模塊

任何以_pass結尾的指令都接受到一組服務器的引用。聲明一組服務器的第一步是在http的upstream塊內聲明一個或多個server指令,以下:

http {
	upstream MyUpstream {
		server 10.0.0.201;
		server 10.0.0.202;
		server 10.0.0.203;
	}
	[…]
}

而後在server塊內引用聲明的upstream,以下:

server {
	server_name example.com;
	listen 80;
	root /home/example.com/www;
	# Proxy all requests to the MyUpstream server group
	proxy_pass http://MyUpstream;
	[…]
}

nginx提供多種負載均衡機制,P248。從Nginx 1.9.0開始,新增的Stream模塊支持TCP負載均衡,這意味原來必須使用LVS或者HAPROXY做爲負載均衡機制的模式能夠採用NGINX了。
要啓用線程池,必須使用--withthreads參數編譯nginx,對於常常文件下載的應用,應使用以下配置:

location /downloads/ {
	aio threads;
	directio 8k;
	sendfile on;
}

 

ngx_http_log_module模塊負責以聲明的格式記錄請求日誌。
其主要的兩個指令是:

  • log_format:聲明日誌格式。格式爲:log_format name [escape=default|json|none] string ...;默認爲log_format combined "...";日誌格式能夠包含公用變量以及僅在日誌寫的時候存在的變量。配置老是包含預約義的「combined」格式,以下:
  • access_log:設置寫日誌的路徑、格式以及額外配置。格式爲:
access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]];
access_log off;

默認爲access_log logs/access.log combined;

nginx獲取環境變量的值

首先參考centos下nginx安裝與配置安裝所需模塊。

With Lua

If you are using Openresty, or have the ngx_lua module and ngx_devel_kit module installed, you are in luck.

You first need to declare what variables you'll be needing somewhere in your nginx.conf file using the envdirective:

env API_KEY;

After that, when you want to access the environment variable, you can use a combination of set_by_lua and os.getenv, like this:

http {   ...   server {     location / {       set_by_lua $api_key 'return os.getenv("API_KEY")';       ...     }   } }

In this example we are assigning the environment variable to one of Nginx variables; we can use $api_key as a regular nginx.conf variable.

With Perl

Using Lua was our preferred approach, since we have OpenResty. If you can't use Lua, a second solution involves using Perl. The first part is similar; you must declare the variables he uses using env:

env API_KEY;

After that, you can combine perl_set and some Perl to do the same thing as before:

http {   ...   server {     location / {       perl_set $api_key 'sub { return $ENV{"API_KEY"}; }';       ...     }   } }

You will need to have the ngx_http_perl_module module enabled in order to be able to use this technique.

相關文章
相關標籤/搜索