那些實(shí)用的Nginx規則
發(fā)布時(shí)間:2018-02-12 瀏覽:519打印字號:大中小
大家都知道Nginx有很多功能模塊,比如反向代理、緩存等,這篇文章總結下我們這些年實(shí)際環(huán)境中那些有用的Nginx規則和模塊,大部分是用法的概括及介紹。
先介紹Nginx默認已支持的內置功能,靠這些基本就滿(mǎn)足大部分的web服務(wù)需求。
proxy常用于兩類(lèi)應用場(chǎng)景,一類(lèi)是中轉,如異地科學(xué)的上網(wǎng)方式,另外一類(lèi)是到后端服務(wù)的負載均衡方案。
用反向代理時(shí)候,需要特別注意里面的域名默認是在nginx啟動(dòng)時(shí)候就解析了,除非reload否則一直用的是當初解析的域名,也就是說(shuō)不能動(dòng)態(tài)解析。
但這個(gè)問(wèn)題是可以通過(guò)別的模塊或者用內置字典變量方式來(lái)解決。
resolver 114.114.114.114;
server {
location / {
set $servers github.com;
proxy_pass http://$servers;
}
}
針對某個(gè)域名進(jìn)行中轉:
server {
listen 172.16.10.1:80;
server_name pypi.python.org;
location ~ /simple {
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://pypi.python.org;
}
}
注意如果是前后端域名不一樣的話(huà)需要處理proxy_redirect的301跳轉之類(lèi)的顯示,否則在跳轉時(shí)候會(huì )跳轉到proxy_pass的域名。
另外可以直接代理所有80端口的http流量:
server {
listen 80;
server_name _;
resolver 114.114.114.114;
set $URL $host;
location / {
proxy_pass http://$URL;
}
}
如果是想代理https的站點(diǎn)也不是不可能,只是需要自行處理CA證書(shū)導入即可,而且經(jīng)過(guò)https中轉的流量對nginx是透明的,也就是有證書(shū)的時(shí)候做竊聽(tīng)和劫持的情況。
這是代理的另外一個(gè)常見(jiàn)用法,通過(guò)upstream到多個(gè)后端,可以通過(guò)weight來(lái)調節權重或者backup關(guān)鍵詞來(lái)指定備份用的后端,通常默認就可以 了,或者可以指定類(lèi)似ip_hash這樣的方式來(lái)均衡,配置很簡(jiǎn)單,先在http區域添加upstream定義:
upstream backend {
ip_hash;
server backend1.example.com weight=5;
server backend2.example.com weight=5;;
}
然后在server里面添加proxy_pass:
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
做負載均衡的時(shí)候可以智能識別后端服務(wù)器狀態(tài),雖然可以智能地proxy_next_upstream到另外的后端,但還是會(huì )定期損失一些正常的“嘗試性”的連接,比如過(guò)了max_fails 次嘗試之后,休息fail_timeout時(shí)間,過(guò)了這個(gè)時(shí)間之后又會(huì )去嘗試,這個(gè)時(shí)候可以使用第三方的upstream_check模塊來(lái)在后臺定期地自動(dòng)探索,類(lèi)似這樣:
check interval=3000 rise=2 fall=5 timeout=2000 type=http;
這樣替代用戶(hù)正常的連接來(lái)進(jìn)行嘗試的方式進(jìn)一步保障了高可用的特性。
還有就是在做前端代理的時(shí)候也是這樣的方式,直接proxy_pass到后端即可,比如CDN的場(chǎng)景。
普通的防盜鏈是通過(guò)referer來(lái)做,比如:
location ~* \.(gif|jpg|png|bmp)$ {
valid_referers none blocked *.example.com server_names ~.google. ~.baidu.;
if ($invalid_referer) {
return 403;
}
}
再精細一點(diǎn)的就是URL加密,針對一些用戶(hù)IP之類(lèi)的變量生成一個(gè)加密URL通常是針對文件下載時(shí)候用到,可以通過(guò)openresty來(lái)寫(xiě)lua腳本或者是accesskey之類(lèi)的模塊來(lái)實(shí)現。
nginx里面支持正則匹配和變量配置,默認的變量比如remote_addr、request_filename、query_string、server_name之類(lèi)的,這些組合在一起可以做很多規則,或者還有日志里面status、http_cookie等。
還有在進(jìn)行多域名配置時(shí)候可以用通配符,比如:
server_name ~^(www\.)?(.+)$;
root /data/web/$2;
這樣就實(shí)現了自動(dòng)進(jìn)行域名的目錄指派。
變量方面,比如配置變量a=1:
set $a 1;
下面這個(gè)案例配合if判斷來(lái)做有更大的用處。
nginx里面支持一些簡(jiǎn)單的if判斷,但是沒(méi)有多重邏輯的語(yǔ)法,多個(gè)判斷條件用起來(lái)需要結合變量的方式來(lái)實(shí)現,比如允許ip地址為10.10.61段和和192.168.100段的用戶(hù)訪(fǎng)問(wèn),其余的拒絕,返回405狀態(tài)碼:
set $err 0;
if ( $remote_addr ~ 10.10.61.){
set $err 0;
}
if ( $remote_addr ~ 192.168.100.){
set $err 0;
}
if ( $err = 1){
return 405;
}
這樣通過(guò)一個(gè)err變量比較巧妙實(shí)現了需求。
有用到后端proxy的地方需要加上這句話(huà)才可以傳到狀態(tài)碼到nginx:
fastcgi_intercept_errors on;
具體配置一般是配置到具體的錯誤URL頁(yè)面,比如:
#返回具體狀態(tài)碼
error_page 404 403 /4xx.html
#返回200狀態(tài)碼
error_page 404 403 =200 /error.html
或者采用callback的方式統一做處理:
error_page 404 403 = @fallback;
location @fallback {
proxy_pass http://backend;
access_log /data/logs/404_error.log access;
}
這樣在重定向時(shí)不會(huì )改變URL,然后把404頁(yè)面直接返回。
rewrite做一些301、302之類(lèi)的跳轉,同時(shí)也可以在CDN前端做“去問(wèn)號”緩存的效果。
location /db.txt {
rewrite (.*) $1? break;
include proxy.conf;
}
另外最常見(jiàn)的跳轉寫(xiě)法:
rewrite ^/game/(.*) /$1;
把/game/test跳轉為/test的效果,注意這樣是沒(méi)有狀態(tài)碼的,如果訪(fǎng)問(wèn)正常就直接返回200狀態(tài)碼。
可以在后面加個(gè)permanent參數,就變?yōu)榱?01 Moved Permanently,或者添加redirect改為302跳轉。
同理,還可以進(jìn)行多個(gè)正則匹配進(jìn)行URL重組,比如:
rewrite ^/download/(.*)/lastest/(.*)$ /file/$1?ver=$2 break;
想針對每個(gè)連接進(jìn)行日志留檔,可以在nginx日志那里配置好字段,比如記錄cookie之類(lèi)的數據。
在log_format字段里面加入$http_cookie變量即可。
另外post的數據可以永久保留在文件里面,比如用來(lái)做http的日志備份,包括get和post的原始數據,把這個(gè)值開(kāi)啟即可:
client_body_in_file_only on;
然后post的數據就會(huì )保存在nginx/client_body_temp文件夾里面。
這個(gè)關(guān)鍵詞很少見(jiàn),但有時(shí)候是很有用的,比如在有很多規則時(shí)候,突然需要針對某個(gè)目錄轉為nginx內部處理。
location ^~ /upload/down/ {
alias /data/web/dts/dtsfile/down/;
internal;
}
字面意思是嘗試,后面可以接多個(gè)目錄或者文件,比如kohana框架:
try_files $uri /index.php?$query_string;
先看是否有URL這個(gè)文件,沒(méi)有的話(huà)再調用index.php來(lái)處理,或者支持狀態(tài)碼處理:
try_files /foo /bar/ =404;
沒(méi)有這兩個(gè)文件的話(huà)返回404狀態(tài)。
可以做簡(jiǎn)單的用戶(hù)登錄認證方式,其中的passwd_file得通過(guò)apache的htpasswd命令來(lái)生成。
auth_basic "Restricted";
auth_basic_user_file passwd_file;
認證通過(guò)之后每次訪(fǎng)問(wèn)會(huì )在頭部添加Authorization字段包含用戶(hù)名密碼的base64加密密文給服務(wù)端。
普通的線(xiàn)上web站點(diǎn)gzip壓縮是必須要開(kāi)的,壓縮一些文本類(lèi)型的文件再返回給用戶(hù)。
注意必須手動(dòng)指定全需要壓縮的類(lèi)型,比如css、js之類(lèi)的,線(xiàn)上配置如下:
gzip on;
gzip_min_length 2048;
gzip_buffers 4 16k;
gzip_vary on;
gzip_http_version 1.1;
gzip_types text/plain text/css text/xml application/xml application/javascript application/x-javascript ;
很久以前基本是忽略這個(gè)配置,但手游流行之后就發(fā)現異常了,需要讓手機瀏覽器知道返回的apk后綴是什么類(lèi)型,否則類(lèi)似IE瀏覽器會(huì )以zip后綴返回,需要加上:
application/vnd.android.package-archive apk;
application/iphone pxl ipa;
限速包括限制請求的并發(fā)數和請求的下載速度。
簡(jiǎn)單的限制某個(gè)線(xiàn)程的下載速度就直接加上一句話(huà)就可以了:
limit_rate 1024k;
要限制某個(gè)IP的并發(fā)數之類(lèi)的就需要用ngx_http_limit_req_module和ngx_http_limit_conn_module模塊了,不過(guò)是默認就編譯好的。
比如使用一個(gè) 10M 大小的狀態(tài)緩存區,針對每個(gè)IP每秒只接受20次的請求:
limit_req_zone $binary_remote_addr zone=NAME:10m rate=20r/s;
location匹配有多種方式,常見(jiàn)的比如
location = /
location /
location ^~ /test{
是有優(yōu)先級的,直接 ”=” 的優(yōu)先級是最高的,一般就用”~”這個(gè)符號來(lái)匹配php就好了,不過(guò)是區分了大小寫(xiě)的:
location ~ .*.php$
返回給用戶(hù)的文件一般都配置了過(guò)期時(shí)間,讓瀏覽器緩存起來(lái)。
比如緩存14天:
expires 14d;
針對某些特殊的文件就需要location匹配之后進(jìn)行禁止緩存配置:
add_header Cache-Control no-cache;
add_header Cache-Control no-store;
expires off;
nginx可以作為ATS這樣的緩存服務(wù)器來(lái)緩存文件,配置也比較簡(jiǎn)單,不過(guò)我們很少用,除非一些特殊的場(chǎng)合,參考配置:
#先在全局下面定義好緩存存放的目錄
proxy_cache_path /data/cache/ levels=1:2 keys_zone=cache_one:10m inactive=7d max_size=10g;
proxy_temp_path /data/cache/proxy_temp_path;
proxy_cache_key $host$uri$is_args$args;
#然后在server里面的location匹配好目的文件,加入下一段即可
proxy_cache cache_one;
proxy_cache_valid 200 304 24h;
proxy_cache_valid any 10m;
proxy_pass https://$host;
proxy_cache_key $host$uri$is_args$args;
add_header Nginx-Cache "$upstream_cache_status"; 3. 內置模塊
nginx含有大量的模塊可以支持多種復雜的需求,比如源碼目錄src/http/modules里面就有很多c模塊的代碼,或者直接通過(guò)./configure –help|grep module來(lái)查看有哪些內置模塊,編譯時(shí)候直接加上就可以了。
除了nginx內置的模塊,網(wǎng)絡(luò )上還有很多第三方的模塊,可以通過(guò)編譯時(shí)候加參數–add-module=PATH指定模塊源碼來(lái)編譯。
下面介紹一些我們線(xiàn)上用過(guò)而且比較贊的內置模塊。
端口轉發(fā)的模塊,從nginx1.9版本才開(kāi)始支持,包含tcp和udp的支持,和IPTABLES相比這個(gè)雖然是應用層,會(huì )監聽(tīng)端口,但是配置起來(lái)很方便,比IPTABLES靈活,在tcp模塊下面添加類(lèi)似vhost的server就可以了,方便自動(dòng)化管理,參考配置:
server {
listen PORT;
proxy_pass IP:PORT;
access_log /data/logs/tcp/PORT.log;
}
nginx反向代理之后,如何讓后端web直接獲取到的IP不是反向代理的iP,而是直接獲取到用戶(hù)的真實(shí)IP呢,就需要這個(gè)模塊了,不需要代碼那里再做類(lèi)似X-Real-IP的變量特殊判斷。
在做CDN時(shí)候可以用到,讓一個(gè)大文件分片,分成多個(gè)小文件通過(guò)206斷點(diǎn)續傳到后端,然后再組合起來(lái),避免大文件直接回源導致多副本和多次回源的問(wèn)題。
前面說(shuō)到的防盜鏈可以用這個(gè)來(lái)做,但是這個(gè)一般是針對那種文件下載時(shí)候用到的,比如從網(wǎng)頁(yè)下載時(shí)候,服務(wù)端生成一個(gè)加密URL給用戶(hù),然后這個(gè)URL有過(guò)期時(shí)間之類(lèi)的,避免此URL被多次分享出去,不過(guò)普通的素材加載還是用普通的防盜鏈即可。
替換響應給用戶(hù)的內容,相對于sed之后再返回,比如可以在需要臨時(shí)全局修改網(wǎng)站背景或者title時(shí)候可以一次性處理好。
簡(jiǎn)單介紹下大名鼎鼎的兩個(gè)基于nginx的擴展項目,也是我們線(xiàn)上有很多地方用到的。
集成lua腳本,幾乎可以完成任何普通web相關(guān)的需求。
比如URL加密進(jìn)行防劫持和防盜鏈,服務(wù)端動(dòng)態(tài)生成一串a(chǎn)es加密的URL給CDN,CDN的openresty解密之后用普通的URL轉發(fā)到后端,然后再返回給用戶(hù)正確的內容。
淘寶的nginx修改版,實(shí)現了很多nginx的收費功能或者是特殊功能,比如動(dòng)態(tài)加載、concat合并請求,動(dòng)態(tài)解析等。
我們python開(kāi)發(fā)的后臺基本都是用的這個(gè)版本,主要是利用了concat的合并素材的功能。
Nginx是個(gè)非常實(shí)用軟件,部分功能已經(jīng)超越了普通的web服務(wù)定位,同時(shí)它具備開(kāi)源、輕量、自動(dòng)化等特性,能有效解決實(shí)際工作中很多特殊場(chǎng)景的需求。
(原文來(lái)自微信公眾號:運維軍團)
- 1簡(jiǎn)約至美!新鴻儒傾力打造《銳馳官網(wǎng)》??榮獲2018IAI設計優(yōu)勝獎
- 2中紀委監察部官網(wǎng)2018新版上線(xiàn)??新鴻儒設計增色彩
- 3新鴻儒?新春大拜年
- 4關(guān)于新麒麟抄襲新鴻儒官網(wǎng)的聲明
- 5不忘初心,感恩前行?新鴻儒新年遷新居
- 6華星鋼構攜手新鴻儒??高端網(wǎng)站隆重亮相
- 7中儲糧簽約新鴻儒?糧食巨頭擁抱互聯(lián)網(wǎng)
- 8新鴻儒簽約方正??塑造集團互聯(lián)網(wǎng)品牌形象
- 9國美再次攜手新鴻儒?創(chuàng )新升級品牌官網(wǎng)
- 10新鴻儒協(xié)辦第二屆互聯(lián)網(wǎng)大會(huì )??助力工程建設行業(yè)互聯(lián)網(wǎng)+


