反向代理

2023-09-03 21:01:20

反向代理

反向代理:reverse proxy,指的是代理外網使用者的請求到內部的指定的伺服器,並將資料返回給使用者的一種方式,這是用的比較多的一種方式。

ngx_http_proxy_module: #將使用者端的請求以http協定轉發至指定伺服器進行處理
ngx_http_upstream_module #用於定義為proxy_pass,fastcgi_pass,uwsgi_pass等指令參照的後端伺服器分組
ngx_stream_proxy_module:#將使用者端的請求以tcp協定轉發至指定伺服器處理
ngx_http_fastcgi_module:#將使用者端對php的請求以fastcgi協定轉發至指定伺服器助理
ngx_http_uwsgi_module: #將使用者端對Python的請求以uwsgi協定轉發至指定伺服器處理

image-20230901171623300

1.1 http 協定反向代理

1. 反向代理設定引數

#官方檔案:https://nginx.org/en/docs/http/ngx_http_proxy_module.html

proxy_pass; 
#用來設定將使用者端請求轉發給的後端伺服器的主機,可以是主機名(將轉發至後端服務做為主機頭首部)、IP
地址:埠的方式
#也可以代理到預先設定的主機群組,需要模組ngx_http_upstream_module支援
​

proxy_pass 後跟斜槓與不跟斜槓的區別

#範例:

#不帶斜槓相當於追加
10.0.0.8/web
 location /web {
   index index.html;
   proxy_pass http://10.0.0.18:8080; #8080後面無uri,即無 / 符號,需要將location後面url 附加到proxy_pass指定的url後面,此行為類似於root
#proxy_pass指定的uri不帶斜線將存取的/web,等於存取後端伺服器
http://10.0.0.18:8080/web/index.html,即後端伺服器設定的站點根目錄要有web目錄才可以被存取
    # http://nginx/web/index.html ==> http://10.0.0.18:8080/web/index.html

 

//有/相當於置換
​
proxy_pass http://10.0.0.18:8080/;   #8080後面有uri,即有 / 符號,相當於置換,即存取/web時實際返回proxy_pass後面uri內容.此行為類似於alias 
    #proxy_pass指定的uri帶斜線,等於存取後端伺服器的http://10.0.0.18:8080/index.html 內容返回給使用者端
 }  # http://nginx/web/index.html ==> http://10.0.0.18:8080

隱藏後端伺服器相應頭部的資訊

#用於nginx作為反向代理的時候,在返回給使用者端http響應時,隱藏後端伺服器相應頭部的資訊,可以設定在http,server或location塊

#範例: 隱藏後端伺服器ETag首部欄位

 location /web {
   index index.html;
   proxy_pass http://10.0.0.18:8080/; 
   proxy_hide_header ETag;
 }
​
proxy_pass_header field;
#預設nginx在響應報文中不傳遞後端伺服器的首部欄位Date, Server, X-Pad, X-Accel等引數,如果
要傳遞的話則要使用 proxy_pass_header field宣告將後端伺服器返回的值傳遞給使用者端
#field 首部欄位大小不敏感
#範例:透傳後端伺服器的Server和Date首部給使用者端,同時不再響應報中顯示前端伺服器的Server欄位
proxy_pass_header Server;
proxy_pass_header Date;
proxy_pass_request_body on | off; 
#是否向後端伺服器傳送HTTP實體部分,可以設定在http,server或location塊,預設即為開啟
proxy_pass_request_headers on | off; 
#是否將使用者端的請求頭部轉發給後端伺服器,可以設定在http,server或location塊,預設即為開啟

1.2 實戰案例: 反向代理單臺web 伺服器

實現單臺反向代理

實驗前關閉防火牆
systemctl stop firewalld.service
 setenforce 0
​

設定7-1 代理伺服器

