Nginx配置二級目錄/路徑 映射不同的反向代理和規避IP+端口訪問
當配置Nginx來映射不同的服務器 可以通過二級路徑來反向代理 來解決一個外網端口實現多個服務訪問。
配置如下:
server { listen 80; server_name demo.domain.com; #通過訪問service二級目錄來訪問後臺 location /service/ { #DemoBackend1後面的斜杠是一個關鍵,沒有斜杠的話就會傳遞service到後端節點導致404 proxy_pass http://backend1/; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } #其他路徑默認訪問前臺網站 location / { proxy_pass http://backend2; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } #簡單的負載均衡節點配置 upstream backend1 { server 192.168.1.1; server 192.168.1.2; ip_hash; } upstream backend2 { server 192.168.2.1; server 192.168.2.2; ip_hash; }
對於規避IP+端口訪問,可能粗略一看,還沒理解是個啥意思吧!
其實就是現在業界流行的一種防DNS汙染的解決方案之一:
做法很簡單,就是在APP中集成多個IP和端口作為備用的訪問途徑。
當開發GG找到我,提出的需求是:
需要實現公網IP+端口來訪問,比如郵件API使用 http://192.168.1.10:125
Ps:公網服務器是多線的,那麽就有多個IP,本文假設電信是192.168.1.10,聯通是192.168.2.10,移動是192.168.3.10等
說白了就是要用端口來區分不同的API,此時如果我不深究,順手可能會寫出如下配置:
Shell#API1 server { listen 125; server_name 192.168.1.10 192.168.2.10 192.168.3.10; location / { proxy_pass http://DemoBackend; proxy_redirect off; proxy_set_header Host api1.domain.com; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } #API2 server { listen 126; server_name 192.168.1.1 192.168.2.1 192.168.3.1; location / { proxy_pass http://DemoBackend; proxy_redirect off; proxy_set_header Host api2.domain.com; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } ##API n等等....
粗略一看,確實是可以實現開發GG的要求啊!再仔細一想,你會發現如此做法會開放越來越多的端口!運維成本以及辨識度低還只是其次,咱說好的安全第一呢?
經過思考和測試,我寫出的最終配置如下:
Shell#新增的IP映射配置 server { listen 80; server_name 192.168.1.10 192.168.2.10 192.168.3.10; location /mail_api/ { proxy_pass http://DemoBackend/; #後面的斜杠不能少,作用是不往後端傳遞/mail-api 這個路徑 proxy_redirect off; proxy_set_header Host mailapi.domain.com; #傳遞不同的host給後方節點,實現IP和域名均可以訪問 proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location /other_api1/ { proxy_pass http://DemoBackend/; proxy_redirect off; proxy_set_header Host otherapi1.domain.com; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } #還可以添加更多映射,通過不同的路徑來映射不同的API,最後對於直接訪問IP則返回403,防網絡上的掃碼探測 location / { return 403; } } #原有的域名映射 server { listen 80; server_name mailapi.domain.com; location / { proxy_pass http://DemoBackend; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } server { listen 80; server_name otherapi1.domain.com; location / { proxy_pass http://DemoBackend; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } #簡單的節點配置(當這些API都用到同一個Backend時,上述代碼中的proxy_set_header傳遞的host就起到了關鍵性作用!) upstream DemoBackend { server 192.168.10.1; server 192.168.10.2; ip_hash; }
最終實現的效果就是:你要通過IP請求郵件API,只要請求 http://192.168.1.1/mail_api/ 即可,而不需要開放多余端口。而且,後續要新增更多API,只需要定義不同的二級路徑即可,這些二級路徑的辨識度可比端口要好得多!
Ps:正如代碼中的註釋,示例代碼只用了一個 DemoBackend 節點配置,為的是分享另一個小技巧:當後端節點承載了多個站點而且都是監聽80端口時(比如某些小公司同一個IIS服務器部署了N個站點),反向代理中的proxy_set_header參數,可以自定義傳遞一個host域名給後端節點,從而正確響應預期內容!
這段解釋有點無力,還是拿實際例子舉例吧!
我之前供職的公司節點用的是IIS服務器,前端用Nginx反向代理,IIS服務器上有多個站點,站點之間部分會通過 rewrite 規則聯系起來。
打個比方:比如A網站有個專題內容(www.a.com/zt/)是通過IIS偽靜態映射到了B網站(content.b.com)。也就是訪問到http://www.a.com/zt/,其實最後是通過A網站映射到了B網站上面。
後來發現IIS有個偽靜態BUG,會經常奔潰,就要我用前端的Nginx來實現直接映射,而不再走IIS的A網站中轉。
那麽這個需求就正好用到了 proxy_set_header 技巧,一看就懂:
Shellserver { listen 80; server_name www.a.com; location /zt/ { proxy_pass http://ABackend; #都是相同的節點,此示例代碼我就不寫upstream了 proxy_redirect off; proxy_set_header Host www.b.com; #這裏就是關鍵性作用,傳遞b域名給後端IIS proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } #upstream略..
很明顯,通過傳遞自定義域名,就可以實現通過A網站訪問Nginx,返回B網站內容,和反向代理谷歌的原理是一致的。
當然,上文為了實現 IP 和域名都可以訪問,這個proxy_set_header 設置也是必須的。說白了就是在反代過程中,對後端服務器偽裝(傳遞)了一個自定域名,讓後端響應該域名預期內容。
本文分享的經驗,其實比較簡單,主要就是通過不同路徑來反代不同的目標。估計很多大拿早就用爛了吧!不過值得註意的是,通過自定義路徑反代,需要註意 proxy_pass 參數後面是否需要斜杠,避免將自定義的路徑傳遞到後端節點,導致訪問404!
Nginx配置二級目錄/路徑 映射不同的反向代理和規避IP+端口訪問