一、Nginx Proxy代理
1、代理原理
(1)反向代理:需要有一個負(fù)載均衡設(shè)備(即反向代理服務(wù)器)來分發(fā)用戶請求,將用戶請求分發(fā)到后端正真提供服務(wù)的服務(wù)器上。服務(wù)器返回自己的服務(wù)到負(fù)載均衡設(shè)備,負(fù)載均衡設(shè)備將服務(wù)器的服務(wù)返回用戶。
(2)正向代理:正向代理的過程隱藏了真實的請求客戶端,服務(wù)器不知道真實的客戶端是誰,客戶端請求的服務(wù)都被代理服務(wù)器代替請求。我們常說的代理也就是正向代理,正向代理代理的是請求方,也就是客戶端。
2、正向和反代的區(qū)別?
正向代理中代理的對象是客戶端。
反向代理中代理的對象是服務(wù)端。
3、nginx Proxy 配置
代理模塊:ngx_http_proxy_module
模擬:兩臺Nginx真實服務(wù)器
a、Nginx-1 啟動網(wǎng)站(內(nèi)容)
IP:192.168.124.19 已編譯安裝好,檢查Nginx是否啟動,是否可以訪問。
b、Nginx-2啟動代理程序
IP:192.168.124.20
yum直接安裝,啟動
編輯nginx的配置文件
[root@nginx-server ~]# vim /etc/nginx/conf.d/default.conf
server {
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://192.168.124.19:80;
proxy_redirect default;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 30;
proxy_send_timeout 60;
proxy_read_timeout 60;
}
}
重新加載nginx配置文件
[root@nginx-server ~]# nginx -s reload
c、使用pc客戶端訪問Nginx-2服務(wù)器地址或域名,也就是http://192.168.124.20,成功訪問Nginx-1服務(wù)器頁面
d、觀察Nginx-1服務(wù)器的日志
訪問成功,記錄了客戶端的IP和代理服務(wù)器的IP。
二、Nginx負(fù)載均衡
1、upstream配置
這個配置是寫一組被代理的服務(wù)器地址,然后配置負(fù)載均衡的算法。
upstream testapp {
server 10.0.105.199:8081;
server 10.0.105.202:8081;
}
server {
....
location / {
proxy_pass http://testapp; #請求轉(zhuǎn)向 testapp 定義的服務(wù)器列表
}
2、負(fù)載均衡算法
1、輪詢(默認(rèn)):每個請求按時間順序逐一分配到不同的后端服務(wù)器;
2、ip_hash:每個請求按訪問IP的hash結(jié)果分配,同一個IP客戶端固定訪問一個后端服務(wù)器??梢员WC來自同一ip的請求被打到固定的機(jī)器上,可以解決session問題。
3、url_hash:按訪問url的hash結(jié)果來分配請求,使每個url定向到同一個后端服務(wù)器。
4、fair:此種算法可以依據(jù)頁面大小和加載時間長短智能地進(jìn)行負(fù)載均衡,也就是根據(jù)后端服務(wù)器的響應(yīng)時間來分配請求,響應(yīng)時間短的優(yōu)先分配。Nginx本身是不支持 fair的,如果需要使用這種調(diào)度算法,必須下載Nginx的 upstream_fair模塊。
配置實例
1、熱備:如果有兩臺服務(wù)器,當(dāng)一個服務(wù)器發(fā)生事故的時候,才啟動第二臺服務(wù)器給提供服務(wù)。
upstream myweb {
server 172.17.14.2:8080;
server 172.17.14.3:8080 backup; #熱備
}
2、輪詢:nginx默認(rèn)就是輪詢其權(quán)重都默認(rèn)1
upstream myweb {
server 172.17.14.2:8080;
server 172.17.14.3:8080;
}
3、加權(quán)輪詢:根據(jù)配置的權(quán)重大小二分發(fā)給不用服務(wù)器數(shù)量的請求。
upstream myweb {
server 172.17.14.2:8080 weight=1;
server 172.17.14.3:8080 weight=2;
}
4、ip_hash:nginx會讓相同的客戶端IP請求相同的服務(wù)器。
upstream myweb {
server 172.17.14.2:8080;
server 172.17.14.3:8080;
ip_hash;
}
5、Nginx負(fù)載均衡配置狀參數(shù)
upstream myweb {
server 172.17.14.2:8080 weight=2 max_fails=2 fail_timeout=2;
server 172.17.14.3:8080 weight=1 max_fails=2 fail_timeout=1;
}
down:表示當(dāng)前的server暫時不參與負(fù)載均衡
backup:預(yù)留的備份機(jī)器
max_fails:允許請求失敗的次數(shù),默認(rèn)為1。當(dāng)超過最大次數(shù)時,返回proxy_next_upstream 模塊定義的錯誤。
fail_timeout:經(jīng)歷了max_fails失敗后。暫停服務(wù)的時間單位秒。max_fails可以和fail_timeout一起使用。
3、Nginx會話保持
有以下幾種實現(xiàn)方式:
1、ip_hash
使用源地址哈希算法,將同一客戶端的請求總是發(fā)送同一個后端服務(wù)器。
upstream backend {
ip_hash;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com down;
}
ip_hash簡單易用,但有如下的問題:
當(dāng)后端服務(wù)器宕機(jī)后,session會丟失;
來自同一個局域網(wǎng)的客戶端會被轉(zhuǎn)發(fā)到同一個后端服務(wù)器,可能會導(dǎo)致負(fù)載失衡;
2、sticky_cookie_insert
使用這個模塊會讓來自同一個客戶端的請求被傳遞到一組服務(wù)器的同一臺服務(wù)器,與ip_hash不同之處是,它不是基于IP來判斷客戶端的,而是基于cookie來判斷(需要引用第三方模塊才能實現(xiàn))
sticky模塊語法:
upstream backend {
server backend1.example.com;
server backend2.example.com;
sticky_cookie_insert srv_id expires=1h domain=3evip.cn path=/;
}
expires:設(shè)置瀏覽器中保持cookie的時間
domain:定義cookie的域
path:為cookie定義路徑
3、jvm_route方式
通過session_cookie這種方式實現(xiàn)session粘性,將特定會話附屬到特定的tomcat上,從而解決session不同步問題,但是無法解決宕機(jī)后會話轉(zhuǎn)移問題。如果cookie和url中并沒有session,則這只是個簡單的round-robin負(fù)載均衡。
jvm_route原理:
1.一開始請求過來,沒有帶session信息,jvm_round就會根據(jù)round robin的方法,發(fā)到一臺Tomcat上面。
2.Tomcat添加上session信息,并返回給客戶。
3.用戶再次請求,jvm_route看到session中有后端服務(wù)器的名稱,它就會把請求轉(zhuǎn)發(fā)到對應(yīng)的服務(wù)器上。
三、Nginx實現(xiàn)動靜分離
為了加快網(wǎng)站的解析速度,可以把動態(tài)頁面和靜態(tài)頁面由不同的服務(wù)器來解析,加快解析速度。降低原來單個服務(wù)器的壓力。
準(zhǔn)備環(huán)境
3臺機(jī)器,一個做Nginx代理,一個http處理動態(tài),一個http處理靜態(tài),三臺機(jī)器都裝Nginx。
代理:192.168.124.10
http:192.168.124.11(動態(tài))192.168.124.12(靜態(tài))
1、配置nginx反向代理upstream(192.168.124.10)
upstream static {
server 192.168.124.11:80 weight=1 max_fails=1 fail_timeout=60s;
}
upstream php {
server 192.168.124.12:80 weight=1 max_fails=1 fail_timeout=60s;
}
server {
listen 80;
server_name localhost
#動態(tài)資源加載
location ~ \.(php|jsp)$ {
proxy_pass http://phpserver;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
#靜態(tài)資源加載
location ~ .*\.(html|gif|jpg|png|bmp|swf|css|js)$ {
proxy_pass http://static;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
2、配置靜態(tài)資源(192.168.124.11)
# #vim /etc/nginx/nginx.conf
server {
listen 80;
server_name localhost;
location ~ \.(html|jpg|png|js|css|gif|bmp|jpeg) {
root /home/www/nginx;
}
}
# mkdir -p /home/www/nginx
# chmod 777 /home/www/
# vim /home/www/nginx/index.html 添加內(nèi)容
3、動態(tài)資源配置(192.168.124.12)
1、yum安裝php7.1
# rpm -Uvh https://mirror.webtatic.com/yum/el7/epel-release.rpm
# rpm -Uvh https://mirror.webtatic.com/yum/el7/webtatic-release.rpm
安裝依賴
# yum install php71w-xsl php71w php71w-ldap php71w-cli php71w-common php71w-devel php71w-gd php71w-pdo php71w-mysql php71w-mbstring php71w-bcmath php71w-mcrypt -y
# yum install -y php71w-fpm
啟動
# systemctl start php-fpm && systemctl enable php-fpm
2、編輯nginx配置文件
# vim /etc/nginx/nginx.conf
server {
listen 80;
server_name localhost;
location ~ \.php$ {
root /home/nginx/html; #指定網(wǎng)站目錄
fastcgi_pass 127.0.0.1:9000; #指定訪問地址
fastcgi_index index.php; #指定默認(rèn)文件
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; #站點根目錄,取決于root配置項
include fastcgi_params; #包含nginx常量定義
}
}
3、創(chuàng)建目錄
# mkdir -p /home/nginx/html
# chmod 777 /home/nginx/
# cat /home/nginx/html/index.php
<? Hello Warld!
?>
4、測試
1、訪問http://192.168.124.10/index.html會轉(zhuǎn)發(fā)到靜態(tài)服務(wù)器,通過location正則匹配來處理請求。
2、訪問http://192.168.124.10/index.php動態(tài)頁面時location匹配到./php結(jié)尾的文件會轉(zhuǎn)發(fā)到php服務(wù)器處理請求。
四、Nginx防盜鏈
兩個網(wǎng)站 A 和 B, A網(wǎng)站引用了B網(wǎng)站上的圖片,這種行為就叫做盜鏈。 防盜鏈,就是要防止A引用B的圖片。
1、Nginx防止網(wǎng)站資源被盜用模板
ngx_http_referer_module
2、防盜鏈配置
[root@nginx-server ~]# vim /etc/nginx/nginx.conf
# 日志格式添加"$http_referer"
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
# valid_referers 使用方式
Syntax: valid_referers none | blocked | server_names | string ...;
Default: —
Context: server, location
解釋:
none : 允許沒有http_referer的請求訪問資源
blocked : 允許不是http://開頭的,不帶協(xié)議的請求訪問資源
server_names : 只允許指定ip/域名來的請求訪問資源(白名單
2、配置實例
準(zhǔn)備兩臺機(jī)器,兩張圖片
第一臺,配置nginx配置文件,并上傳圖片
[root@nginx-server html]# vim /etc/nginx/conf.d/nginx.conf
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
valid_referers none blocked *.baby.com 10.0.105.202;
if ($invalid_referer) {
return 403;
}
}
location ~ .*\.(gif|jpg|png|jpeg)$ {
root /usr/share/nginx/html;
valid_referers baby.com 10.0.105.202;
if ($invalid_referer) {
return 403;
}
}
}
重新加載nginx服務(wù)
[root@nginx-server ~]# nginx -s reload -c /etc/nginx/nginx.conf
第二臺機(jī)器客戶端
1、配置nginx訪問頁面
[root@nginx-server ~]# vim /home/www/nginx/index.html
<html>
<head>
<meta charset="utf-8">
<title>qf.com</title>
</head>
<body style="background-color:red;">
<img src="http://10.0.105.202/test.jpg"/>
</body>
</html>
2、測試不帶http_refer:
[root@nginx-server ~]# curl -I "http://10.0.105.202/test1.png"
HTTP/1.1 200 OK
Server: nginx/1.16.0
...
Connection: keep-alive
ETag: "5d14a80f-39713"
Accept-Ranges: bytes
3、測試帶非法http_refer
[root@nginx-server ~]# curl -e http://www.baidu.com -I "http:/10.0.105.202/test.jpg"
HTTP/1.1 403 Forbidden
Server: nginx/1.16.0
...
Connection: keep-alive
4、測試帶合法的http_refer
[root@nginx-server nginx]# curl -e http://10.0.105.202 -I "http://10.0.105.202/test.jpg"
HTTP/1.1 200 OK
Server: nginx/1.16.0
...
Connection: keep-alive
ETag: "5d14b683-6d39"
Accept-Ranges: bytes
五、Nginx地址重寫rewrite
1、什么是Rewrite?
Rewrite對稱URL Rewrite,即URL重寫。就是把傳入Web的請求重定向到其他URL的過程。
2、Rewrite相關(guān)指令
Nginx Rewrite相關(guān)指令有if、rewrite、set、return
應(yīng)用環(huán)境:server、location
2.1 If 指令
支持如下條件判斷匹配符號:
~ 正則匹配(區(qū)分大小寫)
~* 正則匹配(不區(qū)分大小寫)
!~ 正則不匹配(區(qū)分大小寫)
!~* 正則不匹配(不區(qū)分大小寫)
-f 和 !-f 用來判斷是否存在文件
-d 和 !-d 用來判斷是否存在目錄
-e 和 !-e 用來判斷是否存在文件或目錄
-x 和 !-x 用來判斷文件是否可執(zhí)行
2.2 Rewrite flag
rewrite指令根據(jù)表達(dá)式來重定向URL,或者修改字符串??梢詰?yīng)用于server,location,if環(huán)境下每行rewrite指令最后跟一個flag標(biāo)記,支持的flag標(biāo)記有:
last 表示本條規(guī)則匹配后會重新發(fā)送請求
break 本條規(guī)則匹配完成后,終止匹配,不再匹配 后面的規(guī)則
redirect 返回302臨時重定向,瀏覽器地址會顯示跳轉(zhuǎn)后的URL地址
permanent 返回301永久重定向,瀏覽器地址會顯示跳轉(zhuǎn)后URL地址
2.3 Rewrite匹配參考實例
本地解析host文件
1、# http://www.test.com/a/hhh.html ==> http://www.test.com/b/ggg.html
location /a {
root /html;
index hhh.html index.html;
rewrite .* /b/gggg.html permanent;
}
location /b {
root /html;
index ggg.html index.htm;
}
2、# http://www.test.com/2020/a/1.html ==> http://www.tset.com/2019/a/1,html
location /2020/a {
root /var/www/html;
index 1.html index.hml;
rewrite ^/2020/(.*)$ /2019/$1 permanent;
}
location /2019/a {
root /var/www/html;
index 1.html index.htl;
}
3、# http://www.llf.com/a/1.html ==> http://jd.com
location /a {
root /html;
if ($host ~* test.com ) {
rewrite .* http://jd.com permanent;
}
}
2.4 set指令
set指令用于定義一個變量,并且賦值
應(yīng)用環(huán)境:server、location、if
應(yīng)用實例:
# http://alice.testpm.com ==> http://www.testpm.com/alice
# http://jack.testpm.com ==> http://www.testpm.com/jack
首先做本地解析域名host文件,編輯配置文件:
# vim /etc/nginx/nginx.conf
server {
listen 80;
server_name www.test.com;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
if ( $host ~* ^www.test.com$) {
break;
}
if ( $host ~* "^(.*)\.test\.com$" ) {
set $user $1;
rewrite .* http://www.test.com/$user permanent;
}
}
location /jack {
root /usr/share/nginx/html;
index index.html index.hml;
}
location /alice {
root /usr/share/nginx/html;
index index.html index.hml;
}
}
2.5 return指令
return指令用于返回狀態(tài)碼給客戶端。可以應(yīng)用于server、location、If環(huán)境下。
應(yīng)用實例:
1、如果要訪問.sh結(jié)尾的文件則返回403操作拒絕錯誤
server {
listen 80;
server_name www.test.cn;
#access_log /var/log/nginx/http_access.log main;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
location ~* \.sh$ {
return 403;
}
}
2、80端口轉(zhuǎn)443端口
server {
listen 80;
server_name www.test.cn;
access_log /var/log/nginx/http_access.log main;
return 301 https://www.test.cn$request_uri;
}
server {
listen 443 ssl;
server_name www.test.cn;
access_log /var/log/nginx/https_access.log main;
#ssl on;
ssl_certificate /etc/nginx/cert/2447549_www.test.cn.pem;
ssl_certificate_key /etc/nginx/cert/2447549_www.test.cn.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
ssl_prefer_server_ciphers on;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
}
[root@nginx-server ~]# curl -I http://www.testpm.cn
HTTP/1.1 301 Moved Permanently
Server: nginx/1.16.0
...
Connection: keep-alive
Location: https://www.test.cn/
3、查找順序和優(yōu)先級
1、帶有"="的精確匹配優(yōu)先 (完全匹配)
2、沒有修飾符的精確匹配
3、正則表達(dá)式按照他們在配置文件中定義的順序
4、帶有"^~"修飾符的,開頭匹配
5、帶有"~"或"~*"修飾符的,如果正則表達(dá)式與URL匹配
6、沒有修飾符的,如果指定字符串與URL開頭匹配
= 大于 ^~ 大于 ~|~*|!~|!~* 大于 /
六、Nginx平滑升級
1、為什么要對Nginx進(jìn)行平滑升級
- 在不停掉老進(jìn)程的情況下,啟動新進(jìn)程
- 老進(jìn)程負(fù)責(zé)處理任然沒有處理完的請求,但不再接受處理請求
- 新進(jìn)程接受新請求
- 老進(jìn)程處理完所有請求,關(guān)閉所有連接,停止
用這種方式方便了所有的請求,一般有兩種情況下需要升級nginx。一種是確實要升級nginx的版本,另一種是要為nginx添加新的模板。
2、nginx平滑升級原理
多模式下的請求分配方式
nginx默認(rèn)工作是在多進(jìn)程模式下,即主進(jìn)程啟動后完成配置加載和端口綁定等動作。fock指定數(shù)量的工作進(jìn)程,這些進(jìn)程會持有監(jiān)聽端口的文件描述符(fd),并通過該描述符上添加監(jiān)聽事件來接受連接(accept)。
信號的接收和處理
Nginx主進(jìn)程在啟動完成后會進(jìn)入等待狀態(tài),負(fù)責(zé)響應(yīng)各類系統(tǒng)消耗,如sigchld、sighup、sigusr2等。
Nginx信號簡介
1、主進(jìn)程支持的信號
term,ini:立刻退出
quit:等待工作進(jìn)程結(jié)束后再退出
kill:強(qiáng)制終止進(jìn)程
hup:重新加載配置文件,使用新的配置啟動工作進(jìn)程并逐步關(guān)掉舊進(jìn)程。
usr1:重新打開日志文件
usr2:啟動新的主進(jìn)程,實現(xiàn)熱升級
winch:逐步關(guān)閉工作進(jìn)程
2、工作進(jìn)程支持的信號
term,ini:立刻退出
quit:等待工作進(jìn)程結(jié)束后再退出
usr1:重新打開日志文件
3、nginx平滑升級實戰(zhàn)
按照原來的編譯安裝nginx的方法進(jìn)行安裝,只需要到make,千萬不要make install,否則會覆蓋。
1、編譯安裝
[root@nginx-server ~]# yum install -y gcc gcc-c++ pcre-devel openssl-devel zlib-devel
[root@nginx-server ~]# tar xzf nginx-1.16.0.tar.gz -C /usr/local
[root@nginx-server ~]# cd /usr/local/nginx-1.16.0/
[root@nginx-server nginx-1.16.0]# ./configure --prefix=/usr/local/nginx --group=nginx --user=nginx --sbin-path=/usr/local/nginx/sbin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --http-client-body-temp-path=/tmp/nginx/client_body --http-proxy-temp-path=/tmp/nginx/proxy --http-fastcgi-temp-path=/tmp/nginx/fastcgi --pid-path=/var/run/nginx.pid --lock-path=/var/lock/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_gzip_static_module --with-pcre --with-http_realip_module --with-stream --with-http_image_filter_module
[root@nginx-server nginx-1.16.0]# make
2、備份原nginx二進(jìn)制文件和nginx配置文件
[root@nginx-server nginx-1.16.0]# mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx_$(date +%F)
3、復(fù)制新的nginx二進(jìn)制文件,進(jìn)入新的nginx源碼包
[root@nginx-server nginx-1.16.0]# cp /usr/local/nginx-1.16.0/objs/nginx /usr/local/nginx/sbin/
4、測試新版本的nginx是否正常
[root@nginx-server nginx-1.16.0]# /usr/local/nginx/sbin/nginx -t
5、給nginx發(fā)送平滑遷移信號
[root@nginx-server ~]# kill -USR2 `cat /var/run/nginx.pid`
6、查看nginx.pid,會出現(xiàn)一個nginx.pid.oldbin
[root@nginx-server ~]# ll /var/run/nginx.pid*
-rw-r--r-- 1 root root 5 Jul 1 11:29 /var/run/nginx.pid
-rw-r--r-- 1 root root 5 Jul 1 09:54 /var/run/nginx.pid.oldbin
7、從容關(guān)閉舊的Nginx進(jìn)程
[root@nginx-server ~]# kill -WINCH `cat /var/run/nginx.pid.oldbin`
8、此時不重載配置啟動舊的工作進(jìn)程
root@nginx-server ~]# kill -HUP `cat /var/run/nginx.pid.oldbin`
9、結(jié)束工作進(jìn)程,完成此次升級
[root@nginx-server ~]# kill -QUIT `cat /var/run/nginx.pid.oldbin`
10、驗證Nginx是否升級成功
[root@nginx-server ~]# /usr/local/nginx/sbin/nginx -V
七、Nginx流量控制
1、流量限制
可以用來限制用戶在給定時間內(nèi)HTTP請求的數(shù)量??梢杂米靼踩康模?/p>
- 減慢暴力破解的速率
- 將傳入請求的速率限制為真實用戶的典型值,并標(biāo)識目標(biāo)URL地址
- 抵御DDOS攻擊
- 保護(hù)上游應(yīng)用服務(wù)器不被同時太多用戶請求所擊垮
Nginx如何限流
使用漏桶算法,處理帶寬有限時的突發(fā)情況。
配置基本的限流
"流量限制"配置兩個主要的指令,limit_req_zone和limit_req.
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s; //每個IP地址被限制為每秒只能請求10次
upstream myweb {
server 10.0.124.196:80 weight=1 max_fails=1 fail_timeout=1;
}
server {
listen 80;
server_name localhost;
location /login {
limit_req_zone=mylimit;
proxy_pass http://myweb;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
10.0.124.196配置:
server {
listen 80;
server_name localhost;
location /login {
root /usr/share/nginx/html;
index index.html index.html;
}
}
limit_req_zone指令定義了流量限制相關(guān)的參數(shù),通常在HTTP塊中定義,使其可以在多個上下文使用。
limit_req指令將流量限制應(yīng)用在特定的location或者server塊。
2、處理突發(fā)
如果我們在100毫秒內(nèi)接收到2個請求,怎么辦?對于第二個請求,Nginx將給客戶端返回狀態(tài)碼503。我們希望緩沖任何超額的請求,然后及時地處理它們。我們更新下配置,在limit_req中使用burst參數(shù):
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
upstream myweb {
server 10.0.105.196:80 weight=1 max_fails=1 fail_timeout=1;
}
server {
listen 80;
server_name localhost;
location /login {
limit_req zone=mylimit burst=20;
proxy_pass http://myweb;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
burst參數(shù)定義了超出了zone指定速率的情況下,客戶端還能發(fā)起多少請求。上一個請求100毫秒內(nèi)到達(dá)的請求將會被放入隊列,我們將隊列大小設(shè)置為20。
這意味著,如果從一個給定IP地址發(fā)送21個請求,Nginx會立即將第一個請求發(fā)送到上游服務(wù)器群,然后將余下20個請求放在隊列中。然后每100毫秒轉(zhuǎn)發(fā)一個排隊的請求,只有當(dāng)傳入請求使隊列中排隊的請求數(shù)超過20時,Nginx才會向客戶端返回503。
3、無延遲的排隊
配置burst參數(shù)將會使通訊更流暢,但是可能會不太實用,因為該配置會使站點看起來很慢。在上面的示例中,隊列中的第20個包需要等待2秒才能被轉(zhuǎn)發(fā),此時返回給客戶端的響應(yīng)可能不再有用。要解決這個情況,可以在burst參數(shù)后添加nodelay參數(shù):
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
upstream myweb {
server 10.0.105.196:80 weight=1 max_fails=1 fail_timeout=1;
}
server {
listen 80;
server_name localhost;
location /login {
limit_req zone=mylimit burst=20 nodelay;
proxy_pass http://myweb;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
使用nodelay參數(shù),Nginx仍將根據(jù)burst參數(shù)分配隊列中的位置,并應(yīng)用已配置的速率限制,而不是清理隊列中等待轉(zhuǎn)發(fā)的請求。
例如:
隊列中有20個空位,從給定的IP地址發(fā)出的21個請求同時到達(dá)。Nginx會立即轉(zhuǎn)發(fā)這個21個請求,并且標(biāo)記隊列中占據(jù)的20個位置,然后每100毫秒釋放一個位置。如果是25個請求同時到達(dá),Nginx將會立即轉(zhuǎn)發(fā)其中的21個請求,標(biāo)記隊列中占據(jù)的20個位置,并且返回503狀態(tài)碼來拒絕剩下的4個請求。
注意:對于大部分部署,我們建議使用burst和nodelay參數(shù)來配置limit_req指令。
4、Nginx流量控制總結(jié)
以上已經(jīng)涵蓋了Nginx和Nginx Plus提供的“流量限制”的很多功能,包括為HTTP請求的不同loation設(shè)置請求速率,給“流量限制”配置burst和nodelay參數(shù)。還涵蓋了針對客戶端IP地址的白名單和黑名單應(yīng)用不同“流量限制”的高級配置,闡述了如何去日志記錄被拒絕和延時的請求。
八、Nginx訪問控制
1、nginx訪問控制模塊
- 基于IP的訪問控制:http_access_module
- 基于用戶的信任登錄:http_auth_basic_module
2、基于IP的訪問控制
# vim /etc/nginx/conf.d/access_mod.conf
server {
listen 80;
server_name localhost;
location ~ ^/admin {
root /home/www/html;
index index.html index.hml;
deny 192.168.1.8;
allow all;
#deny 192.168.1.8;
}
}
需要注意: 如果先允許訪問,在定義拒絕訪問。那么拒絕訪問不生效。
指定location拒絕所有請求
如果你想拒絕某個指定URL地址的所有請求,而不是僅僅對其限速,只需要在location塊中配置deny all指令:
server {
listen 80;
server_name localhost;
location /foo.html {
root /home/www/html;
deny all;
}
}
3、基于用戶的信任登錄
將access_mod.conf為auth_mod.conf,內(nèi)容如下:
server {
listen 80;
server_name localhost;
location ~ ^/admin {
root /home/www/html;
index index.html index.hml;
auth_basic "Auth access test!";
auth_basic_user_file /etc/nginx/auth.conf;
}
}
auth_basic 不為off,開啟登錄驗證功能
auth_basic_user_file加載賬號密碼文件
建立口令文件
[root@192 ~]# yum install -y httpd-tools
htpasswd 是開源 http 服務(wù)器 apache httpd 的一個命令工具,用于生成 http 基本認(rèn)證的密碼文件
[root@192 ~]# htpasswd -cm /etc/nginx/auth_conf user10
[root@192 ~]# htpasswd -m /etc/nginx/auth_conf user20
[root@192 ~]# cat /etc/nginx/auth_conf
user10:$apr1$MOa9UVqF$RlYRMk7eprViEpNtDV0n40
user20:$apr1$biHJhW03$xboNUJgHME6yDd17gkQNb0
局限性
- 用戶信息依賴文件方式
- 操作系統(tǒng)管理機(jī)械,效率低下
解決辦法
- Nginx結(jié)合LUA實現(xiàn)高效驗證
- Nginx和LDAP打通,利用nginx-auth-ldap模塊
- Nginx只做中間代理,具體認(rèn)證交給應(yīng)用
九、Nginx變量
1、變量簡介
- 所有的 Nginx變量在 Nginx 配置文件中引用時都須帶上 $ 前綴
- 在 Nginx 配置中,變量只能存放一種類型的值,有且也只存在一種類型,那就是字符串類型
- nginx可以使用變量簡化配置與提高配置的靈活性,所有的變量值都可以通過這種方式引用:$變量名
2、nginx變量的定義和使用
nginx變量分為兩種,自定義變量與內(nèi)置預(yù)定義變量。
2.1 自定義變量
可以在sever,http,location等標(biāo)簽中使用set命令(非唯一)聲明變量。
語法如下:set $變量名 變量值注意:
1.nginx 中的變量必須都以$開頭
2.nginx 的配置文件中所有使用的變量都必須是聲明過的,否則 nginx 會無法啟動并打印相關(guān)異常日志
變量的可見性
- nginx 變量的一個有趣的特性就是nginx中沒一個變量都是全局可見的,而他們又不是全局變量。
location a/ {
return 200 $a
}
location b/ {
set $a hello nginx
return 200 $a
}
# 配置$foo=hello
server {
listen 8080;
server_name localhost;
location /test {
set $foo hello;
echo "foo: $foo";
}
}
使用大括號插值
server {
...
location /test-brace {
set $first "hello ";
echo "${first}world";
}
}
輸出:
[root@localhost html]# nginx -s reload
[root@localhost html]# curl localhost/test-brace
hello world
3、變量作用域
set 指令(以及前面提到的 geo 指令)不僅有賦值的功能,它還有創(chuàng)建 Nginx 變量的副作用,即當(dāng)作為賦值對象的變量尚不存在時,它會自動創(chuàng)建該變量。
server {
listen 8080;
location /foo {
echo "foo = [$foo]";
}
location /bar {
set $foo 32;
echo "foo = [$foo]";
}
}
輸出:
[root@localhost html]# curl 'http://localhost/foo'
foo = []
[root@localhost html]# curl 'http://localhost/bar'
foo = [32]
內(nèi)部跳轉(zhuǎn)例子
server {
listen 8080;
location /foo {
set $a hello;
echo_exec /bar; // echo_exec起到內(nèi)部跳轉(zhuǎn)的作用
}
location /bar {
echo "a = [$a]";
}
}
輸出:
[root@localhost html]# curl localhost/foo
a = [hello]
2.2 內(nèi)置預(yù)定義變量
內(nèi)置預(yù)定義變量即無需聲明就可以使用的變量,通常包括一個http請求或響應(yīng)中一部分內(nèi)容的值。
Nginx內(nèi)建變量最常見的用途是獲取關(guān)于請求或響應(yīng)的各種信息。
十、Nginx監(jiān)控
1、基礎(chǔ)監(jiān)控
- 進(jìn)程監(jiān)控
- 端口監(jiān)控
注意:這兩個必須加在Zabbix監(jiān)控,加觸發(fā)器有問題及時告警。
- Nginx提供了ngx_http_stub_status_module、ngx_http_reqstat_module模塊,提供了基本的監(jiān)控功能
2、監(jiān)控的主要指標(biāo)
2.1 基本活躍指標(biāo)
Accepts(接受)、Handled(已處理)、Requests(請求數(shù))是一直在增加的計數(shù)器。Active(活躍)、Waiting(等待)、Reading(讀)、Writing(寫)隨著請求量而增減。
2.2 每秒請求數(shù) --QPS
1、按照固定時間間隔采樣請求數(shù)據(jù),計算出單位時間的請求量可以看到你的 web 服務(wù)器的請求情況。
2、通過持續(xù)的 QPS 監(jiān)控,可以立刻發(fā)現(xiàn)是否被惡意攻擊或?qū)Ψ?wù)的可用性進(jìn)行評估。
3、雖然當(dāng)問題發(fā)生時,通過 QPS 不能定位到確切問題的位置,但是他卻可以在第一時間提醒你環(huán)境可能出問題了。
2.3 服務(wù)器錯誤率
1、通過監(jiān)控固定時間間隔內(nèi)的錯誤代碼(4XX代碼表示客戶端錯誤,5XX代碼表示服務(wù)器端錯誤),可以了解到客戶端收到的結(jié)果是否是正確的錯誤率突然的飆升很可能是你的網(wǎng)站漏洞發(fā)出的信號.
2、如果你希望通過 access log 分析錯誤率,那么你需要配置 nginx 的日志模塊,讓 nginx 將響應(yīng)碼寫入訪問日志
2.4 請求處理時間
請求處理時間也可以被記錄在 access log 中,通過分析 access log,統(tǒng)計請求的平均響應(yīng)時間,通過持續(xù)觀察,可以發(fā)現(xiàn)上游服務(wù)器的問題。
3、指標(biāo)的收集
編譯時加入nginx的ngx_http_stub_status_module模塊可以實時監(jiān)控以下基本指標(biāo).
3.1 nginx stub status監(jiān)控模塊安裝
[root@localhost ~]# nginx -V //查看是否安裝了這個模塊
如果沒有這個模塊,需要重新安裝
[root@localhost nginx-1.6.0]# ./configure –with-http_stub_status_module
配置配置文件:
server {
listen 80;
server_name localhost;
location /nginx-status {
stub_status on;
access_log on;
allow 10.0.105.207; #允許本地電腦訪問
deny all;
}
}
3.2 nginx狀態(tài)查看
配置完成后在瀏覽器中輸入http://10.0.105.207/nginx-status 查看或者用 curl localhost/nginx_status
Active connections: 2
server accepts handled requests
26 26 48
Reading: 0 Writing: 1 Waiting: 1
3.3 Reqstat模塊監(jiān)控
- 這個模塊計算定義的變量,根據(jù)變量值分別統(tǒng)計 nginx 的運行狀況。
- 可以監(jiān)視的運行狀況有:連接數(shù)、請求數(shù)、各種響應(yīng)碼范圍的請求數(shù)、輸入輸出流量、rt、upstream訪問等。
- 可以指定獲取所有監(jiān)控結(jié)果或者一部分監(jiān)控結(jié)果。
- 利用變量添加自定義監(jiān)控狀態(tài)。總的監(jiān)控狀態(tài)最大個數(shù)為50個。
- 回收過期的監(jiān)控數(shù)據(jù)。
- 設(shè)置輸出格式
- 跟蹤請求,不受內(nèi)部跳轉(zhuǎn)的影響
- 不要使用與響應(yīng)相關(guān)的變量作為條件,比如"$status"