淺談Nginx之反向代理

林花鹿發表於2019-03-02

Nginx是一個非同步框架的 Web伺服器,也可以用作反向代理,負載平衡器 和 HTTP快取,今天我們就來聊聊反向代理。

什麼是反向代理?

反向代理(Reverse Proxy)方式是指以代理伺服器來接受internet上的連線請求,然後將請求轉發給內部網路上的伺服器,並將從伺服器上得到的結果返回給internet上請求連線的客戶端,此時代理伺服器對外就表現為一個反向代理伺服器。

我們換個方式理解,就是當外部網路對內部網路器是不能直接訪問的,要通過一個代理伺服器才能進行訪問,而外部網路看到的只是代理伺服器,反饋也是由代理伺服器返回的,外部網路對於代理伺服器與內部網路直接的具體情況是不可見的。

正向代理和反向代理什麼區別?

正向代理是一個位於客戶端和原始伺服器(origin server)之間的伺服器,為了從原始伺服器取得內容,客戶端向代理髮送一個請求並指定目標(原始伺服器),然後代理向原始伺服器轉交請求並將獲得的內容返回給客戶端。客戶端才能使用正向代理。

這裡有一個最顯著的區別是:(可以看下面的圖示來感受)

  • 正向代理是客戶端知道目的伺服器在哪裡,然後通過代理伺服器去訪問客戶端不能直接訪問的目標伺服器,而目標伺服器並不知道客戶端通過什麼來訪問的, 即 正向代理代理的是客戶端
  • 反向代理中,外部網路對於內部網路具體的情況是不可見的,而代理伺服器來代理內部網路來返回所要的資料(當然靜態檔案可以放在Nginx,這個靜動分離再說),而服務端知道請求的來源以及資料 反向代理代理的是服務端
    Nginx正反向代理圖示

反向代理的好處

  1. 保護了真實的web伺服器,web伺服器對外不可見,外網只能看到反向代理伺服器,而反向代理伺服器上並沒有真實資料,因此,保證了web伺服器的資源安全。
  2. 反向代理為基礎產生了動靜資源分離以及負載均衡的方式,減輕web伺服器的負擔,加速了對網站訪問速度(動靜資源分離和負載均衡會以後說)
  3. 節約了有限的IP地址資源,企業內所有的網站共享一個在internet中註冊的IP地址,這些伺服器分配私有地址,採用虛擬主機的方式對外提供服務;

反向代理在Nginx.conf的簡單配置

server {
        listen       8182;
        server_name  localhost;
        ...
        location / {
	    proxy_pass http://localhost:8082;  
	    ...
        }
        
    }
複製程式碼

server塊可以理解為一個虛擬主機,此時我們如果呼叫的是http://localhost:8182時,會將這個請求轉發到http://localhost:8082,因此實際處理這個請求的是http://localhost:8082

使用Nginx後web伺服器如何獲得真實的使用者IP

問題:

當使用Nginx後,web伺服器中request.getRemoteAddr(),得到的是Nginx的ip,而不是真實使用者的ip

解決方案:

在nginx.conf的的中的location中新增一些賦值操作

server {
        ...
        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;
        }
        
    }
複製程式碼

然後web服務端就可以可以通過request.getHeader("X-Forwarded-For");來獲得真實的使用者ip

知識點介紹:

  • proxy_set_header X-real-ip $remote_addr;
    這裡的X-real-ip是一個自定義名,名字隨意,效果是可以將 ip 就被放在 X-real-ip 這個變數裡了,可以通過request.getHeader("X-real-ip ")獲取當前的值,與X-Forwarded-For,下文會進行解釋
  • proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

首先我們要知道什麼是X-Forwarded-For?

X-Forwarded-For:簡稱XFF頭,它代表客戶端,也就是HTTP的請求端真實的IP,只有在通過了HTTP 代理或者負載均衡伺服器時才會新增該項。用於識別通過HTTP代理或負載平衡器原始IP一個連線到Web伺服器的客戶機地址的非rfc標準,

當Nginx有進行X-Forwarded-For設定的話,每次經過proxy轉發都會有記錄,格式就是client1, proxy1,proxy2,以逗號隔開各個地址,而且由於他是非rfc標準,所以預設是沒有的,需要強制新增,通過Proxy轉達的時候,後端伺服器看到的遠端ip是Proxy的ip,也就是說如果直接使用request.getHeader("X-Forwarded-For")是獲取不到使用者ip的,那我們要如何設定獲得使用者ip呢?

此時就需要在nginx配置的location塊中新增

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for
複製程式碼

注意這裡的意思是增加到X-Forwarded-For中,不是覆蓋,而增加後的格式就是之前說的“client1,proxy1....”,預設的時候X-Forwarded-For是空的,如果有兩個nginx,並且都配置了上面這個命令,則會在web伺服器的request.getHeader("X-Forwarded-For")獲得的是“使用者ip,第一個nginx的ip”,分別對應之前的格式。

proxy_add_forwarded_for包含著兩個格式,前面一部分是請求頭的X-Forwarded-For,而後面$remote_addr,也就是說是遠端使用者的ip

我們來個圖淺顯的解釋下:

反向代理X-Forwarded_For圖解

X-real-ip與X-Forwarded-For的區別

  • X-real-ip是覆蓋,而X-Forwarded-For是後面新增

    舉個例子,請求由1.1.1.1發出,經過三層代理,第一層是2.2.2.2,第二層是3.3.3.3,而本次請求的來源IP4.4.4.4是第三層代理,

    而X-Real-IP,沒有相關標準,上面的例子,如果配置了X-Read-IP,可能會有兩種情況

    最後一跳是正向代理,可能會保留真實客戶端IP:X-Real-IP: 1.1.1.1// 最後一跳是反向代理,比如Nginx,一般會是與之直接連線的客戶端IP:X-Real-IP: 3.3.3.3
    複製程式碼

    而X-Forwarded-For的結果則是

    X-Forwarded-For:1.1.1.1, 2.2.2.2, 3.3.3.3
    複製程式碼

    所以如果只有一層代理,則兩個值是一樣的

參考資料

相關文章