代理與反向代理
假設網絡上有三台機器:
- X:你的電腦
- Y:代理服務器
- Z:網站
通常,你會直接訪問需要的網絡資源,此時路徑是由你的電腦直接到網站 X->Z。
代理(Proxy)
但某些情況下,X 並不能直接訪問到 Z。原因可能是兩方面的,
- X 所在的網絡將 Z 進行了屏蔽封鎖,比如公司內網禁用一些娛樂性質的網站,防止員工工作時間娛樂。
- Z 將 X 進行了屏蔽。比如 Z 發現來自 X 的請求異常,懷疑是惡意攻擊,所以將 X 的 IP 封掉。
此時 Y 在中間可充當 X 的代理,將 X 的請求轉發到 Z,拿到內容后再返回給 X。此時路徑為 X->Y->Z。
也就是說,代理是 X 端主動配置和發起的,X 明確知道 Y 並不是返回內容的服務器。
反向代理 (Reverse Proxy)
某些情況下,Z 不想讓 X 直接訪問,所以配置一個 Y 在前面充當代理提供服務。
此時,作為用戶訪問的是 Y,並不知道 Z 才是真正提供服務的機器,用戶被代理了,相比前面,所以這里是 反向代理。
反向代理下,Z 在后台對外不公開只內網可訪問,而作為反向代理的 Y 對外公開可通過公網訪問。
反向代理的場景:
- 比如 Z 是個大型網站,請求量巨大,單台機器是無法滿足所有請求的,所以同樣的網站內容部署在了多台機器上。然后配置一台反向代理的機器,將請求再就近轉發到某台機器。比如 CDN。
- 負載均衡。將請求平均分配到各機器,以至於不會讓某些機器過載,同時將掛掉的機器其請求轉發到還在正常運行的機器上。
NGINX 中反向代理的配置
請求轉發
通過 proxy_pass
可將請求直接轉發。
location /some/path/ {
proxy_pass http://www.example.com/link/;
}
目標地址中的 path 部分會替換掉 location
參數中對應位置中的 path。比如這里 /some/path/page.html
會被轉發到 http://www.example.com/link/page.html
。
其中目標地址可以是 IP,或帶端口,
location ~ \.php {
proxy_pass http://127.0.0.1:8000;
}
除了轉發到 HTTP 服務器,還支持其他類型協議的轉發,相應的指令為:
fastcgi_pass
轉發到 FastCGI 服務器uwsgi_pass
轉發到 uwsgi 服務器scgi_pass
轉發到 SCGI 服務memcached_pass
轉到到 memcached 服務器
請求頭的轉發
默認情況下 NGINX 為代理的請求設置上了兩個請求頭,Host
設置成 $proxy_host
變量的值,Connection
設置為 close
。其他值為空的請求頭會去掉。通過 proxy_set_header
指令可修改代理時的請求頭。
location /some/path/ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://localhost:8000;
}
代理時如果想禁止某個頭部的傳遞,直接將其設置為空即可,
location /some/path/ {
proxy_set_header Accept-Encoding "";
proxy_pass http://localhost:8000;
}
Buffer 的設置
作為代理,在拿到完整響應前將結果暫存在內部的 buffer 數據中,拿到完整響應后再將結果返回到客戶端。這種將響應暫存的方式可提高代理的效率,而同步的方式會浪費代理服務器的資源。
默認 buffer 模式為開啟狀態,可通過 proxy_buffering
進行開關。
proxy_buffers
控制單個請求為其分配的 buffer 大小和數量。
location /some/path/ {
proxy_buffers 16 4k;
proxy_buffer_size 2k;
proxy_pass http://localhost:8000;
}
關閉某些 location 下的 buffer 設置:
location /some/path/ {
proxy_buffering off;
proxy_pass http://localhost:8000;
}
出口地址
通過 proxy_bind
指令可配置代理服務器的出口地址,然后配置內部機器只接收來自該出口地址的請求。
location /app1/ {
proxy_bind 127.0.0.1;
proxy_pass http://example.com/app1/;
}
location /app2/ {
proxy_bind 127.0.0.2;
proxy_pass http://example.com/app2/;
}
IP 地址也可指定為變量,比如 $server_addr
為接收請求機器的 IP。
location /app3/ {
proxy_bind $server_addr;
proxy_pass http://example.com/app3/;
}