vim /apps/nginx/conf.d/pc.conf
server{
        listen   80;
        server_name https://www.cnblogs.com/sl08/p/www.pc.com;
        root /data/nginx/pc;
     location / {
        proxy_pass http://192.168.1.200;//如果存取根就將請求轉發到位於192.168.1.200的伺服器上,通過http協定通訊
    }
}
nginx -s reload 重新載入組態檔

設定7-2 真實伺服器

yum  install   httpd  -y  //安裝http服務
​
cd  /var/www/html //進入http預設網頁目錄
​
echo   "real  server 200"  > index.html  //在預設網頁目錄寫如檔案用於測試
​
systemctl   stop nginx   //關閉nginx服務防止埠號衝突nginx和http都預設用80埠,如果nginx服務已關閉可以不執行此操作
​
systemctl   start httpd 開啟http服務

設定7-3 客戶機

vim  /etc/hosts//進入本地hosts檔案
192.168.1.100  https://www.cnblogs.com/sl08/p/www.pc.com//指明伺服器位置

測試

在客戶機

[root@localhost ~]# curl 192.168.1.100
real server 200

image-20230902133955816

#真實伺服器
建立大檔案檢視連線情況
dd if=/dev/zero   of=test.img    count=1  bs=1G
​
​
找臺伺服器存取
curl https://www.cnblogs.com/sl08/p/www.pc.com
wget --limit-rate=1024 https://www.cnblogs.com/sl08/p/www.pc.com/test.img
​
#真實伺服器
ss -natp | grep ":80" //檢視有哪些在使用80埠

image-20230902143922658

image-20230902144048450

修改埠號 真實伺服器 httpd 伺服器修改埠號

找到httpd服務主組態檔
我的在
vim /etc/httpd/conf/httpd.conf
如果不知道在哪可以使用
 rpm -ql httpd | egrep 'httpd\.conf'
 #\為轉意符
找到Listen 指令並將後面的埠號改為想要的埠號如8080
systemctl restart httpd 重啟服務

image-20230902151612962

修該代理伺服器

 vim /apps/nginx/conf.d/pc.conf //進入組態檔
 
server{
        listen   80;
        server_name https://www.cnblogs.com/sl08/p/www.pc.com;
        root /data/nginx/pc;
     location / {
        proxy_pass http://192.168.1.200:8080;
    }
}
nginx -s reload 重新載入組態檔
設定好後用戶端在存取的時候就會被轉到對應埠如果這邊不修改埠預設轉發80埠
就會報錯502

image-20230902151658162

客戶機存取測試

curl 192.168.1.100
#注意我們存取的是代理伺服器所以還是80埠所以在存取時不用指定埠
由代理伺服器幫我們存取真實伺服器所以代理伺服器要指明埠號8080

image-20230902152140121

 

#還可以在代理伺服器上做一些防火牆操作
在代理伺服器上 做防火牆規則
iptables -A INPUT  -s 192.168.1.100 -j DROP
使用者端再次存取  會出現504閘道器超時(有可能只是處理時間久,伺服器不一定掛了),時間較長1分鐘,沒有定義代理超時時間

iptables -A INPUT  -s 192.168.1.100 -j REJECT
使用者端再次存取  會出現502,一般出現502 代表後端真實伺服器掛了

針對某個uri 進行存取

要求:將使用者對域 https://www.cnblogs.com/sl08/p/www.pc.com的請求轉發給後端伺服器處理

[root@centos8 ~]# cat /apps/nginx/conf.d/pc.conf
server {
 listen 80;
 server_name https://www.cnblogs.com/sl08/p/www.pc.com;
 location ~* /api {
     proxy_pass http://192.168.1.200;
 }
}

~*無視api大小寫
#在後端伺服器下建立檔案
vim /var/www/html/api/index.html
 cat  /var/www/html/api/index.html
api
api
api
api
api

#重啟Nginx 並存取測試

 存取https://www.cnblogs.com/sl08/p/www.pc.com  後端伺服器


