Nginx-基礎
1. 簡介
Nginx (engine x) 是一個高性能的HTTP和反向代理web服務器,同時也提供了IMAP/POP3/SMTP服務。
Nginx是一款輕量級的Web 服務器/反向代理服務器及電子郵件(IMAP/POP3)代理服務器,在BSD-like 協議下發行。其特點是占有內存少,并發能力強,事實上nginx的并發能力在同類型的網頁服務器中表現較好,中國大陸使用nginx網站用戶有:百度、京東、新浪、網易、騰訊、淘寶等。
1.1 正向代理
如圖所示:
當我們想訪問YouTube網站時,由于防火墻的原因,我們并不能直接訪問。此時我們就需要借助VPN,當我們訪問目標服務器時,通過VPN Client將我們的請求代理到VPN Server,VPN Server接收到請求后直接訪問目標地址,最后將訪問到的信息返回給用戶。
正向代理:“代理”的是客戶端。

1.2 反向代理
如圖所示:
反向代理,其實客戶端對代理是無感知的,因為客戶端不需要任何配置就可以訪問,我們只
需要將請求發送到反向代理服務器,由反向代理服務器去選擇目標服務器獲取數據后,在返
回給客戶端,此時反向代理服務器和目標服務器對外就是一個服務器,暴露的是代理服務器
地址,隱藏了真實服務器 IP 地址。
反向代理:“代理”的是服務端。

1.3 負載均衡
如圖所示:
客戶端發送多個請求到服務器,服務器處理請求,有一些可能要與數據庫進行交互,服務器處理完畢后,再將結果返回給客戶端。
這種架構模式對于早期的系統相對單一,并發請求相對較少的情況下是比較適合的,成本也低。但是隨著信息數量的不斷增長,訪問量和數據量的飛速增長,以及系統業務的復雜度增加,這種架構會造成服務器相應客戶端的請求日益緩慢,并發量特別大的時候,還容易造成服務器直接崩潰。很明顯這是由于服務器性能的瓶頸造成的問題,那么如何解決這種情況呢?
我們首先想到的可能是升級服務器的配置,比如提高 CPU 執行頻率,加大內存等提高機器的物理性能來解決此問題,但是我們知道摩爾定律的日益失效,硬件的性能提升已經不能滿足日益提升的需求了。最明顯的一個例子,天貓雙十一當天,某個熱銷商品的瞬時訪問量是極其龐大的,那么類似上面的系統架構,將機器都增加到現有的頂級物理配置,都是不能夠滿足需求的。那么怎么呢?
上面的分析我們去掉了增加服務器物理配置來解決問題的辦法,也就是說縱向解決問題的辦法行不通了,那么橫向增加服務器的數量呢?這時候集群的概念產生了,單個服務器解決不了,我們增加服務器的數量,然后將請求分發到各個服務器上,將原先請求集中到單個服務器上的情況改為將請求分發到多個服務器上,將負載分發到不同的服務器,也就是我們所說的負載均衡。

1.4 動靜分離
如圖所示:
我們將請求的資源分為靜態和動態資源,其中靜態資源指的就是前端資源(html、css、js、img等),我們將這些靜態的資源剝離出來,單獨部署到靜態資源文件服務器(直接通過nginx代理即可),而動態資源(接口請求的數據)通過nginx負載到后端的集群機器上。
這樣做可以把動態頁面和靜態頁面由不同的服務器來解析,加快解析速度。降低原來單個服務器的壓力。

