本篇文章給大家?guī)砹岁P(guān)于Nginx的相關(guān)知識,其中主要跟大家介紹前端Nginx怎么配置,以及HTTPS安全原理,感興趣的朋友下面一起來看一下吧,希望對大家有幫助。
對于一個前端開發(fā),雖然服務(wù)器開發(fā)部署不是主要業(yè)務(wù),但是,獨立開發(fā)前端項目總歸是掛載在服務(wù)器上才能跑起來的,不能總指望運維來做這個工作。而且,作為一個程序員,不可能對項目部署一點都不了解。
本文就講一下作為一個前端開發(fā)應(yīng)該要掌握的基本的 nginx 服務(wù).
關(guān)于 nginx 與 CI 配合的使用,見我的文章:juejin.cn/post/718351…
概念
- 正向代理
特點:用戶主動去聯(lián)系分發(fā)設(shè)備,分發(fā)設(shè)備來判斷分發(fā)的目標(biāo)服務(wù)器。此時,用戶對于服務(wù)器未知。
路由器是正向代理的一個例子,與用戶在一側(cè),有最大帶寬限制。
- 反向代理
反向代理一般是部署在服務(wù)側(cè)的,靈活很多,可以做負(fù)載分流和擴(kuò)展功能等。但是對于用戶而言,反向代理服務(wù)器就相當(dāng)于目標(biāo)服務(wù)器,即用戶直接訪問反向代理服務(wù)器就可以獲得目標(biāo)服務(wù)器的資源。此時,服務(wù)器對于用戶未知,提高了安全性。
nginx 便是高性能的 HTTP 和反向代理 web 服務(wù)器
一個nginx的使用例子就是虛擬主機(jī):多個域名綁定一個主機(jī),由 nginx 轉(zhuǎn)發(fā)不同的資源。
安裝與部署前端應(yīng)用
- 平臺:CentOS7 虛擬機(jī)
- 安裝版本:目前最新 1.21.6
- 下載地址:nginx 官網(wǎng)
安裝包解壓后進(jìn)入目錄
安裝依賴
yum install -y gcc yum install -y pcre-devel yum install -y zlib zlib-devel
開始安裝 (安裝目錄/usr/local/nginx)
./configure --prefix=/usr/local/nginx make make install
安裝成功,查看安裝目錄
測試運行
執(zhí)行 ./sbin/nginx
(也可以使用全局 nginx 命令)
可以看到進(jìn)程已經(jīng)啟動
ps -ef | grep nginx
為了測試,先關(guān)閉防火墻:
systemctl stop firewalld.service
正式線上使用的,可以配置防火墻放行端口。
配置 nginx 配置文件:
vim ./conf/nginx.conf
其中 location 根目錄位置是已經(jīng) build 好的一個 vue 應(yīng)用:
重啟
nginx -s reload
瀏覽器查看 (使用 ip addr 指令可以查看ip)
上述在之前的文章中也有所提及,相面更深入的講一下配置文件的使用
配置文件最小集
配置文件最小集是一個能夠支撐 nginx 正常跑起來的最小的配置項集合,連注釋一并寫在下面,供大家參考:
// ./conf/nginx.conf worker_process 1; // 并行執(zhí)行的任務(wù)數(shù),一般按照CPU內(nèi)核配置 events: { worker_connections 1024; // 配置單個worker進(jìn)程最大的連接數(shù),nginx 默認(rèn)連接數(shù)是1024 } http { // 支持 http 協(xié)議訪問的服務(wù) include mime.types; // 當(dāng)前目錄下的配置的文件類型文件,使用默認(rèn)即可。圖片音頻會自動解析給瀏覽器,不能解析的一律按照二進(jìn)制流下載 default_type application/octet-stream; // 默認(rèn)文件類型 二進(jìn)制流下載 sendfile on; // 是否允許目標(biāo)服務(wù)器繞過 nginx 服務(wù)器直接返回結(jié)果給用戶 keepalive_timeout 65; // 超時時間 server { // 隸屬于 http 的一個 服務(wù)器 listen 10087; // 端口 server_name localhost; // 服務(wù)部署的ip地址,可以是域名 charset utf-8; location / { // 配置 uri root /root/web/dist; // 自定義的資源目錄,可以是絕對目錄;若前邊不加 /, 則表示相對目錄,相對的是 nginx 主目錄 index index.html index.htm; } error_page 404 404.html; // 404頁面配置,相對路由 error_page 500 502 503 504 50x.html; // 同上 location = /50x.html { root html; // 50x 時,資源指向 html目錄下尋找 } location = /404.html { root html; // 同上 } } // end server } // end http
多站點配置
假設(shè)我們有兩個資源目錄,你可以理解為兩個項目的 build 目錄:
/root/web/vue/dist /root/web/react/dist
我們通過配置文件來控制不同的訪問 url 分別分發(fā)給這兩個資源。
server { listen 80; server_name www.vue.com; location / { root /root/web/vue/dist; index index.html index.htm; } } server { listen 8080; server_name www.react.com; location / { root /root/web/react/dist; index index.html index.htm; } }
這樣,訪問 www.vue.com 就會進(jìn)入 vue 的項目,訪問 www.react.com:8080 會進(jìn)入 react 的項目。
注意:https 的域名需要在云端配置 ip 綁定為 nginx 的服務(wù)器。
server_name 匹配
server_name 支持模糊匹配和通配符匹配。
- 通配符: .xxx.com 、www.baidu.
所有 .xxx.com 結(jié)尾的都可以匹配到
- 完全匹配:www.react.com
- 正則匹配:~^[0-9]+.xxx.com$ (規(guī)則:~開頭)
匹配優(yōu)先級:
- 完全匹配
- 通配符在前的
- 通配符在后的
- 正則匹配
如果都不匹配
- 優(yōu)先選擇listen配置項后有 default 或 default_server 的
- 上述都不滿足,則去找端口配置的位置最靠前的server
負(fù)載均衡配置
使用場景:訪問同一個域名,但是目標(biāo)地址可以是多個,根據(jù)使用情況和空閑程度自動分配一個使用。upstream 用于設(shè)置多臺分發(fā)主機(jī)的集合。
http { ... upstream my_server { server 10.123.345.456:8000; server 10.123.345.457:8000; } server { location / { proxy_pass http://my_server; } }}
這樣配置后,實際訪問 http://192.168.122.1 訪問時,系統(tǒng)會在 456 和 457 兩個 ip服務(wù)選擇一個分發(fā),雨露均沾。
當(dāng)然你也可以配置兩個服務(wù)器的輪詢權(quán)重(訪問概率)。
server 10.123.345.456:8000 weight=8; server 10.123.345.457:8000 weight=1; server 10.123.345.457:8000 backup; // 標(biāo)識備用機(jī),實在是沒有可用的機(jī)器時啟用復(fù)制代碼
如果想要某一個服務(wù)器不參與負(fù)載均衡,可以如下配置:
server 10.123.345.456:8000 down;復(fù)制代碼
配置動靜分離
適合小中型網(wǎng)站,靜態(tài)資源不太多的場景。原理是用戶請求頁面時,提取出靜態(tài)資源,等下次用戶訪問相同頁面時,靜態(tài)資源可以不用再次找服務(wù)器獲取,而是取緩存的內(nèi)容。
配置如下:
http { ... upstream my_server { server 10.123.345.456:8000; server 10.123.345.457:8000; } server { location / { proxy_pass http://my_server; } location ~.*.(js|png|jpg|svg|css)$ { // 靜態(tài)資源 root html; index index.html index.htm; } }}
配置 URLRewrite
用于隱藏服務(wù)器真實url路徑。
http { ... upstream my_server { server 10.123.345.456:8000; server 10.123.345.457:8000; } server { location / { rewrite ^/([0-9]+).html$ /index/pageNum=$1 break; proxy_pass http://my_server; } } }
上邊就使用了一個 rewrite 來配置了轉(zhuǎn)發(fā)。
這個例子隱藏了頁面的分頁信息:訪問 /2.html 就相當(dāng)于訪問了 /index/pageNum=2 路徑。
匹配關(guān)鍵字:
- break:停止所有rewrite匹配
- last:本條匹配完成后,繼續(xù)向后匹配其他的 location 的 rewrite
- redirect:返回 302 重定向到真實地址,而不是用假地址
- permanent:301 永久重定向到真實地址 (適用于爬蟲)
配置防盜鏈
盜鏈(Hotlinking)是指在一個網(wǎng)站上,使用別人網(wǎng)站上的圖片或其他媒體資源來裝飾自己的網(wǎng)站,而不獲得該資源的所有者許可的行為。盜鏈可以導(dǎo)致被盜用者的帶寬和流量受到消耗,甚至可能使其網(wǎng)站速度變慢或崩潰。
防盜鏈也是資源節(jié)省優(yōu)化的必備配置。nginx 中根據(jù) http 請求頭的 referer 判斷來源可以做到攔截。
一個配置防盜鏈的例子如下:
location ~* .(jpg|jpeg|png|gif)$ { valid_referers none blocked xxx.com; if ($invalid_referer) { return 403; }}
以上代碼表示,如果訪問的圖片URL的referer
不是 xxx.com,則返回 403 禁止訪問。如果訪問的URL沒有referer,則也會被禁止訪問。
配置項介紹:
- none:referer不存在時可以訪問,不設(shè)置則所有訪問不是 xxx.com 都禁止
- blocked:referer值被防火墻或者代理服務(wù)器刪除或偽裝時可以訪問。一般是不帶 http 前綴的訪問放行配置。
接下來配置錯誤提示頁面:
假設(shè)有個頁面 : 403.html
, 需要配置禁止訪問時顯示:
error_page 403 /403.html location = /403.html { root html; // 資源指向 html目錄下尋找}
或者在 return 403 時設(shè)置:rewrite
到一個配置好的資源也可以。
安全高可用方案配置
安全高可用的意義:在不額外添加機(jī)器的情況下做到不down機(jī)動態(tài)切換機(jī)器,從而達(dá)到服務(wù)持續(xù)可用
keepalived
安裝
yum install keepalived
編輯配置(/etc/keepalived.conf):
global_defs { router_id lb111}vrrp_instance_test { // 自定義 test 實例 state MASTER // 主 interface eth01 // 你機(jī)器上網(wǎng)卡的名字 virtual_router_id 33 // 虛擬路由id,主從要一樣 priority 100 // 優(yōu)先級高的機(jī)器就為 master advert_int 1 // 間隔檢測時間 authentication { // 認(rèn)證配置,同一組保持一致即可 auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.44.1 // 本臺機(jī)器的虛擬地址 }}
上面是第一臺機(jī)器的配置,在第二臺虛擬機(jī)上也配置一下類似的配置,設(shè)置:
global_defs { router_id lb110 // 修改路由號}vrrp_instance_test { // 同一個實例 state BACKUP // 從 interface eth01 virtual_router_id 33 priority 50 // 減低優(yōu)先級 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.44.1 // 本臺機(jī)器的虛擬地址 }}
兩臺機(jī)器分別啟動一下:
systemctl start keepalived
此時在外網(wǎng)可以ping通的ip是: 192.168.44.1。
我們讓 MASTER 機(jī)器關(guān)機(jī)后,再ping一下 192.168.44.1,發(fā)現(xiàn)仍然可以,此時在備份及使用指令 ip addr
查看,可以看到 有一個 192.168.44.1 的虛擬ip。這說明高可用生效了,這種配置叫 ip漂移。
上述情況只能保證 keepalived 進(jìn)程掛掉時起作用,更高級的用法是跑一個腳本,檢測本機(jī)的 nginz 服務(wù)進(jìn)程,如果服務(wù)異常,則 kill 掉本機(jī)的 keepalived 進(jìn)程。
https 與 TLS
http 協(xié)議往往是不安全的,即使有防火墻,但是沒辦法防御消息在傳輸過程中被劫持:
此時就需要對傳輸過程的消息進(jìn)行加密。加密方式有對稱加密和非對稱加密。
對稱加密的加密和解密互為逆過程,規(guī)則是固定的,存放在服務(wù)器端或者客戶端,這個加密算法傳輸過程中也容易被獲取,所以并不是太安全。
- 非對稱加密
非對稱加密會設(shè)置一個公鑰,用于傳遞;服務(wù)端和客戶端分別設(shè)置一個私鑰,自己保存,加密步驟如下:
- 用戶通過服務(wù)器443端口下載公鑰,并傳遞自己的公鑰給服務(wù)器。
- 再次請求服務(wù)器,用服務(wù)公鑰+對稱加密算法來加密明文,生成密文
- 傳遞密文給服務(wù)器
- 服務(wù)端用服務(wù)私鑰+加密算法解開密文,得到明文
- 類似的,服務(wù)端根據(jù)明文請求和用戶傳遞的用戶公鑰進(jìn)行響應(yīng):用戶公鑰+算法的密文
- 用戶用用戶私鑰+算法解密獲取數(shù)據(jù)
其中需注意,公鑰加密的數(shù)據(jù)公鑰自己是解不開的,而且要保證都是公鑰加密,私鑰解密。
但是,如果服務(wù)器被偽造了,公鑰是壞人給的,那你的數(shù)據(jù)加密再好也沒用了,這就是中間人攻擊。
- TLS
為了解決中間人攻擊,需要對使用者進(jìn)行身份認(rèn)證,這就引入了數(shù)字證書。常見的方式是找一個第三方公認(rèn)的好人(CA)來頒發(fā)這個證書來認(rèn)證公鑰。
服務(wù)器會申請公鑰給CA來獲取證書,CA判斷你是否有所認(rèn)證機(jī)構(gòu)的管理權(quán)限和擁有權(quán)限,通過后頒發(fā)數(shù)字證書(CA自己的私鑰+加密算法);服務(wù)器拿到證書后,給用戶傳遞的就是這個證書了,用戶用CA公鑰解密出服務(wù)器公鑰來使用。
此時,中間人獲取不到CA的私鑰,所以用戶端瀏覽器就不認(rèn)這個中間人,以此達(dá)到鑒偽。用戶只要使用的是正版操作系統(tǒng)和正規(guī)瀏覽器,就能保證數(shù)字證書的獲取。這期間使用了 TLS 算法生成了兩組隨機(jī)數(shù),通過非對稱加密,客戶端和服務(wù)端達(dá)成一致,生成了一個只有他們自己知道的對稱加密規(guī)則,我這里借用b站 技術(shù)蛋老師的解釋圖:
上圖的步驟如下:
- 服務(wù)器生成一套私鑰和公鑰
- 可以短生成一個隨機(jī)數(shù)1,并傳給服務(wù)端,請求公鑰
- 服務(wù)端生成隨機(jī)數(shù)2,帶上公鑰、證書一起給客戶端
- 現(xiàn)在客戶端、服務(wù)端、黑客都知道了公鑰、隨機(jī)數(shù)1和隨機(jī)數(shù)2
- 客戶端生成隨機(jī)數(shù)3,結(jié)合公鑰加密后給服務(wù)端,服務(wù)端通過私鑰解密后得到明文
- 客戶端和服務(wù)端各自通過 隨機(jī)數(shù)1/2/3生成一個會話秘鑰,這個會話秘鑰就是對稱加密的秘鑰,且不在網(wǎng)絡(luò)上傳遞。
- 接下來就是對稱加通信環(huán)節(jié),而黑客目前只知道公鑰、隨機(jī)數(shù)1和隨機(jī)數(shù)2,無法破解通信。
這里講一下 nginx 如何配置 https。你需要有一個服務(wù)的公網(wǎng)ip(假設(shè) 123.456.789.111)和購買的域名(假設(shè) www.abc.com )并申請好了域名解析和數(shù)字證書(.key 和 .pem 文件):
server { listen 443 ssl; server_name localhost; // 域名已經(jīng)和ip綁定,寫 localhost也是能解析的 ssl_certificate xxxx.pem; ssl_certificate_key xxxx.key; underscores_in_headers on; // 允許請求頭出現(xiàn)下劃線 root html;}
變量的使用
跟其他技術(shù)的配置文件一樣,nginx 也能使用變量:
location / { set $name "zhangsan"; return 200 "$name"; }
上面就設(shè)置了一個變量叫 name,并且直接返回 200 的請求,在頁面上顯示 name 的值。其格式是:
set $變量名 變量值
當(dāng)然了,nginx 也自帶了一些變量,可以直接使用,比如:
$request
完整的原始的請求行,例如:GET /nginx/index?a=1&b=2 HTTP/1.1$request_uri
完整的原始請求URI,訪問的URL除去域名(或IP)和 port, 如: /nginx/index?a=1&b=2$args
請求行中的全部參數(shù) 例如:a=1&b=2$remote_addr
客戶端ip地址$remote_port
客戶端端口
…
nginx 配置文件的變量可以統(tǒng)一設(shè)置在文件的頂部,這樣在整個文件中都可以使用同一個變量:
set $my_var "hello";
引申:變量值的計算
location / { set $my_var 10; add_header X-Test $my_var; // 成功響應(yīng)時,添加響應(yīng)頭 add_header X-Total $my_var*2; }
上面的例子就是變量簡單的數(shù)值計算。
業(yè)務(wù)場景案例
案例一
- 項目介紹:前端微服務(wù)項目
- 需求:各個子服務(wù)的部署,需要根據(jù)灰度系統(tǒng)傳遞過來的靜態(tài)資源目錄地址來動態(tài)切換轉(zhuǎn)發(fā)地址
- 業(yè)務(wù)介紹:這是我參與的一個前端業(yè)務(wù)場景,訪問微服務(wù)子應(yīng)用時,微服務(wù)啟動器會調(diào)用灰度系統(tǒng)接口獲取當(dāng)前登錄用戶的產(chǎn)品權(quán)限列表,并返回給前端打包好的前端頁面靜態(tài)資源地址。這個地址會根據(jù)用戶權(quán)限和灰度策略變化。
現(xiàn)在有上面一個工作,需要配置nginx來完成動態(tài)轉(zhuǎn)發(fā)的工作,讓用戶看到不同版本的前端項目。
解析
可以使用一個變量來標(biāo)識資源地址,在前端服務(wù)build的CI中修改這個配置文件,更改變量值。
一個示例:
set $uri "/root/web/vue/dist"; server { listen 80; server_name www.test.com; location / { root $uri; index index.html index.htm; }}
在 CI 中修改配置文件:set $uri "/root/web/react/dist",重啟 nginx 后即可。
大家有更好的辦法的話,可以在評論區(qū)討論哦
案例二
- 使用場景:在前端項目部署新版本后,用戶沒辦法感知刷新,在不強制刷新的前提下,看到的仍然是舊版本。
- 需求:需要設(shè)置服務(wù)器配置,在前后端版本不一致時強制刷新
解析
這個問題有多種解決方式。
可以配置 nginx,高速瀏覽器不要緩存:
location / { add_header Cache-Control "no-cache, must-revalidate"}
或者配置強制瀏覽器緩存,常用的辦法是添加hash或者版本號來讓瀏覽器重新下載資源:
<link rel="stylesheet" href="/css/main.css?version=v2"