如果後端伺服器無法連線((比如:iptables -AINPUT -s nginx_ip -j REJECT或者systemctl stop httpd)), 會出

瀏覽器測試

image-20230902165519873

image-20230902165622511

1.3 實戰案例:指定location 實現反向代理 動靜分離

server{
        listen 80;
        server_name  https://www.cnblogs.com/sl08/p/www.pc.com;
        root    /data/nginx/pc;
     location  / {
        root  /data/nginx/pc;
}
     location  /api {
        root  /data/nginx/pc;
        proxy_pass http://192.168.1.200:8080;//存取動態轉到192.168.1.200
​
        }
     location ~* \.(jpg|jpeg|png|gif|bmp)$ {
        root  /data/nginx/pc;
        proxy_pass http://192.168.1.150;//存取靜態內容轉到192.168.1.150
        }
​
}

image-20230902182258185

1.4反向代理範例:快取功能

關閉後端伺服器後,圖片無法存取

快取功能預設關閉,需要開啟

proxy_cache zone_name | off; 預設off
#指明呼叫的快取,或關閉快取機制;可用在Context:http, server, location
#zone_name 表示快取的名稱.需要由proxy_cache_path事先定義
​
proxy_cache_key string;
#快取中用於「鍵」的內容,預設值:proxy_cache_key $scheme$proxy_host$request_uri;
​
​
​
proxy_cache_valid [code ...] time;
#定義對特定響應碼的響應內容的快取時長,定義在http{...}中
 範例:
 proxy_cache_valid 200 302 10m;//狀態碼為200 302 快取10m中
 proxy_cache_valid 404 1m;狀態碼為404快取1m
proxy_cache_path;
#定義可用於proxy功能的快取;Context:http   必須放在http語句中
proxy_cache_path path [levels=levels] [use_temp_path=on|off] 
keys_zone=zone_name:size [inactive=time] [max_size=size] [manager_files=number] 
[manager_sleep=time] [manager_threshold=time] [loader_files=number] 
[loader_sleep=time] [loader_threshold=time] [purger=on|off] 
[purger_files=number] [purger_sleep=time] [purger_threshold=time];
#範例:在http設定定義快取資訊
   proxy_cache_path /var/cache/nginx/proxy_cache #定義快取儲存路徑,proxy_cache會自動建立
   levels=1:2:2 #定義快取目錄結構層次,1:2:2可以生成2^4x2^8x2^8=2^20=1048576個目錄
   keys_zone=proxycache:20m #指記憶體中快取的大小,主要用於存放key和metadata(如:使用次數),一般1M可存放8000個左右的key
   inactive=120s  #快取有效時間  
   max_size=10g; #最大磁碟佔用空間,磁碟存入檔案內容的快取空間最大值
#呼叫快取功能,需要定義在相應的設定段,如server{...};或者location等
proxy_cache proxycache;
proxy_cache_key $request_uri; #對指定的資料進行MD5的運算做為快取的key
proxy_cache_valid 200 302 301 10m; #指定的狀態碼返回的資料快取多長時間
proxy_cache_valid any 1m;   #除指定的狀態碼返回的資料以外的快取多長時間,必須設定,否則不會快取
proxy_cache_use_stale error | timeout | invalid_header | updating | http_500 | http_502 | http_503 | http_504 | http_403 | http_404 | off ; #預設是off
#在被代理的後端伺服器出現哪種情況下,可直接使用過期的快取響應使用者端
​
#範例
proxy_cache_use_stale error http_502 http_503;
​
​
proxy_cache_methods GET | HEAD | POST ...;
#對哪些使用者端請求方法對應的響應進行快取,GET和HEAD方法總是被快取

擴充套件知識:清除快取

方法1: rm -rf 快取目錄
方法2: 第三方擴充套件模組ngx_cache_purge

實現快取實際操作

