幫忙看了一個茶包:建立 ASP.NET Core 6.0 專案部署到 CentOS 平台,搭配 Nginx Reverse Proxy 對外服務,卻怎麼都無法成功,但同一專案在本機測試,瀏覽器測試正常。

網站架設做法是在 /etc/systemd/system/kestrel-webapp.service 設定 ExecStart=/usr/bin/dotnet /var/www/webapp/WebApp.Core.dll 將 Kestrel 轉為系統服務,/var/nginx/conf.d/webapp.conf 則設定 proxy_pass http://localhost:5000 將 CentOS 主機的 80 Port 導向 Kestrel 服務的 5000 Port,看起來沒什麼問題,但用 curl ℎttp://localhost:80 什麼都沒傳回就結束,往前一層檢查 Kestrel 服務 curl ℎttp://localhost:5000 也是什麼沒東西,再往前一層,手動跑 dotnet WebApp.Core.dll,curl ℎttp://localhost:5000 也是一片空,最後甚至將專案原始碼放到 CentOS,現場編譯 dotnet run 測試其隨機 Port,curl ℎttp://localhost:5058 仍然連個鬼影都沒有。但 dotnet run 畫面顯示的 ℎttps://localhost:7121 跟 ℎttp://localhost:5058 讓我懷疑一件事,莫非因為 ASP.NET Core 預設要強制 HTTPS 連線,因此 http: 會被導到 https:,但 curl 不支援導向?改測 curl ℎttps://localhost:7121 果然有網頁內容。

在 Windows 上用瀏覽器觀察,可以看到 ℎttp://localhost:5058 時 Kestrel 會回傳 HTTP 307,並透過 Location Header 導向 ℎttps://localhost:7121:

改用 PowerShell Invoke-WebRequest,連線 ℎttp://localhost:5058 時有自動導向,傳回 ℎttps://localhost:7121 的結果:

至此得到結論:1) curl 不支援 307 導向,故連 http 時看到空白一片 2) Nginx proxy_pass http://localhost:5000 有成功將 80 Port 導向 5000,但也不支援 307 導向,故看到的也是一片空白。

我平時開發 ASP.NET Core 專案,都是預想會跑 Docker 搭配 Nginx 對外,Kestrel 與 Nginx 在同一台機器,啟用 TLS 加密傳輸是多此一舉,還要處理 Self-Signed 憑證不被信任問題,所以修改專案時都順手將下圖的 app.UseHttpsRedirection() 註解掉,讓專案正式執行時只聽 ℎttp://localhost:5000:

所以一定要改程式碼嗎?未必,我們也可以設定 ASPNETCORE_URLS 環境參數或是加上 --urls 參數,指定只聽 ℎttp://localhost:5000,ASP.NET Core 很聰明,發現只有 http 時會忽略 UseHttpsRedirection,這樣不用改程式就能搭配 Nginx 使用囉~ (註:Docker 容器有預設 ASPNETCORE_URLS 環境變數 ℎttp://+:80,亦不會遇到這類問題)

When using Nginx as reverse proxy, be beware that app.UseHttpsRedirection() may fail the connection.


Comments

# by Ivan

之前也有遇到這問題 公司L4 Switch只會用http打給服務 結果就是不停的Redirect

# by Tony

curl 可加上參數 -v 或 --verbose 印出執行細節 詳細可參考 https://curl.se/docs/manpage.html#-v 另加上 -L 會跟隨Redirect至HTTPS

Post a comment