nginx 學習筆記
簡介
nginx是俄羅斯人Igor Sysoev編寫的輕量級Web伺服器。
它不僅是一個高性能的HTTP和反向代理伺服器,同時也是一個IMAP/POP3/SMTP 代理伺服器
nginx只是一個靜態文件伺服器或者http請求轉發器,它可以把靜態文件的請求直接返回靜態文件資源,把動態文件的請求轉發給後台服務。
特點
- 輕量
- 事件驅動的非同步非阻塞處理
- 佔用記憶體少、啟動速度快、並發能力強
- 可靠
- 熱部署:通過master管理進程與worker工作進程的分離設計,使的Nginx具有熱部署的功能,那麼在7×24小時不間斷服務的前提下,升級Nginx的可執行文件。也可以在不停止服務的情況下修改配置文件,更換日誌文件等功能
整體結構
Nginx 主配置文件 /etc/nginx/nginx.conf 是一個純文本類型的文件,整個配置文件是以區塊的形式組織,通常每一個區塊以一對大括弧{}來表示開始與結束(可看下方的程式碼注釋)。
- Main 位於 nginx.conf 配置文件的最高層;
user nginx; worker_processes 1; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; ......
- Main 層下可以有 Event、HTTP 層;
events {} http {}
- Http 層下面允許有多個 Server 層,用於對不同的網站做不同的配置;
- Server 層下面允許有多個 Location,用於對不同的路徑進行不同模組的配置。
應用
- 動靜分離
- 定義:將網站靜態資源(HTML,JavaScript,CSS,img等文件)與後台應用分開部署,提高用戶訪問靜態程式碼的速度,降低對後台應用訪問
- 優點:
- api介面服務化:動靜分離之後,後端應用更為服務化,只需要通過提供api介面即可,可以為多個功能模組甚至是多個平台的功能使用,可以有效的節省後端人力,更便於功能維護
- 前後端開發並行:前後端只需要關心介面協議即可,各自的開發相互不干擾,並行開發,並行自測,可以有效的提高開發時間,也可以有些的減少聯調時間
- 減輕後端伺服器壓力,提高靜態資源訪問速度:後端不用再將模板渲染為html返回給用戶端,且靜態伺服器可以採用更為專業的技術提高靜態資源的訪問速度。
- 反向代理
- 定義:指以代理伺服器來接受internet上的連接請求,然後將請求轉發給內部網路上的伺服器,並將從伺服器上得到的結果返回給internet上請求連接的客戶端,此時代理伺服器對外就表現為一個反向代理伺服器。
簡單來說就是真實的伺服器不能直接被外部網路訪問,所以需要一台代理伺服器,而代理伺服器能被外部網路訪問的同時又跟真實伺服器在同一個網路環境,當然也可能是同一台伺服器,埠不同而已。
對於前端而言,請求後端的介面容易報跨域問題,這就是前端所處於的ip和後端介面的ip不一致,這就用到了反向代理,通過nginx將後端的介面改成瀏覽器一樣的的ip,(跨域除了nginx配置外,可以通過nodejs設置中轉,後端設置白名單)
反向代理是為服務端服務的,反向代理可以幫助伺服器接收來自客戶端的請求,幫助伺服器做請求轉發,負載均衡等。
反向代理對服務端是透明的,對我們是非透明的,即我們並不知道自己訪問的是代理伺服器,而伺服器知道反向代理在為他服務。 - 關鍵命令:proxy_pass
- 作用:
- 安全:隱藏服務節點的IP,將服務節點置於防火牆之後,避免直接攻擊業務節點伺服器
- 服務節點更專註於業務,同時提升性能(去讓nginx實現gzip壓縮,https等等;動靜分離,快取機制,)
- 三種模式
- 基於IP(路徑path)代理
location後的path帶不帶/沒有區別,proxy_pass後的路徑帶不帶『/』 區別很大.- target服務路徑需要context-path(location: /docs)時
location /docs{ proxy_pass //localhost:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } #//aaa.test/docs #代理訪問後端服務://localhost:8080/docs
- target服務路徑不需要context-path(location:/a)時
location /a { proxy_pass //localhost:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } #//localhost:1111/a/docs #代理訪問後端服務://localhost:8080/docs
- 基於域名代理
server { listen 80; server_name a.local; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; location / { proxy_pass //127.0.0.1:8080; } }
- 基於埠代理
server { listen 16010; server_name localhost; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; location / { proxy_pass //192.192.192.192:16010; } }
- 基於IP(路徑path)代理
- eg:這三種模式的反向代理除了基於ip其他的情況都是根據locaiton的根域名為/來設置的,這樣的可以通過訪問域名/埠代理了。
- 定義:指以代理伺服器來接受internet上的連接請求,然後將請求轉發給內部網路上的伺服器,並將從伺服器上得到的結果返回給internet上請求連接的客戶端,此時代理伺服器對外就表現為一個反向代理伺服器。
- 正向代理
- 定義:
與反向代理相反,FQ,就是所謂的正向代理。有個恰當的例子:多個人找代購購買同一個商品,代購找到買這個的店後一次性給買了。這個過程中,該店主是不知道代購是幫別代買買東西的。那麼代購對於多個想買商品的顧客來講,他就充當了正向代理。
正向代理是為我們服務的,即為客戶端服務的,客戶端可以根據正向代理訪問到它本身無法訪問到的伺服器資源。
向代理對我們是透明的,對服務端是非透明的,即服務端並不知道自己收到的是來自代理的訪問還是來自真實客戶端的訪問 - 缺點:不能直接應用於https,需要特製配置,見示例
- 程式碼示例(未實踐,回頭實踐)看 (Nginx伺服器—正向代理)[//blog.csdn.net/weixin_42751488/article/details/124148392]
- 定義:
- 負載均衡
- 定義:簡單而言就是當有2台或2台以上伺服器時,根據規則隨機的將請求分發到指定的伺服器上處理,以來減輕伺服器的壓力。
負載均衡配置一般都需要同時配置反向代理,通過反向代理跳轉到負載均衡。 - 關鍵命令: upstream
- 作用:
- 分攤伺服器集群壓力
- 保證客戶端訪問的穩定性(nginx自帶心跳檢查,會定期輪詢向所有的伺服器發起請求,用來檢查某個伺服器是否異常,若有異常,則停止請求到這個伺服器,直到這個伺服器正常)
- 策略:Nginx目前支援自帶3種負載均衡策略,兩種常見的第三方負載均衡策略
- 默認:按照時間一次分配到不同的機器上
upstream test { server localhost:8080; server localhost:8081; } server { listen 80; server_name localhost; client_max_body_size 1024M; location / { proxy_pass //test; proxy_set_header Host $host:$server_port; } }
- 權重 weight:指定輪詢幾率,weight和訪問比率成正比,用於後端伺服器性能不均的情況。
upstream test { server localhost:8080 weight=9; #請求的 90% 進入到8080伺服器 server localhost:8081 weight=1; #請求的 10% 進入到8081伺服器 }
- ip_hash:每個請求按訪問ip的hash結果分配,這樣每個訪客固定訪問一個後端伺服器,可以解決session的問題,通過session/cookie共享,來指定跳到對應有session/cookie的伺服器,(如果客戶已經訪問了某個伺服器,當用戶再次訪問時,會將該請求通過哈希演算法,自動定位到該伺服器。)
upstream test { ip_hash; server localhost:8080 weight=9; #請求的 90% 進入到8080伺服器 server localhost:8081 weight=1; #請求的 10% 進入到8081伺服器 }
- fair(第三方):按後端伺服器的響應時間來分配請求,響應時間短的優先分配。
upstream test { fair; server localhost:8080 weight=9; #請求的 90% 進入到8080伺服器 server localhost:8081 weight=1; #請求的 10% 進入到8081伺服器 }
- url_hash(第三方):按訪問url的hash結果來分配請求,使每個url定向到同一個(對應的)後端伺服器,後端伺服器為快取時比較有效。
upstream test { server squid1:3128; server squid2:3128; hash $request_uri; hash_method crc32; }
- 默認:按照時間一次分配到不同的機器上
- 定義:簡單而言就是當有2台或2台以上伺服器時,根據規則隨機的將請求分發到指定的伺服器上處理,以來減輕伺服器的壓力。
- 虛擬主機
- 虛擬主機就是將一台伺服器分割成多個「虛擬伺服器」,每個站點使用各自的硬碟空間,由於省資源,省錢,眾多網站都使用虛擬主機來部署網站
- 虛擬主機的概念就是在web服務里的一個獨立的網站站點,這個站點對應獨立的域名(IP),具有獨立的程式和資源目錄,可以獨立的對外提供服務
- 這個獨立的站點配置是在nginx.conf中使用server{}程式碼塊標籤來表示一個虛擬主機
- Nginx支援多個server{}標籤,即支援多個虛擬主機站點
- 本地測試的話需要配置host
- 類型
- 基於 IP 的虛擬主機
server { listen 80;#監聽埠 server_name 192.168.1.1;#配置虛擬主機名和IP location / { root /home/wwwroot/ipsite01/;#請求匹配路徑 index index.html;#指定主頁 access_log /home/wwwlog/ipsite01.access.log main; error_log /home/wwwlog/ipsite01.error.log warn; } } server { listen 80; server_name 192.168.1.2; location / { root /home/wwwroot/ipsite02/;#請求匹配路徑 index index.html; access_log /home/wwwlog/ipsite02.access.log main; error_log /home/wwwlog/ipsite02.error.log warn; } }
- 基於域名的虛擬主機
server { listen 80;#監聽埠 server_name www.cainiaojc.com;#配置虛擬主機域名 location / { root /home/wwwroot/domainsite01/;#請求匹配路徑 index index.html;#指定主頁 access_log /home/wwwlog/domainsite01.access.log main; error_log /home/wwwlog/domainsite01.error.log warn; } } server { listen 80; server_name man.niaoge.com; location / { root /home/wwwroot/domainsite02/;#請求匹配路徑 index index.html; access_log /home/wwwlog/domainsite02.access.log main; error_log /home/wwwlog/domainsite02.error.log warn; } }
- 基於埠的虛擬主機
server { listen 8080;#監聽埠 server_name www.cainiaojc.com;#配置虛擬主機域名 location / { root /home/wwwroot/portsite01/;#請求匹配路徑 index index.html;#指定主頁 access_log /home/wwwlog/portsite01.access.log main; error_log /home/wwwlog/portsite01.error.log warn; } } server { listen 8090; server_name www.cainiaojc.com; location / { root /home/wwwroot/portsite02/;#請求匹配路徑 index index.html; access_log /home/wwwlog/portsite02.access.log main; error_log /home/wwwlog/portsite02.error.log warn; } }
nginx內置全局變數
以下都是nginx的部分內置全局變數,可以在配置的任何位置使用
- $host : 請求資訊中的Host,若請求中沒有host行,則等於設置的伺服器名
- $request_mothed: 客戶端的請求類型,如get/post/put
- $remote_addr: 客戶端的ip
- $args: 請求中的參數
- $content_length: 請求頭中的content-length欄位
- $http_user_agent: 客戶端的agent資訊
- $http_cookie: 客戶端的cookie資訊
- $remote_port: 客戶端的port埠
- $server_protocol: 請求使用的協議,如HTTP/1.0 HTTP/2.0
- $server_addr: 伺服器地址
- $server_name: 伺服器名稱
- $server_port: 伺服器的埠號
- $uri: 請求中的當前 URI,已標準化。我們可以在請求處理期間更改 $uri 的值,例如在進行內部重定向或使用索引文件時。
- $request: 完整的原始請求行
- $request_body: 當請求正文被讀取到 memory_buffer 時,該變數的值在由 proxy_pass 和 scgi_pass 指令處理的位置中可用。
- $request_body_file: 帶有請求正文的臨時文件的名稱。
- $request_uri: 帶有參數的完整原始請求 URI(統一資源標識符)。
nginx變數
在配置文件中,可以通過變數,來上下文使用
用法就是用 $ 來命名變數
set $a "hello world";
#這樣在nginx.conf文件中都能用到
例子:移動端和pc端切換.
location / {
# 適配移動端/PC端配置
set $type "pc";
if ($http_user_agent ~* (mobile|nokia|iphone|ipad|android|samsung|htc|blackberry)) {
set $type "mobile";
}
root /usr/local/var/www/project/$type; # 根據設備類型選擇設定根目錄文件夾名(pc/mobile)
index index.html index.htm;
}
多個server同一個server_name匹配規則
客戶端發出一個http請求時,nginx收到後會取出header頭中的host,與nginx.conf中每個server的server_name進行匹配,以此決定到底由哪一個server塊來處理這個請求。
-
匹配規則:
- 完全匹配
- 通配符在前的,如*.test.com
- 通配符在後的,如www.test.*
- 正則匹配,如~^.www.test.com$
如果都不匹配 - 優先選擇listen配置項後有default或default_server的
- 再不匹配的話,找到匹配listen埠的第一個server塊
-
調試程式碼:
server{ default_type text/plain; listen 80; server_name _; return 200 "no1 match"; } server{ default_type text/plain; listen 80; server_name *.test.com; return 200 "通配符在前"; } server{ default_type text/plain; listen 80; server_name www.test.*; return 200 "通配符在後"; } server{ default_type text/plain; listen 80; server_name ~^www.test.com$; return 200 "正則匹配"; } server{ default_type text/plain; listen 80; server_name www.test.com; return 200 "完全匹配"; } # 把這些放到nginx.conf中,重啟nginx -s reload # 配置host文件 127.0.0.1 www.test.com # 打開www.test.com # 結果就如匹配規則一樣,從前依次刪除server測試,重啟nginx,即可發現規律 # 同樣的,可以改變server的順序,也可得出第一種匹配規則和順序無關
server{ default_type text/plain; listen 80 default_server; server_name 127.0.0.1; return 200 "default"; } server{ default_type text/plain; listen 80; server_name *.test.com; return 200 "通配符在前"; } # 這個我測試的老是報a duplicate default server for 0.0.0.0:82 in /usr/local/etc/nginx/servers/learn.conf:65, 原因未解 # 網上說的即使有defualt,但也會命中通配符在前,這說明了第一種情況的優先順序高於第二種
server{ default_type text/plain; listen 83; return 200 "first"; } server{ default_type text/plain; listen 83; return 200 "last"; } #若都不匹配的話,直接取第一個
location匹配規則
- 基礎
- location 是在 server 塊中配置
- 可以根據不同的 URI 使用不同的配置(location 中配置),來處理不同的請求
- location 是有順序的,會被 第一個 匹配的location 處理。
- 規則
- / 代表任意匹配
- /api 要求必須以指定模式開始
location /api{ #規則 } # 以下訪問都是正確的 # //127.0.0.1/api # //127.0.0.1/api?p1=TOM # //127.0.0.1/api/ # //127.0.0.1/apiapi
- = : 用於不包含正則表達式的uri前,必須與指定的模式精確匹配
location =/api{ #規則 } # 可以匹配到 # //127.0.0.1/api # //127.0.0.1/api?p1=TOM # 匹配不到 # //127.0.0.1/api/ # //127.0.0.1/apiapi
- ~ :大小寫敏感
location ~ /Example/ { #規則 } # 可以匹配到 #//127.0.0.1/Example/ # 匹配不到 #//127.0.0.1/example/
- ~* : 大小寫忽略
location ~* /Example/ { #規則 } # 可以匹配到 #//127.0.0.1/Example/ #//127.0.0.1/example/
- ^~ : 只匹配以 uri 開頭,用於不包含正則表達式的uri前,功能和不加符號的一致,唯一不同的是,如果模式匹配,那麼就停止搜索其他模式了
location ^~ /img/ { #規則 } #以 /img/ 開頭的請求,都會匹配上 #//local.learn.com/img/a.jpg #//local.learn.com/img/b.mp4
- @ nginx內部跳轉
location /img/ { error_page 404 @img_err; } location @img_err { # 規則 } #以 /img/ 開頭的請求,如果鏈接的狀態為 404。則會匹配到 @img_err 這條規則上。
- 匹配順序
多個location配置的情況下匹配順序為(當有匹配成功時候,停止匹配,按當前匹配規則處理請求):- 優先匹配 =
- 其次匹配 ^~
- 按照文件中的匹配順序執行
- 最後匹配 /
程式碼注釋
#運行用戶
user nobody;
#啟動進程,通常設置成和cpu的數量相等
worker_processes 1;
#全局錯誤日誌及PID文件
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
#工作模式及連接數上限
events {
#epoll是多路復用IO(I/O Multiplexing)中的一種方式,
#僅用於linux2.6以上內核,可以大大提高nginx的性能
use epoll;
#單個後台worker process進程的最大並發鏈接數
worker_connections 1024;
# 並發總數是 worker_processes 和 worker_connections 的乘積
# 即 max_clients = worker_processes * worker_connections
# 在設置了反向代理的情況下,max_clients = worker_processes * worker_connections / 4 為什麼
# 為什麼上面反向代理要除以4,應該說是一個經驗值
# 根據以上條件,正常情況下的Nginx Server可以應付的最大連接數為:4 * 8000 = 32000
# worker_connections 值的設置跟物理記憶體大小有關
# 因為並發受IO約束,max_clients的值須小於系統可以打開的最大文件數
# 而系統可以打開的最大文件數和記憶體大小成正比,一般1GB記憶體的機器上可以打開的文件數大約是10萬左右
# 我們來看看360M記憶體的VPS可以打開的文件句柄數是多少:
# $ cat /proc/sys/fs/file-max
# 輸出 34336
# 32000 < 34336,即並發連接總數小於系統可以打開的文件句柄總數,這樣就在作業系統可以承受的範圍之內
# 所以,worker_connections 的值需根據 worker_processes 進程數目和系統可以打開的最大文件總數進行適當地進行設置
# 使得並發總數小於作業系統可以打開的最大文件數目
# 其實質也就是根據主機的物理CPU和記憶體進行配置
# 當然,理論上的並發總數可能會和實際有所偏差,因為主機還有其他的工作進程需要消耗系統資源。
# ulimit -SHn 65535
}
http {
#設定mime類型,類型由mime.type文件定義
include mime.types;
default_type application/octet-stream;
#設定日誌格式
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
#日誌保存地址 格式程式碼 main
access_log logs/access.log main;
#sendfile 指令指定 nginx 是否調用 sendfile 函數(zero copy 方式)來輸出文件,
#對於普通應用,必須設為 on,
#如果用來進行下載等應用磁碟IO重負載應用,可設置為 off,
#以平衡磁碟與網路I/O處理速度,降低系統的uptime.
sendfile on;
#tcp_nopush on;
#連接超時時間
#keepalive_timeout 0;
keepalive_timeout 65;
tcp_nodelay on;
#開啟gzip壓縮
gzip on;
gzip_disable "MSIE [1-6].";
# 設定壓縮的臨界點
gzip_min_length 1000;
# 壓縮級別
gzip_comp_level 3;
# 要壓縮的文件類別
gzip_types text/plain application/xml;
#設定請求緩衝
client_header_buffer_size 128k;
large_client_header_buffers 4 128k;
#開啟錯誤頁面跳轉404
proxy_intercept_errors on;
#設定虛擬主機配置
server {
#偵聽80埠
listen 80;
#定義使用 www.nginx.cn訪問
server_name www.nginx.cn;
#定義伺服器的默認網站根目錄位置
root html;
#設定本虛擬主機的訪問日誌
access_log logs/nginx.access.log main;
#默認請求
location / {
#定義首頁索引文件的名稱
index index.php index.html index.htm;
try_files $uri index.html =404;
}
# 定義錯誤提示頁面
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
#靜態文件,nginx自己處理
location ~ ^/(images|javascript|js|css|flash|media|static)/ {
#過期30天,靜態文件不怎麼更新,過期可以設大一點,
#如果頻繁更新,則可以設置得小一點。
expires 30d;
}
#PHP 腳本請求全部轉發到 FastCGI處理. 使用FastCGI默認配置.
location ~ .php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
#禁止訪問 .htxxx 文件
location ~ /.ht {
deny all;
}
}
}
程式碼示例
- 重定向
301 是永久重定向,302 是臨時跳轉,
主要的區別在於搜索引擎對此的對待方式:- 301:搜索引擎會將權重和 PR 值進行轉移
- 302:搜索引擎不會進行額外處理
server {
listen 80;
server_name ~^(?:www\.)?(.+)$;
return 301 //$1$request_uri;
}
程式碼解釋:在 http 對應的 sever 中,把 server_name 也改為正則模式,並將 $host 用捕獲的根域名 $1 取代www 在這裡會直接棄掉,所以不需要捕獲,使用 ?: 標示實現只分組不捕獲,於是後面的根域名就成了 $1這樣的結果是不管原來是否帶 www,都統一跳轉到不帶 www 的 https 根域名
2. 防盜鏈
location ~* \.(gif|jpg|jpeg|png|bmp|swf)$ {
valid_referers none blocked 192.168.0.103; # 只允許本機IP外鏈引用
if ($invalid_referer){
return 403;
}
}
- 解決跨域
server {
listen 8080;
server_name localhost;
location / {
# 跨域代理設置
proxy_pass //www.baidu.com; # 要實現跨域的域名
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
}
}
- 設置訪問白名單
server {
listen 8080;
server_name localhost;
location / {
# IP訪問限制(只允許IP是 12.12.12.12 的機器才能訪問)
allow 12.12.12.12;
deny all;
root html;
index index.html index.htm;
}
}
注意事項
- 配置server時,server_name所綁定的ip或者域名需要在host文件中添加,要不然會報找不到文件。
- 當訪問時出現502時,代表所代理的服務沒有啟動/或者FQ軟體開啟了。
- alias和root的區別
- alias
- alias不會拼接location後面配置的路徑,會把它丟棄掉,把當前匹配到的目錄指向到指定的目錄
location /test { alias /myTest/nginxTest; } # 訪問地址為:localhost/test/nginxTest.html-->文件目錄:/myTest/nginxTest/nginxTest.html
- 使用alias時,目錄名後面一定要加”/”,否則會找不到文件
- alias在使用正則匹配時,必須捕捉要匹配的內容並在指定的內容處使用
- alias只能位於location塊中
- root
- root會拼接location後面配置的路徑
location /test { root /myTest/nginxTest; } # 訪問地址為:localhost/test/nginxTest.html-->文件目錄:/myTest/nginxTest/test/nginxTest.html # 說明root把匹配的字元/test拼接到了文件路徑中 # 當root下沒有test的文件夾的話會直接報404
- root可以不放在location中,也可以放在http、server、if上下文中
- alias
- Invalid Host header
由於 Vue 的主機檢查配置導致的,1. 找到 Vue 項目中的 build 目錄下的 webpack.dev.js 文件。2. 在 devServer 下添加 disableHostCheck: true ,即跳過檢查,如此訪問 Vue 項目時就不會進行主機檢查。3.重啟項目。
參考資料
(8分鐘帶你深入淺出搞懂Nginx)[//zhuanlan.zhihu.com/p/34943332]
(Nginx中文文檔)[//www.nginx.cn/doc/index.html]
(Nginx 教程)[//www.cainiaojc.com/nginx/nginx-index.html]