在未開啟快取前可以測試下載速度
ab -c100 -n1000 http://https://www.cnblogs.com/sl08/p/www.pc.com/3m.jpg
去代理伺服器上 新增操作
先去   主組態檔 的 http模組 中加入下方設定
proxy_cache_path /data/nginx/proyxcache //定義快取路徑會自動建立  levels=1:1:1//目錄比 keys_zone=proxycache:20m//指定記憶體快取大小 inactive=120s//快取有效時間 max_size=1g最大磁碟佔用空間,磁碟存入檔案內容的快取空間最大值


proxy_cache_path /data/nginx/proyxcache   levels=1:1:1 keys_zone=proxycache:20m inactive=120s max_size=1g;

image-20230903142603432

#再去 子組態檔中新增
vim /apps/nginx/conf.d/pc.conf
server{
        listen 80;
        server_name  https://www.cnblogs.com/sl08/p/www.pc.com;
        proxy_cache proxycache;
        proxy_cache_key $request_uri;
或者放這個 #proxy_cache_key $host$uri$is_args$args;
        proxy_cache_valid 200 302 301 10m;
        proxy_cache_valid any 5m;
        root    /data/nginx/html/pc;
     location  / {
        root  /data/nginx/html/pc;
}
     location  /api {
        root  /data/nginx/html/pc;
        proxy_pass http://192.168.1.200;
        }
}
#設定真實伺服器
cd /var/www/html/api
[root@localhost api]# ls //這裡我放了一張名為2.jpg的圖片
2.jpg  index.html

測試

瀏覽器存取

image-20230903143819639

來到代理伺服器,進入快取目錄檢視,快取情況

image-20230903144502866

斷開真實伺服器檢視快取是否生效

systemctl stop httpd.service//停止httpd服務
systemctl status httpd.service//檢視httpd服務狀態
​

image-20230903144718666

用瀏覽器存取

image-20230903144757005

等待快取時間超時在存取就看不到圖片了

image-20230903145251982

image-20230903145159674

1.5** 實現反向代理使用者端 IP 透傳

image-20230903152909097

為什麼要實現IP穿透

使用者端在存取資源的時候,經過代理伺服器轉發,真實伺服器紀錄檔沒法顯示使用者端IP,不便於排錯

實現IP穿透

在使用者端存取資源的時候會經過代理伺服器轉發到真實伺服器,真實在伺服器會記錄使用者端存取資源所經過代理伺服器ip

 

範例

實現上圖的IP穿透

代理伺服器

#開啟第一臺代理伺服器紀錄檔
進入主組態檔
 vim /apps/nginx/conf/nginx.conf
 //將#去掉
   #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  logs/access.log  main;
​

image-20230903172510093

進入虛擬主機組態檔
 vim /apps/nginx/conf.d/pc.conf
#新增使用者端IP和反向代理伺服器IP到請求報文頭部
 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 #如果用proxy_set_header X-Real-IP $remote_addr;          #只新增使用者端IP到請求報文頭部,轉發至後端伺服器如果是多臺代理會覆蓋之前的ip資訊
​

image-20230903172829027

設定真實伺服器紀錄檔
#進入主組態檔
vim /etc/httpd/conf/httpd.conf
新增
\"%{X-Forwarded-For}i\"    //這個與代理伺服器的對應

image-20230903174529813

設定第二帶代理伺服器

#開啟紀錄檔服務
 vim /apps/nginx/conf/nginx.conf
​
 //將#去掉
   #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  logs/access.log  main;

image-20230903181738228

因為我第二臺代理伺服器沒有虛擬主機所以

#講第一臺代理伺服器的pc.conf檔案複製到101的 /apps/nginx/下
scp /apps/nginx/conf.d/pc.conf 192.168.1.101:/apps/nginx/
//101伺服器檢視是否複製成功
[root@localhost nginx]# ls
 pc.conf #有pc檔案複製成功
[root@localhost nginx]# mkdir conf.d
[root@localhost nginx]# mv pc.conf conf.d/
vim /apps/nginx/conf.d/pc.conf//修改伺服器指向
vim /apps/nginx/conf/nginx//新增位置指向

