转载自:https://blog.fcci.cn/2016/05/nginx-https-proxy-sni/
作者姚毅,版权所有,署名转载
背景:
这事起源于需要一个反向代理,请求的后端是某开放云的CDN,CDN配置为基于HTTPS的虚拟主机(单IP多Host区分的虚拟主机)
注意:所以本文并不是你的nginx提供了https服务,而在于反向代理的后端是否为https服务。
正常nginx配置了SSL是可以通过HTTPS访问后端的,但是对SNI的支持有点麻烦。
代理服务器是nginx。以下为配置过程:
首先支持SNI协议的openssl版本最低为0.9.8f
Mozilla NSS 3.11.1 client-side onlyOpenSSL0.9.8f (released 11 Oct 2007) – not compiled in by default, can be compiled in with config option ‘–enable-tlsext’0.9.8j (released 07 Jan 2009) through 1.0.0 (released 29 March 2010) – compiled in by defaultGNU TLSlibcurl / cURL since 7.18.1 (released 30 Mar 2008) when compiled against an SSL/TLS toolkit with SNI supportPython 3.2 (ssl, urllib and httplib modules)Qt 4.8Oracle Java 7 JSSE
这里选用了最新的openssl 1.0.1t
curl -o openssl.tar.gz https://www.openssl.org/source/openssl-1.0.1t.tar.gz
tar -xvf openssl-1.0.1t.tar.gz
openssl这里不用编译,有源代码就可以了
nginx从1.7之后开始支持SNI proxy指令,我这里选择的nginx 1.10
wget http://nginx.org/download/nginx-1.10.0.tar.gz
tar -xvf nginx-1.10.0.tar.gz
cd nginx-1.10.0
以下是我的配置命令,目录自行选择
./configure –prefix=/opt/nginx/ –with-http_ssl_module –with-openssl=~/openssl-1.0.1t
上面参数解释:
–prefix是nginx安装目录
–with-http_ssl_module是启用ssl支持
–with-openssl是刚刚下载的openssl代码目录
make && make install
编译之后,进入nginx的sbin/nginx -V 看一下是否支持
nginx version: nginx/1.10.0built by gcc 3.4.5 20051201 (Red Hat 3.4.5-2)built with OpenSSL 1.0.1t 3 May 2016TLS SNI support enabled
如果有TLS SNI support enabled就表示支持SNI
修改nginx安装后的conf/nginx.conf文件
以下是我的server配置节
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 server { listen 8443; access_log logs/proxy_access.log main; underscores_in_headers on; ssl_protocols SSLv3 TLSv1.2 TLSv1.1 TLSv1 SSLv2; error_log logs/error.log info; location / { proxy_ssl_server_name on; proxy_pass https://$http_host$request_uri; proxy_ssl_verify off; proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $http_host; proxy_set_header cookie $http_cookie; proxy_set_header Proxy-Connection ""; proxy_http_version 1.1; } }以上配置酌情修改,注意以下几点:
1、proxy_pass 后面是https://这说明请求以https协议发出
2、为了安全,proxy_ssl_verify 应该配置为on,这里便于调试配置了off,如果配置了on,请确保你的ca文件中有对方服务器的证书
3、ssl_protocols 表示支持的协议,印象中是sslv3和tls1.0以后才支持的SNI,所以都写上吧。
4、最关键的一句proxy_ssl_server_name on最关键的,也就是把主机名字传递给后端服务器,让对方服务器在TLS握手层面就可以收到host,便于打到具体的主机。(nginx 1.7开始支持)
重启nginx服务器(涉及socket监听的不要使用reload,因为无法reload信号无法让nginx重新监听)
curl -v -x 127.0.0.1:8443 http://www.symantec.com/
应返回:* Trying 127.0.0.1…* Connected to 127.0.0.1 (127.0.0.1) port 8443 (#0)> HEAD http://www.symantec.com/ HTTP/1.1> Host: www.symantec.com> User-Agent: curl/7.47.1> Accept: */*> Proxy-Connection: Keep-Alive>< HTTP/1.1 200 OK
特别说明一下:http://www.symantec.com/这里虽然写的是http,但实际上代理走的是https协议,这里不能直接写https
目前发现,对于使用SNI做域名识别的HTTPS Web服务器,如果代理服务器不发送SNI,会返回502错误。即无法正常和后端通信。
SNI(Server Name Indication)https://en.wikipedia.org/wiki/Server_Name_Indication
nginx关于proxy_ssl_server_name的配置:http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_ssl_server_name
转载于:https://www.cnblogs.com/yaoyi/articles/nginx-https-proxy-sni.html
