前置知識章節:
1.介紹、安裝、hello world、location匹配✅
2.反向代理、負載均衡、快取服務、靜態資源訪問✅
3.當前章節?:日誌管理、http限流、https配置,http_rewrite模組,第三方模組安裝,結語。✅
日誌管理
nginx裡面有訪問日誌和錯誤日誌,訪問日誌記錄記錄客戶端訪問nginx的每一個請求;錯誤日誌記錄發生錯誤的請求。
access_log
access_log用於配置訪問日誌,日誌的格式可以根據log_format指令來進行自定義。
?log_format用於定義訪問日誌的格式。log_format指令的第一個引數是格式名,可以給當前格式定義一個名字,第二個引數是格式字串,支援一些內部變數語法,比如$remote_addr
會獲取到請求的客戶端的IP地址。log_format只可以配置在http塊中。
log_format示例:
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
log_format mylog '[client_ip:] $remote_addr [time:] $time_local [user_agent:] "$http_user_agent"';
log_format語法說明:
- 整個字串使用
''
包裹,內部可以使用$
開頭的變數,比如$remote_addr
會獲取到請求的客戶端的IP地址,其他字元都作為顯示效果,比如上面使用的""
只是用於包裹資料而已。[]
,-
,:
也是這樣的。
?access_log指令可以用來指定訪問日誌的儲存位置和日誌格式。access_log指令的第一個引數是訪問日誌的儲存路徑,第二個引數是使用的格式的格式名.access_log可以使用在http, server, location, location的if, limit_except等塊中。
語法格式:
access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]];
* path是日誌儲存路徑
* format用於定義格式,是log_formate的名字,
* buffer=size 為存放日誌的緩衝區大小
* flush=time 為將緩衝區的日誌刷到磁碟的時間
* gzip[=level] 表示壓縮級別
* if一般不配置
access_log off; # 關閉訪問日誌記錄
?預設在nginx.conf中配置了access_log的預設配置:
nginx日誌常見可用變數:(更多變數可以參考:英文文件,某CSDN部落格)
內建變數 | 說明 |
---|---|
$remote_addr | 客戶端的IP地址 |
$remote_user | 客戶端使用者名稱,用於記錄瀏覽者進行身份驗證時提供的名稱,如果沒有登入則為空 |
$time_local | 訪問的時間與時區 |
$request | 請求的URI和HTTP協議 |
$status | 記錄請求返回的HTTP狀態碼 |
$body_bytes_sent | 傳送給客戶端的檔案主體 |
$http_referer | 請求來源的URL地址 |
$http_user_agent | 客戶端瀏覽器資訊 |
$http_x_forwarded_for | 經過的客戶端IP地址列表,如果請求是代理轉發的,那麼原始的客戶端IP應該在這個欄位裡面 |
error_log
- error_log是錯誤日誌,只有訪問錯誤的時候才會記錄下來。不支援格式定義。
- error_log的語法是:
error_log file [level];
- error_log指令的第一個引數是錯誤日誌儲存路徑,第二個引數是日誌級別。
- 日誌級別有debug,info,notice,warn,error,crit幾個等級。debug的日誌記錄是最完善的,crit只記錄“致命”級別的錯誤。
- error_log可以設定在http、server、location、location的if塊中配置。
- 指令
error_log /dev/null
用於關閉錯誤日誌。/dev/null
在linux中可以認為是一個無底洞,可以把它當作垃圾桶。
日誌檔案切割
對於日誌檔案有些版本會自動切割,有些版本不會,也就是說,如果你的服務端跑了一年,那麼一年的訪問日誌都儲存在access.log中,很明顯,這不是一個好的處理,這樣不方便我們在發生錯誤時分析日誌。所以通常都會對日誌檔案進行切割,根據業務需求可能按天、按周來進行切割。
?自動切割:如果你的nginx能夠自動切割日誌,那麼你就不需要看了,怎麼判斷有沒有自動切割功能呢,檢視一下/etc/logrotate.d
下是否有nginx檔案,logrotate用於日誌切割,linux自帶的,但內建的除了切割還有一些其他的操作,比如定時清除,有需要的可以自行看一下vim /etc/logrotate.d/nginx
?下面教的是使用定時任務自動切割日誌檔案,當然如果你喜歡手動也沒問題。
我們只需要定義一個定時任務即可。
1.先提一下crontab的語法,用示例來簡單講解語法:
示例:0 * * * * /root/nginx-cut-log.sh>/dev/null 2>&1
crontab語法:
第一個引數:分(取值0-59,*代表每一個),對應上面第一個0
第二個引數:時(取值0-23),對應上面第二個0
第三個引數:日(取值1-31)
第四個引數:月(取值1-12)
第五個引數:星期(取值0-6,0代表星期日)
第六個引數:要執行的命令
額外的說明:
上面的命令中`>/dev/null 2>&1`用於把定時任務的標準輸出和錯誤輸出都重定向到“垃圾桶/黑洞”中。
2.然後編寫一個切割日誌檔案的指令碼檔案nginx-cut-log.sh
(命名隨意):
#!/bin/bash
#定義日誌目錄變數
logs_path="/var/log/nginx/"
#切割日誌,其實就是拷貝與新建而已。
#`date -d yes +"%Y%m%d"`中``可以用來獲取linux命令的執行結果,可以參考https://www.cnblogs.com/asxe/p/9317811.html
mv $logs_path/access.log $logs_path/access-`date +"%Y-%m-%d-%H-%M"`.log # 測試的時候請開啟這一個關閉下面的,這個用於每分鐘執行一次。
#下面的這個應該用於每天執行的情況,因為以日期命名了檔案
#mv $logs_path/access.log $logs_path/access-`date -d "1 day ago" +"%Y-%m-%d"`.log
#上面的操作類似於重新命名,所以原本的access.log會沒了,使用下面的命令讓nginx重新生成一個access.log.
/nginx -s reopen;
3.記得給指令碼檔案增加執行許可權:
chmod +x nginx-cut-log.sh
4.然後定義一個定時任務:
執行命令crontab -e
,並在那裡附加下述命令:
* * * * * /root/nginx-cut-log.sh>/dev/null 2>&1
上面的用於每分鐘都建立新的日誌檔案的測試,正式使用應該前面兩個是一個準確的值,比如0 0 * * * /root/nginx-cut-log.sh>/dev/null 2>&1
代表每天零點零分執行。
5.然後重啟crond:執行命令crond restart
6.然後你在/var/log/nginx/目錄下等一分鐘看是否會建立新的access.log檔案。如果建立了,就說明我們的日誌切割成功執行了。當然,記得測試完後清除我們上面在crontab -e
中輸入的命令,因為那個代表了每分鐘都執行。
自定義錯誤頁
- 自定義錯誤頁其實是一個非常小的內容。用於定義nginx的http請求發生錯誤的時候顯示的頁面
- 語法:
error_page code ... [=[response]] uri;
- 示例:
error_page 500 502 503 504 /50x.html;
:代表http響應碼為500,502,503,504時,返回各自location的root下的/50x.html
error_page 400 http://xxxx.html
:代表http響應碼為400時,返回http://xxxx.html
error_page 404 = @fallback;
還支援內部重定向,@fallback
是自定義的一個內部重定向location.error_page 400=200 http://xxxx.html
:發生400錯誤時,返回http://xxxx.html
,並修改返回的響應碼為200.
http訪問限流
?訪問限流依靠ngx_http_limit_conn_module模組,ngx_http_limit_req_module模組。ngx_http_limit_conn_module用來限制連線數。ngx_http_limit_req_module用來限制請求數。
?為什麼需要限流呢?那是為了防止過量的請求給服務端帶來過大的壓力。
❓連線跟請求的區別:
- http也是應用層協議,也是tcp的一種,http請求其實是使用tcp來連線請求的。在HTTP/1.0中,大多是一次連線,一次請求的。但它其實也支援
Connection: keep-alive
,如果在響應的Header中有這Connection: keep-alive
,那麼就會維持連線,直到響應/請求的Header中有Connection: close
才斷開連線(超時也會,keep-alive也是有時效的)。在Connection: keep-alive
的時候一個連線可以發起多個請求。
如下圖,我連續請求一張圖片,第一次的時候initial connection初始化了tcp連線,而第二次請求的時候沒initial connection,這代表連線沒用埠:
百度的請求是支援Connection: keep-alive
的,你可以嘗試在谷歌瀏覽器中開啟百度的一張圖,並開啟它的請求Timing來檢視是否每一次都initial connection(初始化連線,這代表建立新的tcp連線,而stalled代表檢測是否有舊的可用的tcp連線,所以上面的第二種圖中沒用initial,只有stalled,stalled使用了沒斷開的tcp連線)中測試。
限制請求數
語法
?limit_req_zone:用來設定請求限制規則,
- 語法
limit_req_zone key zone=name:size rate=rate;
- key用於定義請求限制的物件,比如為
$server_name
的時候,代表限制虛擬主機的請求次數,為$binary_remote_addr
或$remote_addr
時代表限制同一個IP的客戶端的請求次數。 - zone=name:size中,name是當前這個請求限制規則空間的名字,size是這個空間的大小。
- key用於定義請求限制的物件,比如為
- 使用位置 : limit_req_zone只能配置在Http塊。
- 示例:
limit_req_zone $binary_remote_addr zone=req_zone:10m rate=1r/s;
?limit_req:與limit_req_zone配合,用來定義限制請求次數。
- 語法:
limit_req zone=name [burst=number] [nodelay | delay=number];
- zone=name中name式limit_req_zone的名字
- burst用來定義突發大小,例如在
limit_req zone=req_zone burst=3
中,限制請求次數是1,那麼突發的2個請求會放到下一秒再執行。
- 使用位置 :limit_req可以用在http, server, location
- ?超出請求限制的請求,會返回503.
- 示例:
limit_req zone=req_zone burst=3 nodelay;
使用
1.配置nginx:
2.重啟之後測試:你可以在一秒內連續在瀏覽器中重新整理,如果重新整理多次之後突然響應503,那說明請求被限制了。或者你可以在/var/log/nginx/error.log
中看到limiting requests
限制連線數
語法
?limit_conn_zone:用來設定連線限制規則,語法limit_conn_zone key zone=name:size;
- key用於定義連線限制的物件,比如為
$server_name
的時候,代表限制虛擬主機的連線次數,為$binary_remote_addr
或$remote_addr
時代表限制同一個IP的客戶端的連線次數。 - zone=name:size中,name是當前這個連線限制規則空間的名字,size是這個空間的大小。
- limit_conn_zone只能配置在Http塊。
- 例如:
limit_conn_zone $binary_remote_addr zone=addr:10m;
?limit_conn:與limit_conn_zone配合,用來定義限制連線次數。語法limit_conn zone number;
- number是限制的次數。
- limit_conn可以用在http, server, location。
- 例如:
limit_conn addr 1;
,假如addr是一個限制同一個IP的客戶端的連線次數的規則,代表同一個IP的客戶端的併發連線為1.
?補充:並不是所有的連線都會被計算,只有併發壓力的連線才計算,比如上面的limit_conn addr 1;
代表每個IP只能有一個連線,但如果你給不了nginx請求壓力的話,那麼假設你發起兩個連線,nginx馬上處理完第一連線之後,後面來的第二個連線此時並不算併發連線(這時候就限制失敗了),所以如果你下面測試的話,可以訪問處理比較慢的資源,讓nginx持續地持有這個連線,然後我們再發起另外一個連線,這樣才能測試成功。下面是官網文件的一段話:
Not all connections are counted. A connection is counted only if it has a request being processed by the server and the whole request header has already been read.
測試
上面說了, 要使用一個響應比較慢的資源,所以我們這裡使用反向代理來作為響應。
1.新建一個後端服務端介面:(下面示例基於spring boot,我讓它sleep了10秒,也就相當於要處理十秒才能響應資料。此時有充足的時間來讓我們發起第二次資料)
2.配置default.conf:
3.測試訪問:
- 首先訪問一下
http://192.168.31.128/user/info
,這個是我的代理後的請求介面,響應時間至少需要十秒 - 在上面響應的十秒內,用另外一個視窗訪問一下
http://192.168.31.128/user/info
,這個會直接得到503,而不是等待十秒的響應。
補充:
limit_rate
可以用來限制響應的傳輸速度,這裡沒講。
https配置
?注意,此時的https配置並沒有太多實戰意義,因為證照都是正規機構發的話,瀏覽器才能夠識別成安全的。這裡的教學只是做個認知,就是知道怎麼配置,證照什麼的是都是應該從正規機構申請的。
- 使用
nginx -V
檢視編譯引數,如果有--with-http_ssl_module
,那麼就代表啟用了ngx_http_ssl_module模組。預設的YUM方式安裝是攜帶這個模組的。如果你是使用了編譯安裝的,那麼自行去加上吧。
Https有什麼好處,處理什麼情況,這些自己查吧。
Https會使用幾種加密方式,非對稱加密用於身份驗證和金鑰協商,對稱加密用於採用協商的金鑰來對資料進行加密。另外雜湊演算法用於檢驗資料完整性。
對稱加密使用同一個金鑰。
非對稱加密,公鑰用於加密,私鑰用於解密
Https簡單流程:首先發起非對稱加密,服務端將公鑰傳送給客戶端(此時傳送的是證照,證照客戶端是需要校驗的),如果證照合法,那麼客戶端使用偽隨機數來生成一個會話金鑰,使用證照加密會話金鑰並傳輸給服務端。服務端使用私鑰來解密得到會話金鑰。然後後面傳輸的資料使用此時兩端都知道的會話金鑰來加密資料。?從這個簡單流程,應該我們只需要關心兩條?,一個是證照,一個是私鑰。
使用
生成證照
1.生成證照私鑰:此處生成的私鑰用於提交給CA來生成證照認證簽名檔案。
openssl genrsa -out server.key 2048
用於生成金鑰Key,執行這個命令後需要輸入一個密碼,會基於這個密碼來生成私鑰。
genrsa
代表使用RSA來生成私鑰,openssl rsa
代表從私鑰中獲取公鑰。- 可選的
-des3
:指定生成的金鑰使用des3方式進行加密,這樣的話每次使用都需要輸出密碼來解密。 - out 檔案路徑
:用於指定生成的key的位置。2048
是金鑰的長度,長度越長,安全性越強,一般推薦使用2048。
2.建立伺服器證照的申請檔案server.csr。CSR檔案是您的公鑰證照原始檔案,包含了您的伺服器資訊和您的單位資訊,需要提交給CA認證中心稽核。
openssl req -new -key server.key -out server.csr
會提示輸入幾個內容:
- 如果你上面使用了-des3來生成證照私鑰,那麼第一行會是要求你輸入私鑰的解密密碼
server.key
:生成金鑰時輸入的密碼 Country Name (2 letter code) [XX]
:國家程式碼,如CN,可以不填,直接回車跳過即可。State or Province Name (full name) []
:省份名稱,可以不填,直接回車跳過即可。Locality Name (eg, city) [Default City]
:城市名稱,可以不填,直接回車跳過即可。Organization Name (eg, company) [Default Company Ltd]
:機構名稱,可以不填,直接回車跳過即可。Organizational Unit Name (eg, section) []
:組織單位名稱,可以不填,直接回車跳過即可。Common Name (eg, your name or your server's hostname) []
:使用SSL加密的域名。注意這裡要配成你的網站的域名,不然在訪問的時候會說"這個證照不屬於這個網站(?英文我忘記是什麼了)",如果你看到這樣的錯誤的話,你就應該知道是你的證照繫結錯了域名。比如可以輸入www.123.com
。Email Address []
:郵件地址,可以省略A challenge password []
:有些認證機構需要這個密碼,一般為空An optional company name []
:可選的公司名稱,省略即可。
?其實上面這個建立證照檔案也就是自己用用而已,正式的時候都會去證照機構中申請,比如在阿里雲或者騰訊雲中申請一個免費的證照,個人用的話申請一個免費的就可以了。【PS:證照也是有區別的,一些證照只會加密資料,不能用於認證,比如說有些網站訪問的時候就會顯示XXX公司,其實這就是在證照中做了企業認證。】
3.生成CRT證照認證檔案:
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
* X509用於自簽名
* -req:x509工具預設以證照檔案做為inputfile(-in file),指定該選項將使得input file的file為證照請求檔案。
* -days 30 用於設定證照的有效期
* -in:用於指定CSR證照申請檔案
* -signkey:用於指定簽名的私鑰
* -out:用於指定輸出的CRT證照認證檔案的路徑。
4.完成:
那麼此時生成了一個.crt
檔案和.key
檔案。
配置nginx
簡單配置一個新的server:
server {
server_name www.123.com;
listen 443 ssl;
ssl_certificate /etc/nginx/ssl_key/server.crt;
ssl_certificate_key /etc/nginx/ssl_key/server.key;
location / {
root /usr/share/nginx/html;
}
}
- ssl_certificate用於配置服務端上CA證照的位置
- ssl_certificate_key用於配置服務端上CA私鑰的位置
- 在舊版本中
ssl on
用來開啟ssl,現在可以使用listen 443 ssl
來代替。 - 更多配置可以自行參考ngx_http_ssl_module
測試
為了儘量達到模擬,所以我們手動配置一個dns,這樣的話我們就相當於有一個虛假的域名了。
訪問我們的虛假網站www.123.com
:
但由於我們是本地環境,它始終會報錯,它還是會在瀏覽器中顯示不安全,但https是已經配置成功了的。我們選擇強行訪問的話,連結欄仍熱會報紅:
只是因為我們是自己生成證照,導致證照頒發機構不可信而已,如果我們是從網上申請的證照,那麼此時證照頒發機構應該是可信的。
補充
?正規域名的https配置可以稍微參考阿里雲nginx配置https文件
HttpRewrite模組
if
if在nginx文件中
?if屬於ngx_http_rewrite_module
模組。
?if可以做一些的判斷,根據條件來進行不同的處理,可以使用在server和location中。
?if的使用場景:
- 場景一:假如你想讓沒有攜帶指定header的請求返回403的話,這樣的請求判斷需要藉助if。
- 場景二:如果瀏覽器是IE瀏覽器,返回指定資料
- 。。。
下面是一個例子,就是如果瀏覽器是谷歌瀏覽器,就返回503。
#禁止chrome訪問:如果$http_user_agent`如果包含Chrome,就禁止訪問。
if ($http_user_agent ~ Chrome) {
return 503;
}
if的語法:
- 判斷條件:
=
用於判斷兩個值是否相等,例如if ($request_method = POST)
!=
用於判斷兩個值是否不相等~
:大小寫敏感的正則匹配,與後面的正則搭配使用,例如:if ($http_user_agent ~ MSIE)
代表$http_user_agent
如果包含MSIE,就為true。~*
:對大小寫不敏感的正則匹配,與後面的正則搭配使用。!~
:如果~
結果為true,則!~
為false!~*
:如果~*
結果為true,則!~*
為false-f
:如果檔案存在,為true。例如:if (-f $request_filename)
!-f
:如果目錄存在,檔案不存在,為ture;目錄和檔案都不存在,為false。例如:if (!-f $request_filename)
-d
:如果請求的目錄存在,則為true!-d
:如果請求目錄的上級目錄存在,目錄不存在,為true;如果上級目錄和目錄都不存在,為false.
- if可以使用變數來判斷,可用變數有全域性變數和自定義變數。
下面是可以用作if判斷的全域性變數
全域性變數
引數名 | 說明 |
---|---|
`$arg_PARAMETER | PARAMETER是變數名,可以根據不同的PARAMETER獲取請求行中的指定引數,也就是URL中的引數。 |
$args |
URL中的查詢引數。,比如https://www.baidu.com/baidu?wd=nginx&tn=monline_4_dg&ie=utf-8 中的wd=nginx&tn=monline_4_dg&ie=utf-8 |
$binary_remote_addr |
二進位制的客戶端IP地址。 |
$content_type |
請求頭中的Content-Type欄位。 |
$cookie_COOKIE |
客戶端cookie資訊 |
$document_root |
當前請求在root指令中指定的值。 |
$document_uri |
包含請求引數的原始URI |
$host |
請求頭中的Host 欄位 |
$http_HEADER |
HEADER是一個變數,可以用於獲取請求頭中的引數值。 |
$http_user_agent |
客戶端agent資訊,客戶端瀏覽器資訊 |
$http_cookie |
客戶端cookie資訊 |
$is_args |
如果有url引數,則為?;無則為空。 |
$limit_rate |
nginx配置的limit_conn 的數值。 |
$query_string |
與$args 功能一致 |
$remote_addr |
客戶端的IP地址 |
$remote_port |
客戶端的埠 |
$request_filename |
當前請求的資原始檔的路徑名 |
$request_method |
請求的方法,GET 、POST 之類的。 |
$request_uri |
包含請求引數的原始URI,不包含主機名 |
$scheme |
http還是https |
$server_addr |
服務端地址 |
$server_name |
服務端名稱(域名) |
$server_port |
服務端接收請求的埠 |
$server_protocol |
http協議版本,1.0,1.1,HTTP/2 ? |
$uri |
與$document_uri 相同 |
自定義變數:
除了使用全域性變數來判斷,還可以自己通過set $變數名 值
設定變數,例如:
location / {
root /usr/share/nginx/html;
default_type text/html;
set $flag "";
if ($http_user_agent ~ Chrome) {
set $flag "Chrome";
}
# 這裡繞了一圈只是為了說明,可以使用我們自己設定的變數
if ($flag = 'Chrome') {
return 200 "hello";
}
}
set的值除了是一個字面值,還可以是一個全域性變數,比如set $web_agent "${http_user_agent}";
。set的使用應該是面向場景的,所以這裡只做個開頭,當你想要某個值來做判斷的時候,你可以自己去探究一下這個值該怎麼設定。
重定向rewrite
?rewrite屬於ngx_http_rewrite_module
模組。
?rewrite用於重寫url和重定向,一個比較常見的用途是,比如用於http重定向https,你原本訪問http://example.com
,我幫你強制跳轉到https://example.com
;比如某檔案位置遷移了,訪問舊的位置,重寫成遷移後的位置;比如根據不同瀏覽器重定向到不同頁面你是IE瀏覽器,我就幫你轉到一個特定的頁面;這就是rewrite乾的活,做一些重定向的活。
?語法是:rewrite regex replacement [flag]
,可以使用在server, location, if中。
- regex是正則,注意傳入的資料是uri,不包括域名,只包含訪問的資源路徑。
- replacement是重定向的路徑。可以使用 ($1,$2)來獲取正則中的匹配結果或使用全域性變數來拼接URL。
- flag可以是以下幾個:
- last:會內部重新發起一個重定向目錄的請求,可以匹配到nginx的location。
- beak:匹配後,會內部從root目錄查詢重定向的目錄,不會匹配location。
- redirect:會返回302給瀏覽器,讓瀏覽器發起新的請求,代表臨時重定向,瀏覽器不會快取。
- permanent:會返回301給瀏覽器,讓瀏覽器發起新的請求,代表永久重定向,瀏覽器會進行快取,下次訪問這個地址的時候,瀏覽器直接重定向,不需要訪問nginx再重定向。
實驗一:測試regex匹配物件的是什麼:
server {
listen 80;
server_name 127.0.0.1;
location / {
rewrite (.*) http://192.168.48.129$1 redirect;
}
}
當訪問nginx所在機器192.168.31.128/aaa/bbb
的時候,由於上面的規則是重定向到http://192.168.48.129$1
,所以得出結論,regex對應的部分就是有/
開頭的uri部分。
實驗二:重定向到指定的頁面:
server {
listen 80;
server_name 127.0.0.1;
location / {
#只有匹配成功的時候才重定向,訪問/rewrite/aaa時重定向,訪問/aaa時不重定向
rewrite ^/rewrite/(.*) http://192.168.48.129/$1 redirect;
#訪問http://192.168.31.128/rewrite時,重定向到http://192.168.48.129
#訪問http://192.168.31.128/rewriteaaa,重定向到http://192.168.48.129
#rewrite ^/rewrite http://192.168.48.129 redirect;
#訪問http://192.168.31.128/rewrite,內部重定向到http://192.168.31.128/hello
#root /usr/share/nginx/html;
#rewrite ^/rewrite /hello last;
#訪問http://192.168.31.128/rewrite,返回"root"+/hello.html資源
#root /usr/share/nginx/html;
#rewrite ^/rewrite /hello.html break;
}
location /hello{
default_type text/html;
return 200 "hello";
}
}
實驗三:與if配合重定向,假如瀏覽器是IE的,跳轉到指定頁面:
server {
listen 80;
server_name 127.0.0.1;
location / {
#訪問http://192.168.31.128/rewrite,返回"root"+/hello.html資源
root /usr/share/nginx/html;
# 如果http_user_agent中包含了chrome,那麼就重定向
if ($http_user_agent ~ Chrome) {
rewrite ^(.*)$ /chrome/$1 break;
}
rewrite ^/rewrite /hello.html break;
}
}
第三方模組
上面的例子中都是內建模組的內容,但也稍微提了一下第三方模組,比如在負載均衡中提到了fair和url_hash。對於需要使用第三方模組的,還是建議使用編譯安裝的方式,那樣新增第三方模組比較方便。
前置知識(編譯安裝)
1.先到官網下載編譯安裝用的tar包,或者wget http://nginx.org/download/nginx-1.12.1.tar.gz
【因為下面的演示的echo模組最高相容1.16,所以這裡安裝1.16】
2.解壓tar包:tar -zxvf nginx-1.12.1.tar.gz
3.cd nginx-1.12.1/
4../configure --prefix=/etc/nginx
,注意,編譯方式安裝,檔案目錄佈局與yum安裝方式的不太一樣。
5.make && make install
6.進入/etc/nginx/sbin
目錄下執行./nginx -v
,如果能夠正常輸出nginx版本,那麼就代表編譯安裝成功了。
?--prefix 用於指定nginx編譯後的安裝目錄
【docker內部的nginx也是編譯安裝的,如果你懂docker,那麼你可以通過修改docker的dockerfile來新增第三方模組】
【如果你是覆蓋安裝的,注意儲存之前的配置資訊。】
安裝第三方模組
安裝第三方模組需要我們重新編譯安裝,所以下面的過程是以編譯安裝為基礎的。
下面的安裝模組我們以echo模組為例。echo模組可以返回變數,比如echo $remote_addr;
代表把客戶端的IP作為響應資料。
1.從github上下載echo模組的原始碼:echo-nginx-module
或者直接在nginx所在的機器上wget https://github.com/openresty/echo-nginx-module/archive/v0.61.tar.gz
2.上傳到nginx所在的機器上。
3.解壓第三方模組echo模組:tar -zxvf v0.61.tar.gz
4.我們進入到之前的nginx原始碼目錄:cd nginx-1.12.1/
5.重新編譯安裝:./configure --prefix=/etc/nginx --add-module=/root/temp/echo-nginx-module-0.61
6.make && make install
7.進入/etc/nginx/sbin
目錄下執行./nginx -V
,如果能看到configure arguments: --prefix=/etc/nginx --add-module=/root/temp/echo-nginx-module-0.61
,那麼就代表編譯安裝成功了。除了這樣,你還可以嘗試在程式碼中新增echo指令來測試。
在還沒安裝之前:如果你在程式碼中使用echo的話,重啟nginx會報如下的錯誤: ![20200629210011](https://progor.oss-cn-shenzhen.aliyuncs.com/img/20200629210011.png)
nginx: [emerg] unknown directive "echo" in /etc/nginx/conf.d/default.conf:5
nginx: configuration file /etc/nginx/nginx.conf test failed
那麼如果我們安裝了之後,不報錯,並且訪問nginx服務端之後,返回的是客戶端的IP地址的話,那麼就說明第三方模組安裝成功了。
知識補充:
--add-module=第三方模組原始碼路徑
用於新增第三方模組,--add-module=/usr/local/nginx/third_module/echo-nginx-module-0.60
代表新增了echo模組。--with-模組名
表示啟用的nginx模組,如--with-http_ssl_module
代表啟用了http_ssl_module模組
沒有講到的內容
沒有講到的內容其實挺多的,但上面的應該是常見的內容了,學會了應該就夠日常使用了,後面有需要你自己去百度的時候應該就能看懂別人的配置了。
其他的內容由於優先順序不是很高,而且考慮篇幅問題,所以這裡沒有講解,下面列舉一下我覺得可能
?nginx還支援郵件服務,但可能比較少用。
?nginx與Keepalived搭配的高可用。【其實挺重要,大家可以自己搜尋學習一下】
?nginx也支援NFS(網路檔案系統),但有一些替代方案,比如對於Java來說的話,比較常見的是FastDFS(也依託nginx)了。
?網頁壓縮,可以使用GZIP來進行網頁壓縮,來減少傳輸的資料,但壓縮是需要系統去處理的,所以可能需要消耗一些CPU資源。自己有需求就去找找看吧。
?nginx與其他伺服器的比較,因為這篇文章重點不是這個,所以不講。
?如果你關心檔案傳輸方面的知識,那麼可以瞭解下send_file 和tcp_nopush對於資料傳輸的處理。
?sub_status模組,用來檢視nginx自上次啟動以來的工作狀態。包括處理的連線數、請求數等。
?geoip可以用於地區識別,比如基於IP判斷使用者的地區。
?http_slice_module模組可以用於大檔案分片的處理。
?如果你想拿來當面試談資,那麼IO多路複用模型可以瞭解一下,nginx.conf的events塊中其實可以修改nginx對於請求處理的IO模型,當問nginx為什麼那麼厲害的時候,IO多路複用模型也可以談一下。
?我這篇文章講了一些例如負載均衡的內容,但這並不代表你不需要額外學習nginx的內容了,因為我只是講了普通情況,如果你的業務複雜的話,那麼你最好仔細的看一下官方文件了。
?請認清,這只是一篇用於基礎理論瞭解的文章而已。