我正在使用nginx 流模組利用 nginx 作為 s3 前面的 TCP 反向代理。最近,我需要添加邏輯以容納額外的上游。為此,我選擇透過映射變數 $ssl_preread_server_name 使用條件邏輯。ssl_預讀允許 nginx 從 ClientHello 訊息中提取伺服器名稱,而無需終止 SSL。你可以看到下面的邏輯:
map $ssl_preread_server_name $https_cname {
s3.amazonaws.com https_s3_backend;
aws-service-2.amazonaws.com aws-service-2-backend;
}
upstream https_s3_backend {
server s3.amazonaws.com:443;
}
upstream aws_service_2_backend {
server aws-service-2.amazonaws.com:443;
}
server {
listen 443;
proxy_pass $https_cname;
ssl_preread on;
}
當伺服器名稱為 s3.amazonaws.com 的請求傳入時,該請求將傳送至 s3。當伺服器名稱為 aws-service-2.amazonaws.com 的請求傳入時,該請求將發送到 aws-service-2。
這在大多數情況下都有效。但是,有時錯誤日誌中會出現錯誤,表示請求以某種方式到達連接埠 443 上的 nginx 伺服器,但沒有任何伺服器名稱。
[error] ... no host in upstream "", client: x.x.x.x, server: 0.0.0.0:443
當我在地圖邏輯中加入預設語句時,這些錯誤就會消失。對於某些未提取伺服器名稱的 s3 請求,可能有哪些解釋?目前,請求到達這些 nginx 框的唯一方法是有人執行 s3 操作。
答案1
我對 Amazon S3 本身並不熟悉,但我認為問題在於請求是在沒有設定伺服器名稱的情況下產生的(請參閱伺服器名稱指示)。
我在類似的設定中遇到了同樣的問題,並且能夠透過連線而不明確設定 servername 參數在 OpenSSL v1.0.2p 中重現此問題:
openssl s_client -connect <mydomain>:<some_port> -showcerts
此請求只會向我提供預設伺服器的證書,而不考慮我在 URL 中提供的網域名稱。另一方面,指定 servername 參數時:
openssl s_client -connect <mydomain>:<some_port> -showcerts -servername <mydomain>
..請求被傳送到正確的網域並傳回正確的憑證。
當使用curl或透過網頁瀏覽器存取同一個網頁伺服器時,我沒有觀察到這個問題,我懷疑網頁瀏覽器和curl中的實作是透過從後台的URL中提取伺服器名稱來設定伺服器名稱,而某些客戶端應用程序,例如openssl 將其視為可選參數。
所以就你的情況我想你必須:
- 找出請求是在哪裡產生的
- 看看是否有設定伺服器名稱的選項