最近越來越頻繁地遇到需要配置反向代理的場景,在自己搭建博客的時候,也不可避免要用到 Nginx,所以這段時間集中學(xué)習(xí)了一下 Nginx,同時做了一些筆記,希望也可以幫助到大家~ ??
這篇文章會在 CentOS 環(huán)境下安裝和使用 Nginx,如果對 CentOS 基本操作還不太清楚的,可以先看看 <半小時搞會 CentOS 入門必備基礎(chǔ)知識> 一文先做了解。
相信作為開發(fā)者,大家都知道 Nginx 的重要,廢話不多說,一起來學(xué)習(xí)吧。
CentOS 版本: 7.6
Nginx 版本: 1.16.1
傳統(tǒng)的 Web 服務(wù)器,每個客戶端連接作為一個單獨的進(jìn)程或線程處理,需在切換任務(wù)時將 CPU 切換到新的任務(wù)并創(chuàng)建一個新的運行時上下文,消耗額外的內(nèi)存和 CPU 時間,當(dāng)并發(fā)請求增加時,服務(wù)器響應(yīng)變慢,從而對性能產(chǎn)生負(fù)面影響。
Nginx 是開源、高性能、高可靠的 Web 和反向代理服務(wù)器,而且支持熱部署,幾乎可以做到 7 * 24 小時不間斷運行,即使運行幾個月也不需要重新啟動,還能在不間斷服務(wù)的情況下對軟件版本進(jìn)行熱更新。性能是 Nginx 最重要的考量,其占用內(nèi)存少、并發(fā)能力強、能支持高達(dá) 5w 個并發(fā)連接數(shù),最重要的是,Nginx 是免費的并可以商業(yè)化,配置使用也比較簡單。
Nginx 的最重要的幾個使用場景:
靜態(tài)資源服務(wù),通過本地文件系統(tǒng)提供服務(wù);
反向代理服務(wù),延伸出包括緩存、負(fù)載均衡等;
API 服務(wù),OpenResty ;
對于前端來說 Node.js 不陌生了,Nginx 和 Node.js 的很多理念類似,HTTP 服務(wù)器、事件驅(qū)動、異步非阻塞等,且 Nginx 的大部分功能使用 Node.js 也可以實現(xiàn),但 Nginx 和 Node.js 并不沖突,都有自己擅長的領(lǐng)域。Nginx 擅長于底層服務(wù)器端資源的處理(靜態(tài)資源處理轉(zhuǎn)發(fā)、反向代理,負(fù)載均衡等),Node.js 更擅長上層具體業(yè)務(wù)邏輯的處理,兩者可以完美組合,共同助力前端開發(fā)。
下面我們著重學(xué)習(xí)一下 Nginx 的使用。
首先我們來了解一下簡單請求和非簡單請求,如果同時滿足下面兩個條件,就屬于簡單請求:
請求方法是 HEAD
、GET
、POST
三種之一;
HTTP 頭信息不超過右邊著幾個字段:Accept
、Accept-Language
、Content-Language
、Last-Event-ID
Content-Type
只限于三個值 application/x-www-form-urlencoded
、multipart/form-data
、text/plain
;
凡是不同時滿足這兩個條件的,都屬于非簡單請求。
瀏覽器處理簡單請求和非簡單請求的方式不一樣:
簡單請求
對于簡單請求,瀏覽器會在頭信息中增加 Origin
字段后直接發(fā)出,Origin
字段用來說明,本次請求來自的哪個源(協(xié)議+域名+端口)。
如果服務(wù)器發(fā)現(xiàn) Origin
指定的源不在許可范圍內(nèi),服務(wù)器會返回一個正常的 HTTP 回應(yīng),瀏覽器取到回應(yīng)之后發(fā)現(xiàn)回應(yīng)的頭信息中沒有包含 Access-Control-Allow-Origin
字段,就拋出一個錯誤給 XHR 的 error
事件;
如果服務(wù)器發(fā)現(xiàn) Origin
指定的域名在許可范圍內(nèi),服務(wù)器返回的響應(yīng)會多出幾個 Access-Control-
開頭的頭信息字段。
非簡單請求
非簡單請求是那種對服務(wù)器有特殊要求的請求,比如請求方法是 PUT
或 DELETE
,或 Content-Type
值為 application/json
。瀏覽器會在正式通信之前,發(fā)送一次 HTTP 預(yù)檢 OPTIONS
請求,先詢問服務(wù)器,當(dāng)前網(wǎng)頁所在的域名是否在服務(wù)器的許可名單之中,以及可以使用哪些 HTTP 請求方法和頭信息字段。只有得到肯定答復(fù),瀏覽器才會發(fā)出正式的 XHR
請求,否則報錯。
在瀏覽器上當(dāng)前訪問的網(wǎng)站向另一個網(wǎng)站發(fā)送請求獲取數(shù)據(jù)的過程就是跨域請求。
跨域是瀏覽器的同源策略決定的,是一個重要的瀏覽器安全策略,用于限制一個 origin 的文檔或者它加載的腳本與另一個源的資源進(jìn)行交互,它能夠幫助阻隔惡意文檔,減少可能被攻擊的媒介,可以使用 CORS 配置解除這個限制。
關(guān)于跨域網(wǎng)上已經(jīng)有很多解釋,這里就不啰嗦,也可以直接看 MDN 的 <瀏覽器的同源策略> 文檔進(jìn)一步了解,這里就列舉幾個同源和不同元的例子,相信程序員都能看得懂。
# 同源的例子http://example.com/app1/index.html # 只是路徑不同http://example.com/app2/index.htmlhttp://Example.com:80 # 只是大小寫差異http://example.com# 不同源的例子http://example.com/app1 # 協(xié)議不同https://example.com/app2http://example.com # host 不同http://www.example.comhttp://myapp.example.comhttp://example.com # 端口不同http://example.com:8080復(fù)制代碼
反向代理(Reverse Proxy)對應(yīng)的是正向代理(Forward Proxy),他們的區(qū)別:
正向代理: 一般的訪問流程是客戶端直接向目標(biāo)服務(wù)器發(fā)送請求并獲取內(nèi)容,使用正向代理后,客戶端改為向代理服務(wù)器發(fā)送請求,并指定目標(biāo)服務(wù)器(原始服務(wù)器),然后由代理服務(wù)器和原始服務(wù)器通信,轉(zhuǎn)交請求并獲得的內(nèi)容,再返回給客戶端。正向代理隱藏了真實的客戶端,為客戶端收發(fā)請求,使真實客戶端對服務(wù)器不可見;
舉個具體的例子 ??,你的瀏覽器無法直接訪問谷哥,這時候可以通過一個代理服務(wù)器來幫助你訪問谷哥,那么這個服務(wù)器就叫正向代理。
反向代理: 與一般訪問流程相比,使用反向代理后,直接收到請求的服務(wù)器是代理服務(wù)器,然后將請求轉(zhuǎn)發(fā)給內(nèi)部網(wǎng)絡(luò)上真正進(jìn)行處理的服務(wù)器,得到的結(jié)果返回給客戶端。反向代理隱藏了真實的服務(wù)器,為服務(wù)器收發(fā)請求,使真實服務(wù)器對客戶端不可見。一般在處理跨域請求的時候比較常用?,F(xiàn)在基本上所有的大型網(wǎng)站都設(shè)置了反向代理。
舉個具體的例子 ??,去飯店吃飯,可以點川菜、粵菜、江浙菜,飯店也分別有三個菜系的廚師 ?????,但是你作為顧客不用管哪個廚師給你做的菜,只用點菜即可,小二將你菜單中的菜分配給不同的廚師來具體處理,那么這個小二就是反向代理服務(wù)器。
簡單的說,一般給客戶端做代理的都是正向代理,給服務(wù)器做代理的就是反向代理。
正向代理和反向代理主要的原理區(qū)別可以參見下圖:
一般情況下,客戶端發(fā)送多個請求到服務(wù)器,服務(wù)器處理請求,其中一部分可能要操作一些資源比如數(shù)據(jù)庫、靜態(tài)資源等,服務(wù)器處理完畢后,再將結(jié)果返回給客戶端。
這種模式對于早期的系統(tǒng)來說,功能要求不復(fù)雜,且并發(fā)請求相對較少的情況下還能勝任,成本也低。隨著信息數(shù)量不斷增長,訪問量和數(shù)據(jù)量飛速增長,以及系統(tǒng)業(yè)務(wù)復(fù)雜度持續(xù)增加,這種做法已無法滿足要求,并發(fā)量特別大時,服務(wù)器容易崩。
很明顯這是由于服務(wù)器性能的瓶頸造成的問題,除了堆機器之外,最重要的做法就是負(fù)載均衡。
請求爆發(fā)式增長的情況下,單個機器性能再強勁也無法滿足要求了,這個時候集群的概念產(chǎn)生了,單個服務(wù)器解決不了的問題,可以使用多個服務(wù)器,然后將請求分發(fā)到各個服務(wù)器上,將負(fù)載分發(fā)到不同的服務(wù)器,這就是負(fù)載均衡,核心是「分?jǐn)倝毫Α?。Nginx 實現(xiàn)負(fù)載均衡,一般來說指的是將請求轉(zhuǎn)發(fā)給服務(wù)器集群。
舉個具體的例子 ??,晚高峰乘坐地鐵的時候,入站口經(jīng)常會有地鐵工作人員大喇叭“請走 B 口,B 口人少車空....”,這個工作人員的作用就是負(fù)載均衡。
為了加快網(wǎng)站的解析速度,可以把動態(tài)頁面和靜態(tài)頁面由不同的服務(wù)器來解析,加快解析速度,降低原來單個服務(wù)器的壓力。
一般來說,都需要將動態(tài)資源和靜態(tài)資源分開,由于 Nginx 的高并發(fā)和靜態(tài)資源緩存等特性,經(jīng)常將靜態(tài)資源部署在 Nginx 上。如果請求的是靜態(tài)資源,直接到靜態(tài)資源目錄獲取資源,如果是動態(tài)資源的請求,則利用反向代理的原理,把請求轉(zhuǎn)發(fā)給對應(yīng)后臺應(yīng)用去處理,從而實現(xiàn)動靜分離。
使用前后端分離后,可以很大程度提升靜態(tài)資源的訪問速度,即使動態(tài)服務(wù)不可用,靜態(tài)資源的訪問也不會受到影響。
我們可以先看看
yum list | grep nginx復(fù)制代碼
來看看
然后
yum install nginx復(fù)制代碼
來安裝 Nginx,然后我們在命令行中 nginx -v
就可以看到具體的 Nginx 版本信息,也就安裝完畢了。
然后我們可以使用 rpm -ql nginx
來查看 Nginx 被安裝到了什么地方,有哪些相關(guān)目錄,其中位于 /etc
目錄下的主要是配置文件,還有一些文件見下圖:
主要關(guān)注的文件夾有兩個:
/etc/nginx/conf.d/
文件夾,是我們進(jìn)行子配置的配置項存放處,/etc/nginx/nginx.conf
主配置文件會默認(rèn)把這個文件夾中所有子配置項都引入;
/usr/share/nginx/html/
文件夾,通常靜態(tài)文件都放在這個文件夾,也可以根據(jù)你自己的習(xí)慣放其他地方;
安裝之后開啟 Nginx,如果系統(tǒng)開啟了防火墻,那么需要設(shè)置一下在防火墻中加入需要開放的端口,下面列舉幾個常用的防火墻操作(沒開啟的話不用管這個):
systemctl start firewalld # 開啟防火墻systemctl stop firewalld # 關(guān)閉防火墻systemctl status firewalld # 查看防火墻開啟狀態(tài),顯示running則是正在運行firewall-cmd --reload # 重啟防火墻,永久打開端口需要reload一下# 添加開啟端口,--permanent表示永久打開,不加是臨時打開重啟之后失效firewall-cmd --permanent --zone=public --add-port=8888/tcp# 查看防火墻,添加的端口也可以看到firewall-cmd --list-all復(fù)制代碼
然后設(shè)置 Nginx 的開機啟動:
systemctl enable nginx復(fù)制代碼
啟動 Nginx (其他命令后面有詳細(xì)講解):
systemctl start nginx復(fù)制代碼
然后訪問你的 IP,這時候就可以看到 Nginx 的歡迎頁面了~ Welcome to nginx!
??
# 下載 nvm,或者看官網(wǎng)的步驟 https://github.com/nvm-sh/nvm#install--update-scriptcurl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bashsource ~/.bashrc # 安裝完畢后,更新配置文件即可使用 nvm 命令nvm ls-remote # 查看遠(yuǎn)程 node 版本nvm install v12.16.3 # 選一個你要安裝的版本安裝,我這里選擇 12.16.3nvm list # 安裝完畢查看安裝的 node 版本node -v # 查看是否安裝好了yum install git # git 安裝復(fù)制代碼
Nginx 的命令在控制臺中輸入 nginx -h
就可以看到完整的命令,這里列舉幾個常用的命令:
nginx -s reload # 向主進(jìn)程發(fā)送信號,重新加載配置文件,熱重啟nginx -s reopen # 重啟 Nginxnginx -s stop # 快速關(guān)閉nginx -s quit # 等待工作進(jìn)程處理完成后關(guān)閉nginx -T # 查看當(dāng)前 Nginx 最終的配置nginx -t -c <配置路徑> # 檢查配置是否有問題,如果已經(jīng)在配置目錄,則不需要-c復(fù)制代碼
systemctl
是 Linux 系統(tǒng)應(yīng)用管理工具 systemd
的主命令,用于管理系統(tǒng),我們也可以用它來對 Nginx 進(jìn)行管理,相關(guān)命令如下:
systemctl start nginx # 啟動 Nginxsystemctl stop nginx # 停止 Nginxsystemctl restart nginx # 重啟 Nginxsystemctl reload nginx # 重新加載 Nginx,用于修改配置后systemctl enable nginx # 設(shè)置開機啟動 Nginxsystemctl disable nginx # 關(guān)閉開機啟動 Nginxsystemctl status nginx # 查看 Nginx 運行狀態(tài)復(fù)制代碼
就跟前面文件作用講解的圖所示,Nginx 的主配置文件是 /etc/nginx/nginx.conf
,你可以使用 cat -n nginx.conf
來查看配置。
nginx.conf
結(jié)構(gòu)圖可以這樣概括:
main # 全局配置,對全局生效├── events # 配置影響 Nginx 服務(wù)器或與用戶的網(wǎng)絡(luò)連接├── http # 配置代理,緩存,日志定義等絕大多數(shù)功能和第三方模塊的配置│ ├── upstream # 配置后端服務(wù)器具體地址,負(fù)載均衡配置不可或缺的部分│ ├── server # 配置虛擬主機的相關(guān)參數(shù),一個 http 塊中可以有多個 server 塊│ ├── server│ │ ├── location # server 塊可以包含多個 location 塊,location 指令用于匹配 uri│ │ ├── location│ │ └── ...│ └── ...└── ...復(fù)制代碼
一個 Nginx 配置文件的結(jié)構(gòu)就像 nginx.conf
顯示的那樣,配置文件的語法規(guī)則:
配置文件由指令與指令塊構(gòu)成;
每條指令以 ;
分號結(jié)尾,指令與參數(shù)間以空格符號分隔;
指令塊以 {}
大括號將多條指令組織在一起;
include
語句允許組合多個配置文件以提升可維護(hù)性;
使用 #
符號添加注釋,提高可讀性;
使用 $
符號使用變量;
部分指令的參數(shù)支持正則表達(dá)式;
Nginx 的典型配置:
user nginx; # 運行用戶,默認(rèn)即是nginx,可以不進(jìn)行設(shè)置worker_processes 1; # Nginx 進(jìn)程數(shù),一般設(shè)置為和 CPU 核數(shù)一樣error_log /var/log/nginx/error.log warn; # Nginx 的錯誤日志存放目錄pid /var/run/nginx.pid; # Nginx 服務(wù)啟動時的 pid 存放位置events { use epoll; # 使用epoll的I/O模型(如果你不知道Nginx該使用哪種輪詢方法,會自動選擇一個最適合你操作系統(tǒng)的) worker_connections 1024; # 每個進(jìn)程允許最大并發(fā)數(shù)}http { # 配置使用最頻繁的部分,代理、緩存、日志定義等絕大多數(shù)功能和第三方模塊的配置都在這里設(shè)置 # 設(shè)置日志模式 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; # Nginx訪問日志存放位置 sendfile on; # 開啟高效傳輸模式 tcp_nopush on; # 減少網(wǎng)絡(luò)報文段的數(shù)量 tcp_nodelay on; keepalive_timeout 65; # 保持連接的時間,也叫超時時間,單位秒 types_hash_max_size 2048; include /etc/nginx/mime.types; # 文件擴(kuò)展名與類型映射表 default_type application/octet-stream; # 默認(rèn)文件類型 include /etc/nginx/conf.d/*.conf; # 加載子配置項 server { listen 80; # 配置監(jiān)聽的端口 server_name localhost; # 配置的域名 location / { root /usr/share/nginx/html; # 網(wǎng)站根目錄 index index.html index.htm; # 默認(rèn)首頁文件 deny 172.168.22.11; # 禁止訪問的ip地址,可以為all allow 172.168.33.44; # 允許訪問的ip地址,可以為all } error_page 500 502 503 504 /50x.html; # 默認(rèn)50x對應(yīng)的訪問頁面 error_page 400 404 error.html; # 同上 }}復(fù)制代碼
server 塊可以包含多個 location 塊,location 指令用于匹配 uri,語法:
location [ = | ~ | ~* | ^~] uri { ...}復(fù)制代碼
指令后面:
=
精確匹配路徑,用于不含正則表達(dá)式的 uri 前,如果匹配成功,不再進(jìn)行后續(xù)的查找;
^~
用于不含正則表達(dá)式的 uri; 前,表示如果該符號后面的字符是最佳匹配,采用該規(guī)則,不再進(jìn)行后續(xù)的查找;
~
表示用該符號后面的正則去匹配路徑,區(qū)分大小寫;
~*
表示用該符號后面的正則去匹配路徑,不區(qū)分大小寫。跟 ~
優(yōu)先級都比較低,如有多個location的正則能匹配的話,則使用正則表達(dá)式最長的那個;
如果 uri 包含正則表達(dá)式,則必須要有 ~
或 ~*
標(biāo)志。
Nginx 有一些常用的全局變量,你可以在配置的任何位置使用它們,如下表:
全局變量名 | 功能 |
---|---|
$host | 請求信息中的 Host ,如果請求中沒有 Host 行,則等于設(shè)置的服務(wù)器名,不包含端口 |
$request_method | 客戶端請求類型,如 GET 、POST |
$remote_addr | 客戶端的 IP 地址 |
$args | 請求中的參數(shù) |
$arg_PARAMETER | GET 請求中變量名 PARAMETER 參數(shù)的值,例如:$http_user_agent (Uaer-Agent 值), $http_referer ... |
$content_length | 請求頭中的 Content-length 字段 |
$http_user_agent | 客戶端agent信息 |
$http_cookie | 客戶端cookie信息 |
$remote_addr | 客戶端的IP地址 |
$remote_port | 客戶端的端口 |
$http_user_agent | 客戶端agent信息 |
$server_protocol | 請求使用的協(xié)議,如 HTTP/1.0 、HTTP/1.1 |
$server_addr | 服務(wù)器地址 |
$server_name | 服務(wù)器名稱 |
$server_port | 服務(wù)器的端口號 |
$scheme | HTTP 方法(如http,https) |
還有更多的內(nèi)置預(yù)定義變量,可以直接搜索關(guān)鍵字「nginx內(nèi)置預(yù)定義變量」可以看到一堆博客寫這個,這些變量都可以在配置文件中直接使用。
在某某云 ?? 上購買了域名之后,就可以配置虛擬主機了,一般配置的路徑在 域名管理 -> 解析 -> 添加記錄
中添加二級域名,配置后某某云會把二級域名也解析到我們配置的服務(wù)器 IP 上,然后我們在 Nginx 上配置一下虛擬主機的訪問監(jiān)聽,就可以拿到從這個二級域名過來的請求了。
現(xiàn)在我自己的服務(wù)器上配置了一個 fe 的二級域名,也就是說在外網(wǎng)訪問 fe.sherlocked93.club
的時候,也可以訪問到我們的服務(wù)器了。
由于默認(rèn)配置文件 /etc/nginx/nginx.conf
的 http 模塊中有一句 include /etc/nginx/conf.d/*.conf
也就是說 conf.d
文件夾下的所有 *.conf
文件都會作為子配置項被引入配置文件中。為了維護(hù)方便,我在 /etc/nginx/conf.d
文件夾中新建一個 fe.sherlocked93.club.conf
:
# /etc/nginx/conf.d/fe.sherlocked93.club.confserver { listen 80; server_name fe.sherlocked93.club; location / { root /usr/share/nginx/html/fe; index index.html; }}復(fù)制代碼
然后在 /usr/share/nginx/html
文件夾下新建 fe 文件夾,新建文件 index.html
,內(nèi)容隨便寫點,改完 nginx -s reload
重新加載,瀏覽器中輸入 fe.sherlocked93.club
,發(fā)現(xiàn)從二級域名就可以訪問到我們剛剛新建的 fe 文件夾:
反向代理是工作中最常用的服務(wù)器功能,經(jīng)常被用來解決跨域問題,下面簡單介紹一下如何實現(xiàn)反向代理。
首先進(jìn)入 Nginx 的主配置文件:
vim /etc/nginx/nginx.conf復(fù)制代碼
為了看起來方便,把行號顯示出來 :set nu
(個人習(xí)慣),然后我們?nèi)?http
模塊的 server
塊中的 location /
,增加一行將默認(rèn)網(wǎng)址重定向到最大學(xué)習(xí)網(wǎng)站 Bilibili 的 proxy_pass
配置 ?? :
改完保存退出,nginx -s reload
重新加載,進(jìn)入默認(rèn)網(wǎng)址,那么現(xiàn)在就直接跳轉(zhuǎn)到 B 站了,實現(xiàn)了一個簡單的代理。
實際使用中,可以將請求轉(zhuǎn)發(fā)到本機另一個服務(wù)器上,也可以根據(jù)訪問的路徑跳轉(zhuǎn)到不同端口的服務(wù)中。
比如我們監(jiān)聽 9001
端口,然后把訪問不同路徑的請求進(jìn)行反向代理:
把訪問 http://127.0.0.1:9001/edu
的請求轉(zhuǎn)發(fā)到 http://127.0.0.1:8080
把訪問 http://127.0.0.1:9001/vod
的請求轉(zhuǎn)發(fā)到 http://127.0.0.1:8081
這種要怎么配置呢,首先同樣打開主配置文件,然后在 http 模塊下增加一個 server 塊:
server { listen 9001; server_name *.sherlocked93.club; location ~ /edu/ { proxy_pass http://127.0.0.1:8080; } location ~ /vod/ { proxy_pass http://127.0.0.1:8081; }}復(fù)制代碼
反向代理還有一些其他的指令,可以了解一下:
proxy_set_header
:在將客戶端請求發(fā)送給后端服務(wù)器之前,更改來自客戶端的請求頭信息。
proxy_connect_timeout
:配置Nginx與后端代理服務(wù)器嘗試建立連接的超時時間。
proxy_read_timeout
:配置Nginx向后端服務(wù)器組發(fā)出read請求后,等待相應(yīng)的超時時間。
proxy_send_timeout
:配置Nginx向后端服務(wù)器組發(fā)出write請求后,等待相應(yīng)的超時時間。
proxy_redirect
:用于修改后端服務(wù)器返回的響應(yīng)頭中的Location和Refresh。
關(guān)于簡單請求、非簡單請求、跨域的概念,前面已經(jīng)介紹過了,還不了解的可以看看前面的講解。現(xiàn)在前后端分離的項目一統(tǒng)天下,經(jīng)常本地起了前端服務(wù),需要訪問不同的后端地址,不可避免遇到跨域問題。
要解決跨域問題,我們來制造一個跨域問題。首先和前面設(shè)置二級域名的方式一樣,先設(shè)置好 fe.sherlocked93.club
和 be.sherlocked93.club
二級域名,都指向本云服務(wù)器地址,雖然對應(yīng) IP 是一樣的,但是在 fe.sherlocked93.club
域名發(fā)出的請求訪問 be.sherlocked93.club
域名的請求還是跨域了,因為訪問的 host 不一致(如果不知道啥原因參見前面跨域的內(nèi)容)。
在前端服務(wù)地址為 fe.sherlocked93.club
的頁面請求 be.sherlocked93.club
的后端服務(wù)導(dǎo)致的跨域,可以這樣配置:
server { listen 9001; server_name fe.sherlocked93.club; location / { proxy_pass be.sherlocked93.club; }}復(fù)制代碼
這樣就將對前一個域名 fe.sherlocked93.club
的請求全都代理到了 be.sherlocked93.club
,前端的請求都被我們用服務(wù)器代理到了后端地址下,繞過了跨域。
這里對靜態(tài)文件的請求和后端服務(wù)的請求都以 fe.sherlocked93.club
開始,不易區(qū)分,所以為了實現(xiàn)對后端服務(wù)請求的統(tǒng)一轉(zhuǎn)發(fā),通常我們會約定對后端服務(wù)的請求加上 /apis/
前綴或者其他的 path 來和對靜態(tài)資源的請求加以區(qū)分,此時我們可以這樣配置:
# 請求跨域,約定代理后端服務(wù)請求path以/apis/開頭location ^~/apis/ { # 這里重寫了請求,將正則匹配中的第一個分組的path拼接到真正的請求后面,并用break停止后續(xù)匹配 rewrite ^/apis/(.*)$ /$1 break; proxy_pass be.sherlocked93.club; # 兩個域名之間cookie的傳遞與回寫 proxy_cookie_domain be.sherlocked93.club fe.sherlocked93.club;}復(fù)制代碼
這樣,靜態(tài)資源我們使用 fe.sherlocked93.club/xx.html
,動態(tài)資源我們使用 fe.sherlocked93.club/apis/getAwo
,瀏覽器頁面看起來仍然訪問的前端服務(wù)器,繞過了瀏覽器的同源策略,畢竟我們看起來并沒有跨域。
也可以統(tǒng)一一點,直接把前后端服務(wù)器地址直接都轉(zhuǎn)發(fā)到另一個 server.sherlocked93.club
,只通過在后面添加的 path 來區(qū)分請求的是靜態(tài)資源還是后端服務(wù),看需求了。
當(dāng)瀏覽器在訪問跨源的服務(wù)器時,也可以在跨域的服務(wù)器上直接設(shè)置 Nginx,從而前端就可以無感地開發(fā),不用把實際上訪問后端的地址改成前端服務(wù)的地址,這樣可適性更高。
比如前端站點是 fe.sherlocked93.club
,這個地址下的前端頁面請求 be.sherlocked93.club
下的資源,比如前者的 fe.sherlocked93.club/index.html
內(nèi)容是這樣的:
<html><body> <h1>welcome fe.sherlocked93.club!!<h1> <script type='text/javascript'> var xmlhttp = new XMLHttpRequest() xmlhttp.open("GET", "http://be.sherlocked93.club/index.html", true); xmlhttp.send(); </script></body></html>復(fù)制代碼
打開瀏覽器訪問 fe.sherlocked93.club/index.html
的結(jié)果如下:
很明顯這里是跨域請求,在瀏覽器中直接訪問 http://be.sherlocked93.club/index.html
是可以訪問到的,但是在 fe.sherlocked93.club
的 html 頁面訪問就會出現(xiàn)跨域。
在 /etc/nginx/conf.d/
文件夾中新建一個配置文件,對應(yīng)二級域名 be.sherlocked93.club
:
# /etc/nginx/conf.d/be.sherlocked93.club.confserver { listen 80; server_name be.sherlocked93.club; add_header 'Access-Control-Allow-Origin' $http_origin; # 全局變量獲得當(dāng)前請求origin,帶cookie的請求不支持* add_header 'Access-Control-Allow-Credentials' 'true'; # 為 true 可帶上 cookie add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; # 允許請求方法 add_header 'Access-Control-Allow-Headers' $http_access_control_request_headers; # 允許請求的 header,可以為 * add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range'; if ($request_method = 'OPTIONS') { add_header 'Access-Control-Max-Age' 1728000; # OPTIONS 請求的有效期,在有效期內(nèi)不用發(fā)出另一條預(yù)檢請求 add_header 'Content-Type' 'text/plain; charset=utf-8'; add_header 'Content-Length' 0; return 204; # 200 也可以 } location / { root /usr/share/nginx/html/be; index index.html; }}復(fù)制代碼
然后 nginx -s reload
重新加載配置。這時再訪問 fe.sherlocked93.club/index.html
結(jié)果如下,請求中出現(xiàn)了我們剛剛配置的 Header:
解決了跨域問題。
gzip 是一種常用的網(wǎng)頁壓縮技術(shù),傳輸?shù)木W(wǎng)頁經(jīng)過 gzip 壓縮之后大小通常可以變?yōu)樵瓉淼囊话肷踔粮。ü倬W(wǎng)原話),更小的網(wǎng)頁體積也就意味著帶寬的節(jié)約和傳輸速度的提升,特別是對于訪問量巨大大型網(wǎng)站來說,每一個靜態(tài)資源體積的減小,都會帶來可觀的流量與帶寬的節(jié)省。
百度可以找到很多檢測站點來查看目標(biāo)網(wǎng)頁有沒有開啟 gzip 壓縮,在下隨便找了一個 <網(wǎng)頁GZIP壓縮檢測> 輸入掘金 juejin.im
來偷窺下掘金有沒有開啟 gzip。
這里可以看到掘金是開啟了 gzip 的,壓縮效果還挺不錯,達(dá)到了 52% 之多,本來 34kb
的網(wǎng)頁體積,壓縮完只需要 16kb
,可以想象網(wǎng)頁傳輸速度提升了不少。
使用 gzip 不僅需要 Nginx 配置,瀏覽器端也需要配合,需要在請求消息頭中包含 Accept-Encoding: gzip
(IE5 之后所有的瀏覽器都支持了,是現(xiàn)代瀏覽器的默認(rèn)設(shè)置)。一般在請求 html 和 css 等靜態(tài)資源的時候,支持的瀏覽器在 request 請求靜態(tài)資源的時候,會加上 Accept-Encoding: gzip
這個 header,表示自己支持 gzip 的壓縮方式,Nginx 在拿到這個請求的時候,如果有相應(yīng)配置,就會返回經(jīng)過 gzip 壓縮過的文件給瀏覽器,并在 response 相應(yīng)的時候加上 content-encoding: gzip
來告訴瀏覽器自己采用的壓縮方式(因為瀏覽器在傳給服務(wù)器的時候一般還告訴服務(wù)器自己支持好幾種壓縮方式),瀏覽器拿到壓縮的文件后,根據(jù)自己的解壓方式進(jìn)行解析。
先來看看 Nginx 怎么進(jìn)行 gzip 配置,和之前的配置一樣,為了方便管理,還是在 /etc/nginx/conf.d/
文件夾中新建配置文件 gzip.conf
:
# /etc/nginx/conf.d/gzip.confgzip on; # 默認(rèn)off,是否開啟gzipgzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;# 上面兩個開啟基本就能跑起了,下面的愿意折騰就了解一下gzip_static on;gzip_proxied any;gzip_vary on;gzip_comp_level 6;gzip_buffers 16 8k;# gzip_min_length 1k;gzip_http_version 1.1;復(fù)制代碼
稍微解釋一下:
gzip_types:要采用 gzip 壓縮的 MIME 文件類型,其中 text/html 被系統(tǒng)強制啟用;
gzip_static:默認(rèn) off,該模塊啟用后,Nginx 首先檢查是否存在請求靜態(tài)文件的 gz 結(jié)尾的文件,如果有則直接返回該 .gz
文件內(nèi)容;
gzip_proxied:默認(rèn) off,nginx做為反向代理時啟用,用于設(shè)置啟用或禁用從代理服務(wù)器上收到相應(yīng)內(nèi)容 gzip 壓縮;
gzip_vary:用于在響應(yīng)消息頭中添加 Vary:Accept-Encoding
,使代理服務(wù)器根據(jù)請求頭中的 Accept-Encoding
識別是否啟用 gzip 壓縮;
gzip_comp_level:gzip 壓縮比,壓縮級別是 1-9,1 壓縮級別最低,9 最高,級別越高壓縮率越大,壓縮時間越長,建議 4-6;
gzip_buffers:獲取多少內(nèi)存用于緩存壓縮結(jié)果,16 8k 表示以 8k*16 為單位獲得;
gzip_min_length:允許壓縮的頁面最小字節(jié)數(shù),頁面字節(jié)數(shù)從header頭中的 Content-Length
中進(jìn)行獲取。默認(rèn)值是 0,不管頁面多大都壓縮。建議設(shè)置成大于 1k 的字節(jié)數(shù),小于 1k 可能會越壓越大;
gzip_http_version:默認(rèn) 1.1,啟用 gzip 所需的 HTTP 最低版本;
這個配置可以插入到 http 模塊整個服務(wù)器的配置里,也可以插入到需要使用的虛擬主機的 server
或者下面的 location
模塊中,當(dāng)然像上面我們這樣寫的話就是被 include 到 http 模塊中了。
其他更全的配置信息可以查看 <官網(wǎng)文檔ngx_http_gzip_module>,配置前是這樣的:
配置之后 response 的 header 里面多了一個 Content-Encoding: gzip
,返回信息被壓縮了:
注意了,一般 gzip 的配置建議加上 gzip_min_length 1k
,不加的話:
由于文件太小,gzip 壓縮之后得到了 -48% 的體積優(yōu)化,壓縮之后體積還比壓縮之前體積大了,所以最好設(shè)置低于 1kb
的文件就不要 gzip 壓縮了 ??
當(dāng)前端項目使用 Webpack 進(jìn)行打包的時候,也可以開啟 gzip 壓縮:
// vue-cli3 的 vue.config.js 文件const CompressionWebpackPlugin = require('compression-webpack-plugin')module.exports = { // gzip 配置 configureWebpack: config => { if (process.env.NODE_ENV === 'production') { // 生產(chǎn)環(huán)境 return { plugins: [new CompressionWebpackPlugin({ test: /\.js$|\.html$|\.css/, // 匹配文件名 threshold: 10240, // 文件壓縮閾值,對超過10k的進(jìn)行壓縮 deleteOriginalAssets: false // 是否刪除源文件 })] } } }, ...}復(fù)制代碼
由此打包出來的文件如下圖:
這里可以看到某些打包之后的文件下面有一個對應(yīng)的 .gz
經(jīng)過 gzip
壓縮之后的文件,這是因為這個文件超過了 10kb
,有的文件沒有超過 10kb
就沒有進(jìn)行 gzip
打包,如果你期望壓縮文件的體積閾值小一點,可以在 compression-webpack-plugin
這個插件的配置里進(jìn)行對應(yīng)配置。
那么為啥這里 Nginx 已經(jīng)有了 gzip 壓縮,Webpack 這里又整了個 gzip 呢,因為如果全都是使用 Nginx 來壓縮文件,會耗費服務(wù)器的計算資源,如果服務(wù)器的 gzip_comp_level
配置的比較高,就更增加服務(wù)器的開銷,相應(yīng)增加客戶端的請求時間,得不償失。
如果壓縮的動作在前端打包的時候就做了,把打包之后的高壓縮等級文件作為靜態(tài)資源放在服務(wù)器上,Nginx 會優(yōu)先查找這些壓縮之后的文件返回給客戶端,相當(dāng)于把壓縮文件的動作從 Nginx 提前給 Webpack 打包的時候完成,節(jié)約了服務(wù)器資源,所以一般推介在生產(chǎn)環(huán)境應(yīng)用 Webpack 配置 gzip 壓縮。
負(fù)載均衡在之前已經(jīng)介紹了相關(guān)概念了,主要思想就是把負(fù)載均勻合理地分發(fā)到多個服務(wù)器上,實現(xiàn)壓力分流的目的。
主要配置如下:
http { upstream myserver { # ip_hash; # ip_hash 方式 # fair; # fair 方式 server 127.0.0.1:8081; # 負(fù)載均衡目的服務(wù)地址 server 127.0.0.1:8080; server 127.0.0.1:8082 weight=10; # weight 方式,不寫默認(rèn)為 1 } server { location / { proxy_pass http://myserver; proxy_connect_timeout 10; } }}復(fù)制代碼
Nginx 提供了好幾種分配方式,默認(rèn)為輪詢,就是輪流來。有以下幾種分配方式:
輪詢,默認(rèn)方式,每個請求按時間順序逐一分配到不同的后端服務(wù)器,如果后端服務(wù)掛了,能自動剔除;
weight,權(quán)重分配,指定輪詢幾率,權(quán)重越高,在被訪問的概率越大,用于后端服務(wù)器性能不均的情況;
ip_hash,每個請求按訪問 IP 的 hash 結(jié)果分配,這樣每個訪客固定訪問一個后端服務(wù)器,可以解決動態(tài)網(wǎng)頁 session 共享問題。負(fù)載均衡每次請求都會重新定位到服務(wù)器集群中的某一個,那么已經(jīng)登錄某一個服務(wù)器的用戶再重新定位到另一個服務(wù)器,其登錄信息將會丟失,這樣顯然是不妥的;
fair(第三方),按后端服務(wù)器的響應(yīng)時間分配,響應(yīng)時間短的優(yōu)先分配,依賴第三方插件 nginx-upstream-fair,需要先安裝;
動靜分離在之前也介紹過了,就是把動態(tài)和靜態(tài)的請求分開。方式主要有兩種,一種 是純粹把靜態(tài)文件獨立成單獨的域名,放在獨立的服務(wù)器上,也是目前主流推崇的方案。另外一種方法就是動態(tài)跟靜態(tài)文件混合在一起發(fā)布, 通過 Nginx 配置來分開。
通過 location 指定不同的后綴名實現(xiàn)不同的請求轉(zhuǎn)發(fā)。通過 expires 參數(shù)設(shè)置,可以使瀏覽器緩存過期時間,減少與服務(wù)器之前的請求和流量。具體 expires 定義:是給一個資源設(shè)定一個過期時間,也就是說無需去服務(wù)端驗證,直接通過瀏覽器自身確認(rèn)是否過期即可,所以不會產(chǎn)生額外的流量。此種方法非常適合不經(jīng)常變動的資源。(如果經(jīng)常更新的文件,不建議使用 expires 來緩存),我這里設(shè)置 3d,表示在這 3 天之內(nèi)訪問這個URL,發(fā)送一個請求,比對服務(wù)器該文件最后更新時間沒有變化。則不會從服務(wù)器抓取,返回狀態(tài)碼 304,如果有修改,則直接從服務(wù)器重新下載,返回狀態(tài)碼 200。
server { location /www/ { root /data/; index index.html index.htm; } location /image/ { root /data/; autoindex on; }}復(fù)制代碼
當(dāng)主 Nginx 服務(wù)器宕機之后,切換到備份 Nginx 服務(wù)器
首先安裝 keepalived,
yum install keepalived -y復(fù)制代碼
然后編輯 /etc/keepalived/keepalived.conf
配置文件,并在配置文件中增加 vrrp_script
定義一個外圍檢測機制,并在 vrrp_instance
中通過定義 track_script
來追蹤腳本執(zhí)行過程,實現(xiàn)節(jié)點轉(zhuǎn)移:
global_defs{ notification_email { acassen@firewall.loc } notification_email_from Alexandre@firewall.loc smtp_server 127.0.0.1 smtp_connect_timeout 30 // 上面都是郵件配置,沒卵用 router_id LVS_DEVEL // 當(dāng)前服務(wù)器名字,用hostname命令來查看}vrrp_script chk_maintainace { // 檢測機制的腳本名稱為chk_maintainace script "[[ -e/etc/keepalived/down ]] && exit 1 || exit 0" // 可以是腳本路徑或腳本命令 // script "/etc/keepalived/nginx_check.sh" // 比如這樣的腳本路徑 interval 2 // 每隔2秒檢測一次 weight -20 // 當(dāng)腳本執(zhí)行成立,那么把當(dāng)前服務(wù)器優(yōu)先級改為-20}vrrp_instanceVI_1 { // 每一個vrrp_instance就是定義一個虛擬路由器 state MASTER // 主機為MASTER,備用機為BACKUP interface eth0 // 網(wǎng)卡名字,可以從ifconfig中查找 virtual_router_id 51 // 虛擬路由的id號,一般小于255,主備機id需要一樣 priority 100 // 優(yōu)先級,master的優(yōu)先級比backup的大 advert_int 1 // 默認(rèn)心跳間隔 authentication { // 認(rèn)證機制 auth_type PASS auth_pass 1111 // 密碼 } virtual_ipaddress { // 虛擬地址vip 172.16.2.8 }}復(fù)制代碼
其中檢測腳本 nginx_check.sh
,這里提供一個:
#!/bin/bashA=`ps -C nginx --no-header | wc -l`if [ $A -eq 0 ];then /usr/sbin/nginx # 嘗試重新啟動nginx sleep 2 # 睡眠2秒 if [ `ps -C nginx --no-header | wc -l` -eq 0 ];then killall keepalived # 啟動失敗,將keepalived服務(wù)殺死。將vip漂移到其它備份節(jié)點 fifi復(fù)制代碼
復(fù)制一份到備份服務(wù)器,備份 Nginx 的配置要將 state
后改為 BACKUP
,priority
改為比主機小。
設(shè)置完畢后各自 service keepalived start
啟動,經(jīng)過訪問成功之后,可以把 Master 機的 keepalived 停掉,此時 Master 機就不再是主機了 service keepalived stop
,看訪問虛擬 IP 時是否能夠自動切換到備機 ip addr
。
再次啟動 Master 的 keepalived,此時 vip 又變到了主機上。
根據(jù)用戶設(shè)備不同返回不同樣式的站點,以前經(jīng)常使用的是純前端的自適應(yīng)布局,但無論是復(fù)雜性和易用性上面還是不如分開編寫的好,比如我們常見的淘寶、京東......這些大型網(wǎng)站就都沒有采用自適應(yīng),而是用分開制作的方式,根據(jù)用戶請求的 user-agent
來判斷是返回 PC 還是 H5 站點。
首先在 /usr/share/nginx/html
文件夾下 mkdir
分別新建兩個文件夾 PC
和 mobile
,vim
編輯兩個 index.html
隨便寫點內(nèi)容。
cd /usr/share/nginx/htmlmkdir pc mobilecd pcvim index.html # 隨便寫點比如 hello pc!cd ../mobilevim index.html # 隨便寫點比如 hello mobile!復(fù)制代碼
然后和設(shè)置二級域名虛擬主機時候一樣,去 /etc/nginx/conf.d
文件夾下新建一個配置文件 fe.sherlocked93.club.conf
:
# /etc/nginx/conf.d/fe.sherlocked93.club.confserver { listen 80; server_name fe.sherlocked93.club; location / { root /usr/share/nginx/html/pc; if ($http_user_agent ~* '(Android|webOS|iPhone|iPod|BlackBerry)') { root /usr/share/nginx/html/mobile; } index index.html; }}復(fù)制代碼
配置基本沒什么不一樣的,主要多了一個 if
語句,然后使用 $http_user_agent
全局變量來判斷用戶請求的 user-agent
,指向不同的 root 路徑,返回對應(yīng)站點。
在瀏覽器訪問這個站點,然后 F12 中模擬使用手機訪問:
可以看到在模擬使用移動端訪問的時候,Nginx 返回的站點變成了移動端對應(yīng)的 html 了。
具體配置過程網(wǎng)上挺多的了,也可以使用你購買的某某云,一般都會有免費申請的服務(wù)器證書,安裝直接看所在云的操作指南即可。
我購買的騰訊云提供的亞洲誠信機構(gòu)頒發(fā)的免費證書只能一個域名使用,二級域名什么的需要另外申請,但是申請審批比較快,一般幾分鐘就能成功,然后下載證書的壓縮文件,里面有個 nginx 文件夾,把 xxx.crt
和 xxx.key
文件拷貝到服務(wù)器目錄,再配置下:
server { listen 443 ssl http2 default_server; # SSL 訪問端口號為 443 server_name sherlocked93.club; # 填寫綁定證書的域名 ssl_certificate /etc/nginx/https/1_sherlocked93.club_bundle.crt; # 證書文件地址 ssl_certificate_key /etc/nginx/https/2_sherlocked93.club.key; # 私鑰文件地址 ssl_session_timeout 10m; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #請按照以下協(xié)議配置 ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; ssl_prefer_server_ciphers on; location / { root /usr/share/nginx/html; index index.html index.htm; }}復(fù)制代碼
寫完 nginx -t -q
校驗一下,沒問題就 nginx -s reload
,現(xiàn)在去訪問 https://sherlocked93.club/
就能訪問 HTTPS 版的網(wǎng)站了。
一般還可以加上幾個增強安全性的命令:
add_header X-Frame-Options DENY; # 減少點擊劫持add_header X-Content-Type-Options nosniff; # 禁止服務(wù)器自動解析資源類型add_header X-Xss-Protection 1; # 防XSS攻擊復(fù)制代碼
server { listen 80; server_name static.sherlocked93.club; charset utf-8; # 防止中文文件名亂碼 location /download { alias /usr/share/nginx/html/static; # 靜態(tài)資源目錄 autoindex on; # 開啟靜態(tài)資源列目錄 autoindex_exact_size off; # on(默認(rèn))顯示文件的確切大小,單位是byte;off顯示文件大概大小,單位KB、MB、GB autoindex_localtime off; # off(默認(rèn))時顯示的文件時間為GMT時間;on顯示的文件時間為服務(wù)器時間 }}復(fù)制代碼
server { listen 80; server_name *.sherlocked93.club; # 圖片防盜鏈 location ~* \.(gif|jpg|jpeg|png|bmp|swf)$ { valid_referers none blocked 192.168.0.2; # 只允許本機 IP 外鏈引用 if ($invalid_referer){ return 403; } }}復(fù)制代碼
# 非指定請求全返回 403if ( $request_method !~ ^(GET|POST|HEAD)$ ) { return 403;}location / { # IP訪問限制(只允許IP是 192.168.0.2 機器訪問) allow 192.168.0.2; deny all; root html; index index.html index.htm;}復(fù)制代碼
由于圖片、字體、音頻、視頻等靜態(tài)文件在打包的時候通常會增加了 hash,所以緩存可以設(shè)置的長一點,先設(shè)置強制緩存,再設(shè)置協(xié)商緩存;如果存在沒有 hash 值的靜態(tài)文件,建議不設(shè)置強制緩存,僅通過協(xié)商緩存判斷是否需要使用緩存。
# 圖片緩存時間設(shè)置location ~ .*\.(css|js|jpg|png|gif|swf|woff|woff2|eot|svg|ttf|otf|mp3|m4a|aac|txt)$ { expires 10d;}# 如果不希望緩存expires -1;復(fù)制代碼
server { listen 80; server_name fe.sherlocked93.club; location / { root /usr/share/nginx/html/dist; # vue 打包后的文件夾 index index.html index.htm; try_files $uri $uri/ /index.html @rewrites; expires -1; # 首頁一般沒有強制緩存 add_header Cache-Control no-cache; } # 接口轉(zhuǎn)發(fā),如果需要的話 #location ~ ^/api { # proxy_pass http://be.sherlocked93.club; #} location @rewrites { rewrite ^(.+)$ /index.html break; }}復(fù)制代碼
配置完 HTTPS 后,瀏覽器還是可以訪問 HTTP 的地址 http://sherlocked93.club/
的,可以做一個 301 跳轉(zhuǎn),把對應(yīng)域名的 HTTP 請求重定向到 HTTPS 上
server { listen 80; server_name www.sherlocked93.club; # 單域名重定向 if ($host = 'www.sherlocked93.club'){ return 301 https://www.sherlocked93.club$request_uri; } # 全局非 https 協(xié)議時重定向 if ($scheme != 'https') { return 301 https://$server_name$request_uri; } # 或者全部重定向 return 301 https://$server_name$request_uri; # 以上配置選擇自己需要的即可,不用全部加}復(fù)制代碼
這是一個非常實用的技能,經(jīng)常有時候我們可能需要配置一些二級或者三級域名,希望通過 Nginx 自動指向?qū)?yīng)目錄,比如:
test1.doc.sherlocked93.club
自動指向 /usr/share/nginx/html/doc/test1
服務(wù)器地址;
test2.doc.sherlocked93.club
自動指向 /usr/share/nginx/html/doc/test2
服務(wù)器地址;
server { listen 80; server_name ~^([\w-]+)\.doc\.sherlocked93\.club$; root /usr/share/nginx/html/doc/$1;}復(fù)制代碼
和之前的功能類似,有時候我們希望把二級或者三級域名鏈接重寫到我們希望的路徑,讓后端就可以根據(jù)路由解析不同的規(guī)則:
test1.serv.sherlocked93.club/api?name=a
自動轉(zhuǎn)發(fā)到 127.0.0.1:8080/test1/api?name=a
;
test2.serv.sherlocked93.club/api?name=a
自動轉(zhuǎn)發(fā)到 127.0.0.1:8080/test2/api?name=a
;
server { listen 80; server_name ~^([\w-]+)\.serv\.sherlocked93\.club$; location / { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header X-NginX-Proxy true; proxy_pass http://127.0.0.1:8080/$1$request_uri; }}復(fù)制代碼
為了使 Nginx 配置更易于維護(hù),建議為每個服務(wù)創(chuàng)建一個單獨的配置文件,存儲在 /etc/nginx/conf.d
目錄,根據(jù)需求可以創(chuàng)建任意多個獨立的配置文件。
獨立的配置文件,建議遵循以下命名約定 <服務(wù)>.conf
,比如域名是 sherlocked93.club
,那么你的配置文件的應(yīng)該是這樣的 /etc/nginx/conf.d/sherlocked93.club.conf
,如果部署多個服務(wù),也可以在文件名中加上 Nginx 轉(zhuǎn)發(fā)的端口號,比如 sherlocked93.club.8080.conf
,如果是二級域名,建議也都加上 fe.sherlocked93.club.conf
。
常用的、復(fù)用頻率比較高的配置可以放到 /etc/nginx/snippets
文件夾,在 Nginx 的配置文件中需要用到的位置 include 進(jìn)去,以功能來命名,并在每個 snippet 配置文件的開頭注釋標(biāo)明主要功能和引入位置,方便管理。比如之前的 gzip
、cors
等常用配置,我都設(shè)置了 snippet。
Nginx 日志相關(guān)目錄,內(nèi)以 域名.type.log
命名(比如 be.sherlocked93.club.access.log
和 be.sherlocked93.club.error.log
)位于 /var/log/nginx/
目錄中,為每個獨立的服務(wù)配置不同的訪問權(quán)限和錯誤日志文件,這樣查找錯誤時,會更加方便快捷。