2. 安裝
2.1 官方
我們可以參照官方安裝文檔實現基于下載源的方式安裝。
2.2 docker-compose
推薦使用docker-compose的方式安裝nginx
小插曲:
因為需要將容器中的配置文件掛載到宿主機中,然而當我們通過volumes掛載的時候,docker其自身的掛載機制是將宿主機中的文件掛載到容器中,所以會導致宿主機將容器中的配置文件給覆蓋掉了(丟失了),所以我們還有些前置的工作。
# 先啟動一個臨時的nginx容器
docker run --rm -d --name=tempnginx nginx
mkdir conf
# 然后將臨時容器中的配置文件拷貝到宿主機上
# 拷貝nginx.conf配置文件
docker cp tempnginx:/etc/nginx/nginx.conf ./conf/
# 拷貝conf.d文件夾
docker cp tempnginx:/etc/nginx/conf.d/ ./conf/
# 停止臨時容器
docker stop tempnginx
docker-compose.yaml配置信息如下
version: '3'
services:
nginx:
# 容器名稱
container_name: nginx
# 默認nginx:latest
image: nginx
# 自啟動
restart: always
# 宿主機端口80:容器默認端口80
ports:
- 80:80
# 文件映射
volumes:
- ./conf/nginx.conf:/etc/nginx/nginx.conf
- ./conf/conf.d/:/etc/nginx/conf.d/
- ./html/:/usr/share/nginx/html/
- ./logs/:/var/log/nginx/
# 時區設置
environment:
- TZ=Asia/Shanghai
3. 常用命令
進入nginx的sbin目錄中
./nginx -v:查看nginx版本號./nginx: 啟動nginx./nginx -s stop: 停止nginx./nginx -s quit: 優雅的停止服務./nginx -s reload:重新加載nginx(不是重啟)nginx -t <指定配置文件路徑>: 查看配置文件書寫是否正確
4. 配置文件
4.1 結構
-
全局塊:配置影響nginx全局的指令。一般有運行nginx服務器的用戶組,nginx進程pid存放路徑,日志存放路徑,配置文件引入,允許生成worker process數等。
-
events塊:配置影響nginx服務器或與用戶的網絡連接。有每個進程的最大連接數,選取哪種事件驅動模型處理連接請求,是否允許同時接受多個網路連接,開啟多個網絡連接序列化等。
-
http塊:可以嵌套多個server,配置代理,緩存,日志定義等絕大多數功能和第三方模塊的配置。如文件引入,mime-type定義,日志自定義,是否使用sendfile傳輸文件,連接超時時間,單連接請求數等。
-
server塊:配置虛擬主機的相關參數,一個http中可以有多個server。
-
location塊:配置請求的路由,以及各種頁面的處理情況,一個 server 塊可以配置多個 location 塊。
#全局塊
...
#events塊
events {...}
#http塊
http {
#http全局塊
...
#server塊
server {
#server全局塊
...
#location塊
location [PATTERN] {...}
location [PATTERN] {...}
}
server {...}
#http全局塊
...
}
4.2 配置信息
4.2.1 nginx.conf
/etc/nginx/nginx.conf
user nginx; # nginx 會使用這個指定的用戶啟動工作進程( worker process)
worker_processes 1; # 允許生成的worker process數,worker_processes 值越大,可以支持的并發處理量也越多,但是會受到硬件、軟件等設備的制約
error_log /var/log/nginx/error.log warn; # 錯誤日志存放路徑
pid /var/run/nginx.pid; # 進程PID存放路徑
events {
worker_connections 1024; # 每個worker process可以同時支持的最大連接數
}
http {
include /etc/nginx/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"'; # 日志格式
access_log /var/log/nginx/access.log main; # 訪問日志存儲路徑 并指定了日志格式為main
sendfile on; # 允許sendfile方式傳輸文件,可以在http塊,server塊,location塊
keepalive_timeout 65; # 連接超時時間
include /etc/nginx/conf.d/*.conf; # 引入/etc/nginx/conf.d/ 下的所有配置文件,使其生效
}
4.2.2 default.conf
/etc/nginx/conf.d/default.conf
server {
# 監聽所有的ipv4的地址 端口80
listen 80;
# 監聽所有的ipv6的地址 端口80
listen [::]:80;
# 本虛擬主機的名稱或 IP 配置
server_name localhost;
# 字符集
#charset koi8-r;
# 訪問日志地址及日志格式
#access_log /var/log/nginx/host.access.log main;
# 匹配所有請求
location / {
# 訪問的根目錄
root /usr/share/nginx/html;
# 訪問默認頁
index index.html index.htm;
}
# 重定向訪問系統404頁面至 /404.html;
#error_page 404 /404.html;
# 重定向系統錯誤頁面到指定的靜態頁面 /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
4.3 location 語法
該指令用于匹配URL
語法如下
location [ = | ~ | ~* | ^~] /uri/ {...}
- = : 用于不含正則表達式的 uri 前,要求請求字符串與 uri
嚴格匹配,如果匹配成功,就停止繼續向下搜索并立即處理該請求 - ~ : 用于表示 uri
包含正則表達式,并且區分大小寫 - ~* : 用于表示 uri
包含正則表達式,并且不區分大小寫 - !~ : 用于表示 uri
包含正則表達式, 并且區分大小寫不匹配 - !~* : 用于表示 uri
包含正則表達式,并且不區分大小寫不匹配 - ^~ : 用于
不含正則表達式的 uri 前,要求 Nginx 服務器找到標識 uri 和請求字符串匹配度最高的 location 后,立即使用此 location 處理請求,而不再使用 location 塊中的正則 uri 和請求字符串做匹配
注意: 如果 uri 包含正則表達式,則必須要有 ~ 或者 ~* 標識
5. 反向代理
實現效果: 用戶訪問nginx服務,通過nginx將請求代理到后臺服務中。
5.1 實例1
-
啟動一個后臺服務
student其端口為8080,項目啟動后直接在地址欄上訪問localhost:8080,返回I am student
-
修改本地
hosts文件,修改完成后,我們便可以通過www.ldx.com:8080訪問到第一步的初始化頁面。那么如何只需要輸入www.ldx.com便可以跳轉到第一步的初始界面呢?便用到 nginx的反向代理。# nginx test 127.0.0.1 www.ldx.com -
在
default.conf配置文件中增加如下配置監聽
80端口,訪問域名為www.ldx.com,訪問該域名時會被nginx代理到192.168.0.107:8080路徑上。server { listen 80; listen [::]:80; server_name www.ldx.com; location / { # 將真實的客戶端信息轉發到服務 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://192.168.0.107:8080; } } -
訪問結果

5.2 實例2
-
我們再起一個后臺服務
teacher,其端口為8081且上下文地址為teacher,啟動后直接在地址欄上訪問localhost:8081/teacher,返回I am teacher -
student服務添加上下文地址student,啟動后的訪問地址為localhost:8080/student
-
在
default.conf配置文件中增加如下配置server { listen 80; listen [::]:80; server_name www.ldx.com; location ^~ /student/ { # 將真實的客戶端信息轉發到服務 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://192.168.0.107:8080; } location ^~ /teacher/ { # 將真實的客戶端信息轉發到服務 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://192.168.0.107:8081; } } -
訪問結果

6. 負載均衡
? 實現效果:用戶通過nginx訪問student集群服務,通過負載策略將請求分發到不同的服務上。
6.1 實例
-
通過idea設計器實現copy兩個啟動類的配置,并且將端口設置為動態傳入,通過啟動配置的環境變量傳入
8081 和 8083兩個端口,實現student服務的偽集群進行測試。
-
修改
default.conf配置文件通過添加
upstream模塊實現負載功能。upstream stu-server { server 192.168.0.107:8081; server 192.168.0.107:8083; } server { listen 80; listen [::]:80; server_name www.ldx.com; location ^~ /student/ { # 將真實的客戶端信息轉發到服務 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://stu-server; } } -
訪問結果

6.2 負載策略
1. Round Robin (default)
輪詢 - 請求在服務器之間平均分配,同時考慮了服務器權重。默認情況下使用此方法(沒有啟用它的指令)
upstream backend {
server backend1.example.com;
server backend2.example.com;
}
2. Least Connections
最少連接 - 將請求發送到具有最少活動連接數的服務器,同時還要考慮服務器權重:
upstream backend {
least_conn;
server backend1.example.com;
server backend2.example.com;
}
3. IP Hash
IP哈希 -從客戶端IP地址確定向其發送請求的服務器。在這種情況下,可以使用IPv4地址的前三個八位字節或整個IPv6地址來計算哈希值。該方法保證了來自相同地址的請求將到達同一服務器,除非該請求不可用。
upstream backend {
ip_hash;
server backend1.example.com;
server backend2.example.com;
}
如果其中一臺服務器需要暫時從負載平衡循環中刪除,則可以使用down參數對其進行標記,以保留客戶端IP地址的當前哈希值。該服務器要處理的請求將自動發送到組中的下一個服務器:
upstream backend {
server backend1.example.com;
server backend2.example.com;
server backend3.example.com down;
}
4. Generic Hash(plugin)
通用哈希 –將請求發送到的服務器是根據用戶定義的鍵確定的,該鍵可以是文本字符串,變量或組合。例如,密鑰可以是成對的源IP地址和端口,或者是本示例中的URI:
upstream backend {
hash $request_uri consistent;
server backend1.example.com;
server backend2.example.com;
}
指令的可選consistent參數hash啟用ketama一致性哈希負載平衡。根據用戶定義的哈希鍵值,請求在所有上游服務器上平均分配。如果將上游服務器添加到上游組中或從上游組中刪除,則只有少數幾個鍵會被重新映射,從而在負載平衡緩存服務器或其他累積狀態的應用程序的情況下最大程度地減少緩存丟失。
5. Fair(plugin)
按后端服務器的響應時間來分配請求,響應時間短的優先分配。
upstream backend {
fair;
server backend1.example.com;
server backend2.example.com;
}
6. weight
默認情況下,NGINX使用Round Robin方法根據請求的權重在組中的服務器之間分配請求。weight參數設置服務器的權重;默認值為1。
upstream backend {
server backend1.example.com weight=5;
server backend2.example.com;
server 192.0.0.1 backup;
}
在示例中,backend1.example.com具有weight 5;其他兩臺服務器的默認權重(1),但具有IP地址的192.0.0.1一臺backup服務器被標記為備份服務器,除非其他兩臺服務器均不可用,否則不會接收請求。權重的這種配置,每6個請求,5個發送到backend1.example.com和1個backend2.example.com。
7. 動靜分離
? Nginx 動靜分離簡單來說就是把動態跟靜態請求分開,不能理解成只是單純的把動態頁面和靜態頁面物理分離。嚴格意義上說應該是動態請求跟靜態請求分開,可以理解成使用 Nginx(ngxin 本身就是個http服務器,可以直接使用nginx部署靜態頁面)處理靜態頁面,Tomcat 處理動態頁面。動靜分離從目前實現角度來講大致分為兩種:
1. 一種是純粹把靜態文件獨立成單獨的域名,放在獨立的服務器上,也是目前主流推崇的方案;
2. 另外一種方法就是動態跟靜態文件混合在一起發布,通過 nginx 來分開。通過 location 指定不同的后綴名實現不同的請求轉發。通過 expires 參數設置,可以使瀏覽器緩存過期時間,減少與服務器之前的請求和流量。具體 Expires 定義:是給一個資源設定一個過期時間,也就是說無需去服務端驗證,直接通過瀏覽器自身確認是否過期即可,所以不會產生額外的流量。此種方法非常適合不經常變動的資源。(如果經常更新的文件,不建議使用Expires 來緩存),我這里設置 3d,表示在這 3 天之內訪問這個 URL,發送一個請求,比對服務器該文件最后更新時間沒有變化,則不會從服務器抓取,返回狀態碼304,如果有修改,則直接從服務器重新下載,返回狀態碼 200。
7.1 部署靜態資源
7.1.1 root
-
準備靜態資源,放入
/usr/share/nginx/html/用于訪問。當前測試的靜態資源是在
gitee上找的純前端項目:項目地址 -
在
default.conf配置文件中增加如下配置用戶直接訪問
/就會匹配到當前location,并直接訪問/usr/share/nginx/html/hotel/目錄下的文件,默認訪問index.html頁面。- 訪問
www.ldx.com實際請求地址就為www.ldx.com/index.html,路徑為/usr/share/nginx/html/hotel/index.html - 訪問
www.ldx.com/discount.html,訪問路徑為/usr/share/nginx/html/hotel/discount.html
server { listen 80; listen [::]:80; server_name www.ldx.com; location / { root /usr/share/nginx/html/hotel/; index index.html; } } - 訪問
-
訪問結果

7.1.2 alias
如果想給請求地址添加個上下文標識,可以使用alias(起個別名)
-
在
default.conf配置文件中增加如下配置server { listen 80; listen [::]:80; server_name www.ldx.com; location /ldx-hotel { alias /usr/share/nginx/html/hotel/; index index.html; } } -
訪問結果

-
但此時使用
root方式就不行了,因為root方式會將location地址的匹配字符串拼接到訪問目錄地址中。錯誤日志如下訪問的真實路徑變成了
/usr/share/nginx/html/hotel/ldx-hotel/index.html,將訪問標識拼接上去了
2021/08/05 14:39:20 [error] 23#23: *2 "/usr/share/nginx/html/hotel/ldx-hotel/index.html" is not found (2: No such file or directory), client: 172.24.0.1, server: www.ldx.com, request: "GET /ldx-hotel/ HTTP/1.1", host: "localhost" 2021/08/05 14:39:34 [error] 23#23: *2 open() "/usr/share/nginx/html/hotel/ldx-hotel/discount.html" failed (2: No such file or directory), client: 172.24.0.1, server: www.ldx.com, request: "GET /ldx-hotel/discount.html HTTP/1.1", host: "localhost"
7.1.3 小節
root : 會將location表達式中的訪問標識拼接到真實請求的路徑中
alias : 可以自定義訪問標識,其標識不會拼接到真實的請求路徑中
7.2 靜態資源索引
可以使用nginx搭建一個靜態資源索引系統,可以用來查看附件索引并且可以使用其下載附件。
-
準備資源文件
在
/usr/share/nginx/html/目錄中添加如下文件├── ldx │ └── 大帥比.txt ├── word.docx ├── 圖片.jpg ├── 測試md.md └── 測試文件.txt 1 directory, 5 files -
在
default.conf配置文件中增加如下配置server { listen 80; listen [::]:80; server_name www.ldx.com; location /file { # 防止文件名中文亂碼 charset utf-8,gbk; # 顯示目錄 autoindex on; # 顯示文件大小 autoindex_exact_size off; # 顯示文件時間 autoindex_localtime off; # 設置文件格式,防止瀏覽器直接打開文件(直接下載文件) if ($request_filename ~* ^.*?\.(txt|doc|pdf|rar|gz|zip|docx|exe|xlsx|ppt|pptx|crx)$){ add_header Content-Disposition attachment; } root /usr/share/nginx/html/; } } -
訪問結果

點擊下載
/ldx/大帥比.txt文件
8. 處理跨域請求
當出現403跨域錯誤的時候 No 'Access-Control-Allow-Origin' header is present on the requested resource,需要給Nginx服務器配置響應的header參數:
location / {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE, PATCH, 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';
if ($request_method = 'OPTIONS') {
return 204;
}
}
Access-Control-Allow-Origin
服務器默認是不被允許跨域的。給Nginx服務器配置`Access-Control-Allow-Origin *`后,表示服務器可以接受所有的請求源(Origin),即接受所有跨域的請求。
Access-Control-Allow-Headers 是為了防止出現以下錯誤:
Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response.
這個錯誤表示當前請求Content-Type的值不被支持。其實是我們發起了"application/json"的類型請求導致的。這里涉及到一個概念:預檢請求(preflight request),請看下面"預檢請求"的介紹。
Access-Control-Allow-Methods 是為了防止出現以下錯誤:
Content-Type is not allowed by Access-Control-Allow-Headers in preflight response.
給
OPTIONS添加204的返回,是為了處理在發送POST請求時Nginx依然拒絕訪問的錯誤
發送"預檢請求"時,需要用到方法
OPTIONS,所以服務器需要允許該方法。
9. 配置 https
9.1 搞到ssl證書
注意: 如果你的證書是pfx格式的,需要將pfx格式的證書解析成pem格式,建議使用linux環境解析,本人試了windows環境解析后的文件一直有問題,強烈介意使用linux解析
linux環境本身就有openssl工具
-
將pfx證書上傳到linux環境
-
執行此命令
openssl pkcs12 -in your.pfx -nodes -out your.pem -
輸入pfx密碼,得到pem文件
-
打開pem文件,內容中包含(取出多余的信息,只保留標簽內的信息)
-----BEGIN PRIVATE KEY----- ... -----END PRIVATE KEY----- -----BEGIN CERTIFICATE----- ... -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- ... -----END CERTIFICATE----- -
將
PRIVATE KEY內容取出放入到test.key文件 -
處理后的文件長這樣

9.2 配置nginx
-
在nginx目錄下創建cert文件夾并將證書文件放進去
-
修改nginx配置文件
以下ssl配置都是基于nginx server的(都是配置在server標簽內的),當然也可以配置到http中(http標簽內,server標簽外),配置到不同的位置,作用域不同
-
添加ssl證書信息
ssl_certificate ../cert/test3.pem; ssl_certificate_key ../cert/test.key; -
限制對文件的訪問,僅使用SSL / TLS的強版本和密碼(保護證書)
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # 從1.9.1版開始,NGINX使用以下默認值 ssl_ciphers HIGH:!aNULL:!MD5; -
https 服務器優化
SSL操作會消耗額外的CPU資源。最耗CPU的操作是SSL握手。有兩種方法可以最大程度地減少每個客戶端執行這些操作的次數:
- 啟用保持連接以通過一個連接發送多個請求
- 重用SSL會話參數以避免并行和后續連接的SSL握手
會話存儲在工作進程之間共享的SSL會話緩存中,并由
ssl_session_cache偽指令配置。一兆字節的緩存包含大約4000個會話。默認的緩存超時為5分鐘。可以使用ssl_session_timeout指令增加此超時。以下是針對具有10 MB共享會話緩存的多核系統進行優化的示例配置:ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; -
配置同時支持兩種協議(http/https)
listen 80; listen 443 ssl;
-
-
拿來主義
upstream test_name{ ip_hash; server 192.168.3.66:8888; server 192.168.3.66:8080; } server { # listen 80; listen 443 ssl; # 避免中文亂碼 charset utf-8; server_name ludangxin.club; ssl_certificate ../cert/test3.pem; ssl_certificate_key ../cert/test.key; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers HIGH:!aNULL:!MD5; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; location / { proxy_pass http://test_name; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } -
雖然可以配置成兩種協議都支持,但是大多數情況下希望用戶訪問
http 80端口的時候被轉發到https 443server { listen 80; server_name ludangxin.club; rewrite ^/(.*)$ https://ludangxin.club:443/$1 permanent; }

浙公網安備 33010602011771號