我正在使用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 并不熟悉,但我认为问题在于请求是在没有设置服务器名称的情况下生成的(请参阅服务器名称指示)。
我在类似的设置中遇到了同样的问题,并且能够通过连接而不明确设置服务器名参数来重现此问题,例如在 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 或通过 Web 浏览器访问同一个 Web 服务器时,我没有观察到此问题,我怀疑 Web 浏览器和 curl 中的实现是通过在后台从 URL 中提取服务器名称来设置服务器名称,而某些客户端应用程序(例如 openssl )将其视为可选参数。
因此,就你的情况而言,我想你必须:
- 找出请求的生成位置
- 看看是否有设置服务器名称的选项