SNI是什么
在使用TLS的时候,http server希望根据HTTP请求中HOST的不同,来决定使用不同的证书。
SNI细节
由于HTTP的HOST字段在HTTP GET中。而TLS的握手以及证书验证都是在HTTP开始之前。
这个时候,TLS协议的HELLO字段中增加了一个server name字段,让HTTP的client的可以提前
设置HOST,从而使server在tls的握手阶段可以选择证书。
然后,这个机制本身可以抛开http不关心,只要TLS client提前设置了server name,便可以实现SNI
nginx的配置
检测nginx是否支持sni,http://nginx.org/en/docs/http/configuring_https_servers.html#Server%20Name%20Indication
$ nginx -V ... TLS SNI support enabled ...
启用了sni的nginx,如下变量会被赋值
$ssl_server_name
证书命令ssl_certificate,也可以通过变量进行设置,形如:
ssl_certificate $ssl_server_name.crt; ssl_certificate_key $ssl_server_name.key;
于是我们可以通过 nginx config中的嵌入逻辑,完成sni的完整配置。
如:
stream {
upstream test {
server 127.0.0.1:50001;
}
map $ssl_server_name $sni_string {
test1.www.local test1;
test2.www.local test2;
test3.www.local test3;
default test1;
}
map $ssl_server_name $sni_string445 {
test1.www.local test4451;
test2.www.local test4452;
test3.www.local test4453;
default test4451;
}
server {
listen 444 ssl;
ssl_certificate /data/sni/sni_${sni_string}.cer;
ssl_certificate_key /data/sni/sni_${sni_string}.key;
proxy_pass test;
}
server {
listen 445 ssl;
ssl_certificate /data/sni445/sni_${sni_string445}.cer;
ssl_certificate_key /data/sni445/sni_${sni_string445}.key;
proxy_pass test;
}
}
注意,如果希望map命令支持host的最长匹配与正则,需要再添加hostnames关键字。
http://nginx.org/en/docs/http/ngx_http_map_module.html#map
map命令的本质,可以理解为通过旧的变量定义出了一个新的变量。
ssl_certificate