一、概述
代理(proxy),即中間人,它代替客戶端發送請求給服務器,收到響應后再轉給客戶端。通常意義上的代理是從用戶的角度講的,用戶通過某個代理可以訪問多個網站,這個代理是靠近用戶的,比如某些公司可能需要限制員工所訪問的網站,就會在網絡出口處放置一個代理來做過濾。
反向代理(reverse proxy),本質上跟代理是一回事,只不過是從服務器的角度講的,是靠近服務器的。比如某個網站有多個服務器,提供同樣的功能,一般會在網絡入口處放一個代理,接收客戶端的請求,再基於某種策略(比如輪轉)轉發給后端服務器,這樣可以提高整個系統的服務能力。nginx 就是一種常見的 HTTP 協議反向代理。
1.1、反向代理指令
nginx 中常見的反向代理指令有兩個:proxy_pass
和 fastcgi_pass
,前者使用標准的 HTTP 協議轉發,后者使用 FastCGI 協議轉發,用於 PHP 等架構的環境。在我要說的這個域名問題上,它們行為是一樣的,所以下面僅以 proxy_pass
為例。
一個最簡單的反向代理配置如下:
server { location / { proxy_pass https://github.com; } }
1.2、域名解析
其作用是將所有請求轉發到 github.com。注意此處寫的是域名,而非 IP。我們知道在真正發起請求前,是需要將域名解析成 IP 的,對於 github.com 來說,在我的環境上它會被解析成兩個 IP:192.30.253.112 和 192.30.253.113,TTL 都是 50s,如下圖:
那么使用上面這個配置,nginx 是什么時候做這件事情的呢?答案是啟動的時候,只做一次,解析結果會被緩存下來,也就是完全無視 TTL,后續所有的請求轉發,都是直接使用緩存下來的 IP,不會再做任何域名解析。對於 github.com 這種返回多個 IP 的情況,nginx 在轉發時會自動對 IP 列表進行輪轉。
可以使用 sudo tcpdump -n -i any port 53
抓包來驗證這個行為。注:53 是 DNS 服務的默認端口。
那么問題來了,IP 變了怎么辦?有什么辦法讓 nginx 自動重新解析域名嗎?
1.3、配置動態域名解析
resolver 8.8.8.8; server { location / { set $servers github.com; proxy_pass http://$servers; } }
如上,通過使用變量($servers
)的方式可以強制 nginx 遵守域名解析結果的 TTL,過期后自動重新解析。不過這種寫法有個副作用,如此配置后 nginx 不會自動使用系統 /etc/resolve.conf
的配置,此時必須使用 resolver
指令手動給它指定一個 DNS 服務器。
其中 8.8.8.8是谷歌的開源免費DNS,國內的有114.114.114.114.如果是內網域名,需要制定內網的DNS服務器。
參看地址:
https://github.com/inetfuture/blog/issues/4
https://www.nginx.com/blog/dns-service-discovery-nginx-plus/
二、反向代理
注意設置proxy_pass 后,同時需要設置proxy_set_header
proxy_set_header Host js.test.com; proxy_pass http://js.test.com/;
2.1、nginx location proxy_pass 后面的url 加與不加/的區別
在nginx中配置proxy_pass時,當在后面的url加上了/,相當於是絕對根路徑,則nginx不會把location中匹配的路徑部分代理走;如果沒有/,則會把匹配的路徑部分也給代理走。
在nginx中配置proxy_pass時,如果是按照^~匹配路徑時,要注意proxy_pass后的url最后的/,當加上了/,相當於是絕對根路徑,則nginx不會把location中匹配的路徑部分代理走;如果沒有/,則會把匹配的路徑部分也給代理走。
首先是location進行的是模糊匹配
1)沒有“/”時,location /abc/def可以匹配/abc/defghi請求,也可以匹配/abc/def/ghi等
2)而有“/”時,location /abc/def/不能匹配/abc/defghi請求,只能匹配/abc/def/anything這樣的請求
下面2種情況分別用http://192.168.1.1/proxy/test.html 進行訪問。
1、proxy_pass后有 / 絕對路徑 不帶走 location 路徑
location /proxy/ { proxy_pass http://127.0.0.1:81/; }
結論:會被代理到http://127.0.0.1:81/test.html 這個url
擴展1、
location /proxy/ { proxy_pass http://127.0.0.1:81/ftlynx/; }
結論:會被代理到http://127.0.0.1:81/ftlynx/test.html 這個url。
擴展2、
location /proxy/ { proxy_pass http://127.0.0.1:81/ftlynx; }
結論:會被代理到http://127.0.0.1:81/ftlynxtest.html 這個url
2、proxy_pass 后沒有 / ,帶走location路徑
location /proxy/ { proxy_pass http://127.0.0.1:81; }
結論:會被代理到http://127.0.0.1:81/proxy/test.html 這個url
3、可以通過的rewrite來實現/的功能