超實(shí)用的 Nginx 極簡(jiǎn)教程,覆蓋了常用場(chǎng)景
概述
什么是 Nginx?
Nginx (engine x) 是一款輕量級(jí)的 Web 服務(wù)器 、反向署理服務(wù)器及電子郵件(IMAP/POP3)署理服務(wù)器。
什么是反向署理?
反向署理(Reverse Proxy)方法是指以署理服務(wù)器來(lái)接受 internet 上的銜接懇求,然后將懇求轉(zhuǎn)發(fā)給內(nèi)部網(wǎng)絡(luò)上的服務(wù)器,并將從服務(wù)器上得到的結(jié)果返回給 internet 上懇求銜接的客戶端,此時(shí)署理服務(wù)器對(duì)外就表現(xiàn)為一個(gè)反向署理服務(wù)器。
裝置與運(yùn)用
裝置
具體裝置方法請(qǐng)參閱:Nginx 裝置
運(yùn)用
nginx 的運(yùn)用比較簡(jiǎn)單,便是幾條指令。
常用到的指令如下:
nginx -s stop 快速封閉Nginx,或許不保存相關(guān)信息,并敏捷終止web服務(wù)。 nginx -s quit 平穩(wěn)封閉Nginx,保存相關(guān)信息,有安排的結(jié)束web服務(wù)。 nginx -s reload 因改變了Nginx相關(guān)裝備,需求從頭加載裝備而重載。 nginx -s reopen 從頭打開日志文件。 nginx -c filename 為 Nginx 指定一個(gè)裝備文件,來(lái)代替缺省的。 nginx -t 不運(yùn)轉(zhuǎn),而只是測(cè)驗(yàn)裝備文件。nginx 將查看裝備文件的語(yǔ)法的正確性,并嘗試打開裝備文件中所引用到的文件。 nginx -v 顯現(xiàn) nginx 的版別。 nginx -V 顯現(xiàn) nginx 的版別,編譯器版別和裝備參數(shù)。
假設(shè)不想每次都敲指令,能夠在 nginx 裝置目錄下新添一個(gè)發(fā)動(dòng)批處理文件startup.bat ,雙擊即可運(yùn)轉(zhuǎn)。內(nèi)容如下:
@echo off rem 假設(shè)發(fā)動(dòng)前現(xiàn)已發(fā)動(dòng)nginx并記載下pid文件,會(huì)kill指定進(jìn)程 nginx.exe -s stop rem 測(cè)驗(yàn)裝備文件語(yǔ)法正確性 nginx.exe -t -c conf/nginx.conf rem 顯現(xiàn)版別信息 nginx.exe -v rem 按照指定裝備去發(fā)動(dòng)nginx nginx.exe -c conf/nginx.conf
假設(shè)是運(yùn)轉(zhuǎn)在 Linux 下,寫一個(gè) shell 腳本,迥然不同。
nginx 裝備實(shí)戰(zhàn)
我始終認(rèn)為,各種開發(fā)工具的裝備還是結(jié)合實(shí)戰(zhàn)來(lái)講述,會(huì)讓人更易了解。
http 反向署理裝備
我們先完成一個(gè)小方針:不考慮復(fù)雜的裝備,只是是完成一個(gè) http 反向署理。
nginx.conf 裝備文件如下:注:conf / nginx.conf 是 nginx 的默許裝備文件。你也能夠運(yùn)用 nginx -c 指定你的裝備文件
#運(yùn)轉(zhuǎn)用戶 #user somebody; #發(fā)動(dòng)進(jìn)程,一般設(shè)置成和cpu的數(shù)量相等 worker_processes 1; #全局錯(cuò)誤日志 error_log D:/Tools/nginx-1.10.1/logs/error.log; error_log D:/Tools/nginx-1.10.1/logs/notice.log notice; error_log D:/Tools/nginx-1.10.1/logs/info.log info; #PID文件,記載當(dāng)前發(fā)動(dòng)的nginx的進(jìn)程ID pid D:/Tools/nginx-1.10.1/logs/nginx.pid; #工作形式及銜接數(shù)上限 events { worker_connections 1024; #單個(gè)后臺(tái)worker process進(jìn)程的最大并發(fā)鏈接數(shù) } #設(shè)定http服務(wù)器,利用它的反向署理功用供給負(fù)載均衡支撐 http { #設(shè)定mime類型(郵件支撐類型),類型由mime.types文件界說 include D:/Tools/nginx-1.10.1/conf/mime.types; default_type application/octet-stream; #設(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 D:/Tools/nginx-1.10.1/logs/access.log main; rewrite_log on; #sendfile 指令指定 nginx 是否調(diào)用 sendfile 函數(shù)(zero copy 方法)來(lái)輸出文件,關(guān)于一般運(yùn)用, #有必要設(shè)為 on,假設(shè)用來(lái)進(jìn)行下載等運(yùn)用磁盤IO重負(fù)載運(yùn)用,可設(shè)置為 off,以平衡磁盤與網(wǎng)絡(luò)I/O處理速度,下降體系的uptime. sendfile on; #tcp_nopush on; #銜接超時(shí)時(shí)刻 keepalive_timeout 120; tcp_nodelay on; #gzip緊縮開關(guān) #gzip on; #設(shè)定實(shí)踐的服務(wù)器列表 upstream zp_server1{ server 127.0.0.1:8089; } #HTTP服務(wù)器 server { #監(jiān)聽80端口,80端口是聞名端口號(hào),用于HTTP協(xié)議 listen 80; #界說運(yùn)用www.xx.com拜訪 server_name www.helloworld.com; #主頁(yè) index index.html #指向webapp的目錄 root D:\01_Workspace\Project\github\zp\SpringNotes\spring-security\spring-shiro\src\main\webapp; #編碼格局 charset utf-8; #署理裝備參數(shù) proxy_connect_timeout 180; proxy_send_timeout 180; proxy_read_timeout 180; proxy_set_header Host $host; proxy_set_header X-Forwarder-For $remote_addr; #反向署理的途徑(和upstream綁定),location 后邊設(shè)置映射的途徑 location / { proxy_pass http://zp_server1; } #靜態(tài)文件,nginx自己處理 location ~ ^/(images|javascript|js|css|flash|media|static)/ { root D:\01_Workspace\Project\github\zp\SpringNotes\spring-security\spring-shiro\src\main\webapp\views; #過期30天,靜態(tài)文件不怎樣更新,過期能夠設(shè)大一點(diǎn),假設(shè)頻頻更新,則能夠設(shè)置得小一點(diǎn)。 expires 30d; } #設(shè)定查看Nginx狀態(tài)的地址 location /NginxStatus { stub_status on; access_log on; auth_basic "NginxStatus"; auth_basic_user_file conf/htpasswd; } #制止拜訪 .htxxx 文件 location ~ /\.ht { deny all; } #錯(cuò)誤處理頁(yè)面(可選擇性裝備) #error_page 404 /404.html; #error_page 500 502 503 504 /50x.html; #location = /50x.html { # root html; #} } }
好了,讓我們來(lái)試試吧:
- 發(fā)動(dòng) webapp,注意發(fā)動(dòng)綁定的端口要和 nginx 中的upstream設(shè)置的端口保持一致。
- 更改 host:在 C:\Windows\System32\drivers\etc 目錄下的 host 文件中增加一條 DNS 記載
127.0.0.1 www.helloworld.com
- 發(fā)動(dòng)前文中 startup.bat 的指令
- 在瀏覽器中拜訪 www.helloworld.com,不出意外,現(xiàn)已能夠拜訪了。
負(fù)載均衡裝備
上一個(gè)比如中,署理只是指向一個(gè)服務(wù)器。
可是,網(wǎng)站在實(shí)踐運(yùn)營(yíng)過程中,八成都是有多臺(tái)服務(wù)器運(yùn)轉(zhuǎn)著相同的 app,這時(shí)需求運(yùn)用負(fù)載均衡來(lái)分流。
nginx 也能夠完成簡(jiǎn)單的負(fù)載均衡功用。
假設(shè)這樣一個(gè)運(yùn)用場(chǎng)景:將運(yùn)用布置在 192.168.1.11:80、192.168.1.12:80、192.168.1.13:80 三臺(tái) linux 環(huán)境的服務(wù)器上。網(wǎng)站域名叫 www.helloworld.com,公網(wǎng) IP 為 192.168.1.11。在公網(wǎng) IP 所在的服務(wù)器上布置 nginx,對(duì)一切懇求做負(fù)載均衡處理。
nginx.conf 裝備如下:
http { #設(shè)定mime類型,類型由mime.type文件界說 include /etc/nginx/mime.types; default_type application/octet-stream; #設(shè)定日志格局 access_log /var/log/nginx/access.log; #設(shè)定負(fù)載均衡的服務(wù)器列表 upstream load_balance_server { #weigth參數(shù)表明權(quán)值,權(quán)值越高被分配到的幾率越大 server 192.168.1.11:80 weight=5; server 192.168.1.12:80 weight=1; server 192.168.1.13:80 weight=6; } #HTTP服務(wù)器 server { #偵聽80端口 listen 80; #界說運(yùn)用www.xx.com拜訪 server_name www.helloworld.com; #對(duì)一切懇求進(jìn)行負(fù)載均衡懇求 location / { root /root; #界說服務(wù)器的默許網(wǎng)站根目錄方位 index index.html index.htm; #界說主頁(yè)索引文件的稱號(hào) proxy_pass http://load_balance_server ;#懇求轉(zhuǎn)向load_balance_server 界說的服務(wù)器列表 #以下是一些反向署理的裝備(可選擇性裝備) #proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; #后端的Web服務(wù)器能夠通過X-Forwarded-For獲取用戶實(shí)在IP proxy_set_header X-Forwarded-For $remote_addr; proxy_connect_timeout 90; #nginx跟后端服務(wù)器銜接超時(shí)時(shí)刻(署理銜接超時(shí)) proxy_send_timeout 90; #后端服務(wù)器數(shù)據(jù)回傳時(shí)刻(署理發(fā)送超時(shí)) proxy_read_timeout 90; #銜接成功后,后端服務(wù)器呼應(yīng)時(shí)刻(署理接收超時(shí)) proxy_buffer_size 4k; #設(shè)置署理服務(wù)器(nginx)保存用戶頭信息的緩沖區(qū)巨細(xì) proxy_buffers 4 32k; #proxy_buffers緩沖區(qū),網(wǎng)頁(yè)平均在32k以下的話,這樣設(shè)置 proxy_busy_buffers_size 64k; #高負(fù)荷下緩沖巨細(xì)(proxy_buffers*2) proxy_temp_file_write_size 64k; #設(shè)定緩存文件夾巨細(xì),大于這個(gè)值,將從upstream服務(wù)器傳 client_max_body_size 10m; #允許客戶端懇求的最大單文件字節(jié)數(shù) client_body_buffer_size 128k; #緩沖區(qū)署理緩沖用戶端懇求的最大字節(jié)數(shù) } } }
網(wǎng)站有多個(gè) webapp 的裝備
當(dāng)一個(gè)網(wǎng)站功用越來(lái)越豐厚時(shí),往往需求將一些功用相對(duì)獨(dú)立的模塊剝離出來(lái),獨(dú)立維護(hù)。這樣的話,一般,會(huì)有多個(gè) webapp。
舉個(gè)比如:假設(shè) www.helloworld.com 站點(diǎn)有好幾個(gè) webapp,finance(金融)、product(產(chǎn)品)、admin(用戶中心)。拜訪這些運(yùn)用的方法通過上下文(context)來(lái)進(jìn)行區(qū)別:
www.helloworld.com/finance/
www.helloworld.com/product/
www.helloworld.com/admin/
我們知道,http 的默許端口號(hào)是 80,假設(shè)在一臺(tái)服務(wù)器上同時(shí)發(fā)動(dòng)這 3 個(gè) webapp 運(yùn)用,都用 80 端口,肯定是不成的。所以,這三個(gè)運(yùn)用需求分別綁定不同的端口號(hào)。
那么,問題來(lái)了,用戶在實(shí)踐拜訪 www.helloworld.com 站點(diǎn)時(shí),拜訪不同 webapp,總不會(huì)還帶著對(duì)應(yīng)的端口號(hào)去拜訪吧。所以,你再次需求用到反向署理來(lái)做處理。
裝備也不難,來(lái)看看怎樣做吧:
http { #此處省掉一些根本裝備 upstream product_server{ server www.helloworld.com:8081; } upstream admin_server{ server www.helloworld.com:8082; } upstream finance_server{ server www.helloworld.com:8083; } server { #此處省掉一些根本裝備 #默許指向product的server location / { proxy_pass http://product_server; } location /product/{ proxy_pass http://product_server; } location /admin/ { proxy_pass http://admin_server; } location /finance/ { proxy_pass http://finance_server; } } }
https 反向署理裝備
一些對(duì)安全性要求比較高的站點(diǎn),或許會(huì)運(yùn)用 HTTPS(一種運(yùn)用 ssl 通訊規(guī)范的安全 HTTP 協(xié)議)。
這里不科普 HTTP 協(xié)議和 SSL 規(guī)范??墒?,運(yùn)用 nginx 裝備 https 需求知道幾點(diǎn):
- HTTPS 的固定端口號(hào)是 443,不同于 HTTP 的 80 端口
- SSL 規(guī)范需求引進(jìn)安全證書,所以在 nginx.conf 中你需求指定證書和它對(duì)應(yīng)的 key
其他和 http 反向署理根本一樣,只是在Server部分裝備有些不同。
#HTTP服務(wù)器 server { #監(jiān)聽443端口。443為聞名端口號(hào),首要用于HTTPS協(xié)議 listen 443 ssl; #界說運(yùn)用www.xx.com拜訪 server_name www.helloworld.com; #ssl證書文件方位(常見證書文件格局為:crt/pem) ssl_certificate cert.pem; #ssl證書key方位 ssl_certificate_key cert.key; #ssl裝備參數(shù)(選擇性裝備) ssl_session_cache shared:SSL:1m; ssl_session_timeout 5m; #數(shù)字簽名,此處運(yùn)用MD5 ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; location / { root /root; index index.html index.htm; } }
靜態(tài)站點(diǎn)裝備
有時(shí)候,我們需求裝備靜態(tài)站點(diǎn)(即 html 文件和一堆靜態(tài)資源)。
舉例來(lái)說:假設(shè)一切的靜態(tài)資源都放在了/app/dist目錄下,我們只需求在nginx.conf中指定主頁(yè)以及這個(gè)站點(diǎn)的 host 即可。
裝備如下:
worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; gzip on; gzip_types text/plain application/x-javascript text/css application/xml text/javascript application/javascript image/jpeg image/gif image/png; gzip_vary on; server { listen 80; server_name static.zp.cn; location / { root /app/dist; index index.html; #轉(zhuǎn)發(fā)任何懇求到 index.html } } }
然后,增加 HOST:
127.0.0.1 static.zp.cn
此時(shí),在本地瀏覽器拜訪 static.zp.cn ,就能夠拜訪靜態(tài)站點(diǎn)了。
建立文件服務(wù)器
有時(shí)候,團(tuán)隊(duì)需求歸檔一些數(shù)據(jù)或資料,那么文件服務(wù)器必不可少。運(yùn)用 Nginx 能夠十分快速便捷的建立一個(gè)簡(jiǎn)易的文件服務(wù)。
Nginx 中的裝備關(guān)鍵:
- 將 autoindex 敞開能夠顯現(xiàn)目錄,默許不敞開。
- 將 autoindex_exact_size 敞開能夠顯現(xiàn)文件的巨細(xì)。
- 將 autoindex_localtime 敞開能夠顯現(xiàn)文件的修正時(shí)刻。
- root 用來(lái)設(shè)置開放為文件服務(wù)的根途徑。
- charset 設(shè)置為charset utf-8,gbk;,能夠避免中文亂碼問題(windows 服務(wù)器下設(shè)置后,仍然亂碼,自己暫時(shí)沒有找到處理方法)。
一個(gè)最簡(jiǎn)化的裝備如下:
autoindex on;# 顯現(xiàn)目錄 autoindex_exact_size on;# 顯現(xiàn)文件巨細(xì) autoindex_localtime on;# 顯現(xiàn)文件時(shí)刻 server { charset utf-8,gbk; # windows 服務(wù)器下設(shè)置后,仍然亂碼,暫時(shí)無(wú)解 listen 9050 default_server; listen [::]:9050 default_server; server_name _; root /share/fs; }
跨域處理方案
web 領(lǐng)域開發(fā)中,常常采用前后端別離形式。這種形式下,前端和后端分別是獨(dú)立的 web 運(yùn)用程序,例如:后端是 Java 程序,前端是 React 或 Vue 運(yùn)用。
各自獨(dú)立的 web app 在互相拜訪時(shí),勢(shì)必存在跨域問題。處理跨域問題一般有兩種思路:
- CORS
在后端服務(wù)器設(shè)置 HTTP 呼應(yīng)頭,把你需求運(yùn)轉(zhuǎn)拜訪的域名參加參加Access-Control-Allow-Origin中。
- jsonp
把后端依據(jù)懇求,結(jié)構(gòu) json 數(shù)據(jù),并返回,前端用 jsonp 跨域。
這兩種思路,本文不展開討論。
需求闡明的是,nginx 依據(jù)第一種思路,也供給了一種處理跨域的處理方案。
舉例:www.helloworld.com 網(wǎng)站是由一個(gè)前端 app ,一個(gè)后端 app 組成的。前端端口號(hào)為 9000, 后端端口號(hào)為 8080。
前端和后端假設(shè)運(yùn)用 http 進(jìn)行交互時(shí),懇求會(huì)被回絕,因?yàn)榇嬖诳缬騿栴}。來(lái)看看,nginx 是怎樣處理的吧:
首要,在 enable-cors.conf 文件中設(shè)置 cors :
# allow origin list set $ACAO '*'; # set single origin if ($http_origin ~* (www.helloworld.com)$) { set $ACAO $http_origin; } if ($cors = "trueget") { add_header 'Access-Control-Allow-Origin' "$http_origin"; add_header 'Access-Control-Allow-Credentials' 'true'; 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'; } if ($request_method = 'OPTIONS') { set $cors "${cors}options"; } if ($request_method = 'GET') { set $cors "${cors}get"; } if ($request_method = 'POST') { set $cors "${cors}post"; }
接下來(lái),在你的服務(wù)器中include enable-cors.conf來(lái)引進(jìn)跨域裝備:
# ---------------------------------------------------- # 此文件為項(xiàng)目 nginx 裝備片段 # 能夠直接在 nginx config 中 include(推薦) # 或者 copy 到現(xiàn)有 nginx 中,自行裝備 # www.helloworld.com 域名需配合 dns hosts 進(jìn)行裝備 # 其中,api 敞開了 cors,需配合本目錄下另一份裝備文件 # ---------------------------------------------------- upstream front_server{ server www.helloworld.com:9000; } upstream api_server{ server www.helloworld.com:8080; } server { listen 80; server_name www.helloworld.com; location ~ ^/api/ { include enable-cors.conf; proxy_pass http://api_server; rewrite "^/api/(.*)$" /$1 break; } location ~ ^/ { proxy_pass http://front_server; } }
到此,就完成了。