Я используюмодуль потока nginxдля использования nginx в качестве обратного прокси-сервера tcp перед s3. Недавно мне нужно было добавить логику для размещения дополнительного апстрима. Для этого я решил использовать условную логику через переменную map $ssl_preread_server_name.ssl_prereadпозволяет 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.
Это работает большую часть времени. Но иногда в журнале ошибок появляются ошибки, указывающие на то, что каким-то образом запросы попадают на серверы nginx на порту 443 без указания имени сервера.
[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, подключившись без явной установки параметра servername:
openssl s_client -connect <mydomain>:<some_port> -showcerts
Этот запрос просто предоставит мне сертификат сервера по умолчанию и не будет учитывать доменное имя, которое я указал в URL. С другой стороны, при указании параметра servername:
openssl s_client -connect <mydomain>:<some_port> -showcerts -servername <mydomain>
.. запрос отправляется на правильный домен и возвращается правильный сертификат.
При доступе к тому же веб-серверу с помощью curl или через веб-браузеры я не наблюдаю этой проблемы, я подозреваю, что реализация в веб-браузере и curl устанавливает имя сервера, извлекая его из URL-адреса в фоновом режиме, тогда как некоторые клиентские приложения, такие как openssl, рассматривают его как необязательный параметр.
Так что в вашем случае, я полагаю, вам придется:
- узнать, где генерируются запросы
- посмотрите, есть ли возможность задать имя сервера