在使用 NGINX 反代 Gitbook 的時候遇到一個很草的問題,搜遍全網不論中英文都沒有人給出有效的解決辦法。那個問題具體來說是:使用 proxy_pass
進行反代時,若網址尾端不加 /,會被重定向到反代地址的監聽端口 ( NGINX redirect url to the listening port except the correct port of destination without slash ) 經過一番摸索,被我試出一個不太優雅但可行的解決方法。
問題描述
假設我們今天要利用 www.example.com
,反代 some.gitbook.io/pages
。而為了方便,我們設定 www.example.com/*
的請求會自動重定向到 some.gitbook.io/pages/$1
上。配置文件寫法如下
1 | server { |
可以看到這裡監聽了 8443
而非 443
端口,這是為了當 Trojan + NGINX Stream 模塊分流的 backend 使用,也是造成報錯的主要原因。
這時候打開以下網址,會發現瀏覽器出現各種截然不同的行為
- 訪問
https://www.example.com
,會跳到https://wwww.example.com:8443//
( 錯誤的端口 ) - 訪問
https://www.example.com/
,會跳到https://wwww.example.com/pages/
( 正常跳轉,第一次加戴不出畫面 ) - 訪問
https://www.example.com//
,會跳到https://wwww.example.com/pages/
( 正常跳轉 ) - 訪問
https://www.example.com/pages
,會跳到https://wwww.example.com:8443/pages/
( 錯誤的端口 ) - 訪問
https://www.example.com/pages/
,可以正常訪問 - 訪問
https://www.example.com/pages/*
,可以正常訪問
1、4 網址尾端沒有 / 就會報錯,3、5、6 正常訪問,2 正常跳轉但不正常訪問。而且不同瀏覽器對 URL 的作法還不一樣,例如 Firefox / Brave / Safari 會自動補上網址尾部的 slash 所以不會觸發這個 bug;在 Edge Chromium / Safari for iOS 上就會發生。
解決方法
Google 上給出的各種參數,例如 absolute_redirect
、proxy_redirect
、proxy_bind
、port_in_redirect
、proxy_set_header X-Forwarded-Port
全部沒有用。最後我的解決方法是在 8443 端口設定 301 跳轉,只要導到錯誤端口就跳回去。經過測試整個跳轉過程幾乎是透明的,除了我們自己知道 8443 端口是開的以外,在網速夠快的情況下,使用者很難看出來中間經過了跳轉。完整配置如下
1 | server { |
雖然要多開一個 8443 感覺不夠優雅,不過這樣可以有效解決奇怪的端口跳轉問題,訪問體驗勘稱完美。若有人有更好的解決辦法,歡迎提出。注意,有些瀏覽器需要清除緩存才會看到效果
如果 Web 直接監聽 443 呢
照以上辦法修改完成後,我開始想,既然 http 模塊間支持分開監聽 0.0.0.0:80
和 127.0.0.1:80
( 其他端口同理 ),那 stream 模塊(分流模塊)和 http 模塊(我們的反代網站),能不能一個監聽 0.0.0.0:443
、另一個藍聽127.0.0.1:443
呢?測試結果是不行的,stream 模塊和 http 模塊監聽同一個端口時,NGINX 會報錯 [emerg] bind() to 0.0.0.0:443 failed (98: Address already in use)
。
結論
要觸發這個問題,從我的情況來看要滿足三個條件
- 網站做為 stream 模塊的 upstream,監聽與被反代網站不同的端口
- 網址尾端不加 slash
- 特定瀏覽器,己知目前版本 Edge Chromium 和 Safari for iOS 有可能觸發(草的是 Edge Chromium 無痕模式正常)
解決這個問題的思路是,在網站端口的0.0.0.0
建立 301 跳轉,當出現問題時自動跳轉回正確的端口。
No comments:
Post a Comment