image-20230903192215556

image-20230903192313785

測試

image-20230903193000098

瀏覽器存取

image-20230903193055288

檢查紀錄檔

第一臺代理服務紀錄檔

image-20230903193559902

第二臺代理服務紀錄檔

image-20230903193735148

真實伺服器

image-20230903193851977

1.6 http反向代理負載均衡

在上一個節中Nginx可以將使用者端的請求轉發至單臺後端伺服器但是無法轉發至特定的一組的伺服器,而且不能對後端伺服器提供相應的伺服器狀態監測,Nginx 可以基於ngx_http_upstream_module模組提供伺服器分組轉發、權重分配、狀態監測、排程演演算法等高階功能

#自定義一組伺服器,設定在http塊內
//定義一組名為wed的伺服器
upstream   web { 
 server 192.168.1.100    後可跟排程演演算法
 server 192.168.1.101
}
​
location  / {
pass_proxy  http://web/
}
server address [parameters];
#設定一個後端web伺服器,設定在upstream內,至少要有一個server伺服器設定。
#server支援的parameters如下:
weight=number #設定權重,預設為1,實現類似於LVS中的WRR,WLC等
max_conns=number  #給當前後端server設定最大活動連結數,預設為0表示沒有限制
max_fails=number  #後端伺服器的下線條件,當用戶端存取時,對本次排程選中的後端伺服器連續進行檢測多少次,如果都失敗就標記為不可用,預設為1次,當用戶端存取時,才會利用TCP觸發對探測後端伺服器健康性檢查,而非週期性的探測
fail_timeout=time #後端伺服器的上線條件,對已經檢測到處於不可用的後端伺服器,每隔此時間間隔再次進行檢測是否恢復可用,如果發現可用,則將後端伺服器參與排程,預設為10秒
backup  #設定為備份伺服器,當所有後端伺服器不可用時,才會啟用此備用伺服器 sorry server   自己不能轉自己
down    #標記為down狀態
resolve #當server定義的是主機名的時候,當A記錄發生變化會自動應用新IP而不用重啟Nginx
#範例
upstream backend {
   server backend1.example.com weight=5;     權重
   server 127.0.0.1:8080       max_fails=3  fail_timeout=30s;
   server unix:/tmp/backend3;
   server backup1.example.com backup;
}

Nginx 負載均衡設定及對談保持

排程演演算法
​
hash KEY [consistent];
#基於指定請求報文中首部欄位或者URI等key做hash計算,使consistent引數,將使用ketama一致性
​
ip_hash;
#源地址hash排程方法,基於的使用者端的remote_addr(源地址IPv4的前24位元或整個IPv6地址)做hash計算,以實現對談保持
least_conn;
#最少連線排程演演算法,優先將使用者端請求排程到當前連線最少的後端伺服器,相當於LVS中的WLC
url_hash;
按存取url的hash結果來分配請求,使每個url定向到同一個後端伺服器。一旦快取住了資源,再次收到請求,就可以從快取中讀取。
輪詢;
每個請求會按時間順序逐一分配到不同的後端伺服器
weight;
權重方式,在輪詢策略的基礎上指定輪詢的比例。
fair;
此種演演算法可以依據頁面大小和載入時間長短智慧地進行負載均衡,也就是根據後端伺服器的響應時間來分配請求,響應時間短的優先分配。

實際操作

這裡不好看實際效果就舉例了

http {
 upstream web {
  server 192.168.1.101:80;
  server 192.168.1.103:80;
}
........
}
​
[root@localhost nginx]#vim conf.d/test.conf 
​
server {
     listen 80;
     server_name https://www.cnblogs.com/sl08/p/www.pc.com;
     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
     root /data/nginx/pc;
     location /  {
     root /data/nginx/pc;
     proxy_pass http://web;           
}
​
}
​