結合實踐、收集各種場景、常見問題,講解Nginx中最實用的Webserver場景,提供一套整體的搭建配置方式
Nginx中間件,不局限於業務邏輯,有效獨立於后台開發框架(不論后端是Java開發、PHP開發、或者其他語言框架)都能做到平台通用
不僅重實踐、也會結合原理(如:Http協議、操作系統),讓你理解背后的原理更有利於你解決實際問題(如:bug解決、二次開發等)
基礎篇
環境調試確認
yum -y install gcc gcc-c++ autoconf pcre pcre-devel make automake
yum -y install wget httpd-tools vim
cd /opt;mkdir app download logs work backup
關閉iptables
# 查看
iptables -L
# 關閉
iptables -F
# 查看
iptables -t nat -L
# 關閉
iptables -t nat -F
Nginx優勢
- 多路IO復用
- 使用Epoll模型
- 輕量級
- CPU親和
- sendfile
安裝
http://nginx.org/en/linux_packages.html#stable
vim /etc/yum.repos.d/nginx.repo
內容如下S
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/7/$basearch/
gpgcheck=0
enabled=1
yum install nginx
# 查看版本
nginx -v
# 查看安裝編譯參數
nginx -V
基本參數使用
安裝目錄
rpm -ql nginx
路徑 | 類型 | 作用 |
---|---|---|
/etc/logrotate.d/nginx | 配置文件 | nginx日志輪轉,用於logrotate服務的日志切割 |
/etc/nginx /etc/nginx/nginx.confd /etc/nginx/conf.d /etc/nginx/conf.d/default.conf |
目錄,配置文件 | nginx主配置文件 |
/etc/nginx/scgi_params /etc/nginx/uwsgi_params /etc/nginx/fastcgi_params |
配置文件 | cgi配置相關,fastcgi配置 |
/etc/nginx/koi-utf /etc/nginx/koi-win /etc/nginx/win-utf |
配置文件 | 編碼轉換映射轉化文件 |
/etc/nginx/mime.types | 配置文件 | 設置http協議的Content-Type與擴展名對應關系 |
/usr/lib/systemd/system/nginx-debug.service /usr/lib/systemd/system/nginx.service /etc/sysconfig/nginx /etc/sysconfig/nginx-debug |
配置文件 | 用於配置出系統守護進程管理器管理方式 |
/usr/lib64/nginx/modules /etc/nginx/modules |
目錄 | nginx模塊目錄 |
/usr/sbin/nginx /usr/sbin/nginx-debug |
命令 | nginx服務的啟動管理的終端命令 |
/usr/share/doc/nginx-1.14.2 /usr/share/doc/nginx-1.14.2/COPYRIGHT /usr/share/man/man8/nginx.8.gz |
文件, 目錄 | nginx的手冊和幫助文件 |
/var/cache/nginx | 目錄 | nginx的緩存目錄 |
/var/log/nginx | 目錄 | nginx的日志目錄 |
安裝編譯參數
nginx -V
編譯選項 | 作用 |
---|---|
--prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock |
安裝目的目錄或路徑 |
--http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp |
執行對應模塊時,nginx所保留的臨時性文件 |
--user=nginx --group=nginx |
設定nginx進程啟動的用戶和組用戶 |
--with-cc-opt=parameters | 設置額外的參數將被添加到CFLAGS變量 |
--with-ld-opt=parameters | 設置附加的參數,鏈接系統庫 |
默認配置語法
- | - | - |
---|---|---|
user | 設置nginx服務的系統使用用戶 | |
worker_processes | 工作進程數 | |
error_log | nginx的錯誤日志 | |
pid | nginx服務啟動時候pid | |
events | worker_connections use |
每個進程允許最大連接數 工作進程數 |
log
http://nginx.org/en/docs/http/ngx_http_log_module.html
錯誤日志,格式如下
2018/12/11 15:51:32 [error] 5809#5809: *37 open() "/usr/share/nginx/html/favicon.ico" failed (2: No such file or directory), client: 120.194.101.83, server: _, request: "GET /favicon.ico HTTP/1.1", host: "120.79.65.88", referrer: "http://120.79.65.88/"
error_log /var/log/nginx/error.log warn;
日志存放位置/var/log/nginx/error.log
級別warn
access_log 記錄了哪些用戶,哪些頁面以及用戶瀏覽器、ip和其他的訪問信息,形式如下
222.88.236.165 - - [11/Dec/2018:16:38:42 +0800] "GET /static/js/login.js HTTP/1.1" 200 14459 "http://mxonline.iceflower.xyz:8081/login/?next=/course/info/6/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36" "-"
格式設置
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
具體的設置可以在官網中找到,可進行自定制
模塊
http://nginx.org/ru/docs/http/ngx_http_stub_status_module.html
sub_status
--with-http_stub_status_module
nginx的客戶端狀態
配置nginx文件,寫在server中
location = /mystatus {
stub_status;
}
重啟nginx,瀏覽器訪問IP+/mystatus
,格式如下
Active connections: 1
server accepts handled requests
43 43 79
Reading: 0 Writing: 1 Waiting: 0
Active connections
當前活動客戶端連接數,包括Waiting連接數。
accepts
已接受的客戶端連接總數。
handled
處理的連接總數。通常,參數值與accepts 除非已達到某些資源限制(例如, worker_connections限制)相同。
requests
客戶端請求的總數。
Reading
nginx正在讀取請求標頭的當前連接數。
Writing
nginx將響應寫回客戶端的當前連接數。
Waiting
當前等待請求的空閑客戶端連接數。
random_index
http://nginx.org/en/docs/http/ngx_http_random_index_module.html
--with-http_random_index_module
目錄中選擇一個隨機主頁
location / {
root /opt/app/code/html;
random_index on;
}
root 后面是主頁面存放位置
不會選擇隱藏文件作為主頁面
sub_module
http://nginx.org/en/docs/http/ngx_http_sub_module.html
--with-http_sub_module
HTTP內容替換
location / {
sub_filter '<a href="http://127.0.0.1:8080/' '<a href="https://$host/';
sub_filter '<img src="http://127.0.0.1:8080/' '<img src="https://$host/';
sub_filter_once on;
}
敏感詞,流媒體替換
請求限制
limit_conn_module
limit_conn_module
連接頻率限制
http://nginx.org/en/docs/http/ngx_http_limit_conn_module.html
http {
limit_conn_zone $binary_remote_addr zone=addr:10m;
...
server {
...
location /api/ {
limit_conn addr 10;
limit_conn_status 503;
}
}
}
示例中定義key(zone=addr)為addr,分配內存大小為10m(zone=addr:10m)(如果限制域的存儲空間耗盡了,對於后續所有請求,服務器都會返回503),同一個ip($binary_remote_addr)和服務器連接超過10個(limit_conn addr 10)將會被攔截並返回503(limit_conn_status 503)錯誤碼
limit_conn_zone
語法: limit_conn_zone key zone=name:size;(設置限制規則、區域名稱及分配的內存大小)
可配置區域: http
key: 必選項;設置限制規則;取值可以是text文本、nginx變量或兩者的組合;實例中使用的nginx變量$binary_remote_addr表示根據每個ip限制並發
name: 必選項; 自定義一個區域名稱; 任意字符串
size: 分配內存的大小
limit_conn
語法: limit_conn zone number; (使用由limit_conn_zone定義的攔截規則, 並設置具體的限制連接數量)
可配置區域: http, server, location
zone: 必選項; 由limit_conn_zone(zone=name)定義的名稱; 表示使用定義的哪個限制規則
number: 必選項; 正整數; 表示具體的限制連接數量
limit_conn_status
語法: limit_conn_status code;
默認值: 503
可配置區域: http, server, location
表示超出limit_req配置的請求數量后返回給客戶端的錯誤碼使用該指令
limit_conn_log_level
語法: limit_conn_log_level info | notice | warn | error;
默認值: limit_conn_log_level error;
可配置區域: http, server, location
當服務器拒絕處理由於速率超過或延遲請求處理而拒絕處理請求時,設置所需的日志記錄級別。
limit_req_module
limit_req_module
請求頻率限制
http://nginx.org/en/docs/http/ngx_http_limit_req_module.html
http {
limit_req_zone $binary_remote_addr zone=req_perip:50m rate=10r/s;
...
server {
...
location /api/ {
limit_req zone=req_perip burst=50 nodelay;
limit_req_status 503;
}
}
}
示例中定義的區域名稱為req_perip(zone=req_perip),分配內存大小為50m(如果限制域的存儲空間耗盡了,對於后續所有請求,服務器都會返回503),同一個ip($binary_remote_addr)平均處理的請求頻率不能超過每秒10次(rate=10r/s); 如果超過每秒10次但超過的請求數量小於等於50(burst=50)時,會延遲請求。如果超過每秒的請求數超過50,則立即返回503(limit_req_status 503)給客戶端
limit_req_zone
語法: limit_req_zone key zone=name:size rate=rate;(可理解為該指令用來定義限制請求頻率)
可配置區域: http
key: 必選項;取值范圍: 1,text(文本); 2,nginx變量;3,text和nginx變量的組合; name: 必選項;自定義字符串
size: 必選項;分配內存大小,用來保存鍵值的狀態參數
rate: 必選項;每秒可請求的頻率(r/s), 或每分鍾可請求的頻率(r/m)
limit_req
語法: limit_req zone=name [burst=number] [nodelay]; (可理解為使用定義的限制請求頻率,一定是先定義后使用!也就是一定要有limit_req_zone指令的配置后才能使用該配置)
可配置區域: http, server, location
name: 必選項;自定義字符串, 名字必須與limit_req_zone中zone=name這個名字一致
number: 必選項;正整數數字, 平均每秒允許不超過limit_req_zone指令中rate規定的請求數,並且不會超過該值所指定數量的請求,可延遲請求的數量
nodelay: 可選配置,表示請求頻率超過rate規定值后又超過burst規定值后立即返回客戶端503(可設置返回code)
limit_req_status
語法: limit_req_status code;
默認值: 503
可配置區域: http, server, location
表示超出limit_req配置的請求數量后返回給客戶端的錯誤碼使用該指令
limit_req_log_level
語法: limit_req_log_level info | notice | warn | error;
默認值: limit_req_log_level error;
可配置區域: http, server, location
當服務器拒絕處理由於速率超過或延遲請求處理而拒絕處理請求時,設置所需的日志記錄級別。
\(binary_remote_addr是\)remote_addr(客戶端IP)的二進制格式,固定占用4個字節。而\(remote_addr按照字符串存儲,占用7-15個字節。用\)binary_remote_addr可以節省空間。
訪問控制
http_access_module
http_access_module
基於IP的訪問控制
http://nginx.org/en/docs/http/ngx_http_access_module.html
location / {
deny 192.168.1.1; # 拒絕訪問
allow 192.168.1.0/24; # 允許訪問
allow 10.1.1.0/16;
allow 2001:0db8::/32; # IPV6
deny all;
}
局限性
IP1 客戶端
IP2 代理服務器
IP3 服務器
基於客戶端的IP,但是對於Nginx來說,它不會管你哪個是真正的客戶端,如果我們的訪問不是客戶端與服務端直接連接,而是通過了一層代理,比如它的代理可以負載均衡、CDN的這種代理實現,也就是我們的訪問不是客戶端直接訪問的服務端,而是通過其他的中間件訪問服務端,這時候會出現一個問題,因為Nginx的access_module它是基於remote_addr這個變量來識別客戶端的IP的,那么如果一個ip通過中間件訪問服務端,那么Nginx認為訪問的ip就是中間件的IP,那么我們在基於IP做限制的時候,那么其實是沒有作用的。所以這樣的話,准確性是不高的,所以就是利用nginx的access_module有局限性。
解決辦法
-
使用http_x_forwarded_for來解決這個問題
但是http_x_forwarded_for進行訪問控制會存在問題,因為是一個協議要求的,並不是所有的cdn和代理廠商它會按照要求來做,甚至x_forwarded_for存在被修改的可能,因為只是一個頭信息,所以最終還是不真實。http_x_forwardded_for也是Nginx的http頭變量的一個常用的變量,它和remote_addr是有區別的。不同的是,x_forwarded_for是http協議中規定頭中要攜帶的,所以在客戶端訪問中間件,再訪問服務端的時候,那么服務端通過Nginx會記錄真實IP和中間件的IP。
格式:http_x_forwarded_for = 客戶端ip,第一台代理ip,第二台代理ip,第N台代理ip....,所以http_x_forwarded_for是由一連串以逗號分隔的ip組成的。 -
結合geo模塊
http://nginx.org/ru/docs/http/ngx_http_geo_module.html -
通過HTTP自定義變量傳遞
http_auth_basic_module
http_auth_basic_module
基於用戶的信任登錄
http://nginx.org/en/docs/http/ngx_http_auth_basic_module.html
location / {
auth_basic "輸入密碼";
auth_basic_user_file user_passwd;
}
htpasswd安裝
yum install httpd-tools -y
首次創建並加入
htpasswd -c ./user_passwd admin
[root@GYJ nginx]# cd /etc/nginx/
[root@GYJ nginx]# ls
conf.d fastcgi_params koi-win modules nginx.conf.rpmnew uwsgi_params
default.d koi-utf mime.types nginx.conf scgi_params win-utf
[root@GYJ nginx]# htpasswd -c ./user_passwd admin
New password:
Re-type new password:
Adding password for user admin
[root@GYJ nginx]# ls
conf.d fastcgi_params koi-win modules nginx.conf.rpmnew user_passwd win-utf
default.d koi-utf mime.types nginx.conf scgi_params uwsgi_params
[root@GYJ nginx]# vim user_passwd
[root@GYJ nginx]# cat user_passwd
admin:$apr1$I04BhX5R$9JexKOl2aYCe.Tww67XMu0
[root@GYJ nginx]#
http_auth_basic_module局限性
用戶信息依賴文件方式,管理操作機械,效率不高
解決方法:
Nginx結合LUA實現高效驗證
Nginx結合LDAP,利用nginx_auth_ldap模塊