国庆期间,抽时间翻译。英文水平太差,翻译太费劲了。。。
英文文档对应页面:Configuring HTTPS servers
配置https服务
为了配置https服务,必须开启 "server"块的 "listen" 指令的 "ssl" 参数,并且需要指定 "server_certificate" 和 "private_key" 文件位置:
server {
listen 443 ssl;
server_name www.example.com;
ssl_certificate www.example.com.crt;
ssl_certificate_key www.example.com.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
}
服务器证书是一个公共的实体。会发送给每个连接到这台服务器的客户端。密钥是一个安全的(私有到)实体,并且应该被存储到一个访问受限的文件中,但必须保证针nginx的主进程是可读的。密钥也可以被存储到同证书相同的文件中(一个文件中,同时包含了证书和密钥),例如:
ssl_certificate www.example.com.cert;
ssl_certificate_key www.example.com.cert;
当文件中同时包含了证书和密钥,这个文件的访问权限也应该被限制(因为密钥的访问权限需要被限制)。虽然证书和密钥存储在同一个文件中,但是连接时只有证书内容会被发送给客户端。
"ssl_protocols" 和 "sll_ciphers" 指令,可用来限制连接的SSL/TLS版本和ciphers。默认情况下,nginx使用 "ssl_protocols TLSv1 TLSv1.1 TLSv1.2" 和 "ssl_ciphers HIGH:!aNULL:!MD5",所以通常情况下,不需要准确配置它们。注意:这些指令的值被改变过好几次了。
HTTPS服务器优化
ssl操作消耗额外的cpu资源。在多处理器系统中,运行的工作进程(worker_processes)数不应该低于可用的cpu核心的数量。最密集的cpu操作是:ssl的握手操作。有2种方式去减少每个客户端的这些操作数量:第一种方式是:启用 'keepalive' 长连接,在一个连接中可发送多个请求;第二种方式是:重新使用ssl的session参数,避免并发连接和后续连接原本需要的的ssl握手操作。session存储在一个ssl的session缓存中,被工作进程(workers)和"ssl_session_cache"指令所设置的值所共享。1m缓存可包含大约4000条session。默认的缓存过期时间是5分钟。使用 "ssl_session_timeout"指令可延长缓存的过期时间。下面是使用了10m共享session缓存空间来优化一个多核系统的配置实例:worker_processes auto;
http {
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
server {
listen 443 ssl;
server_name www.example.com;
keepalive_timeout 70;
ssl_certificate www.example.com.crt;
ssl_certificate_key www.example.com.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
...
ssl证书链
一些浏览器抱怨,其他浏览器接受知名证书机构未发布的签名证书(某些浏览器支持一些未发布的证书,而有些浏览器并不支持)。出现这种情况是因为:发布机构使用了一个中间证书签署了服务器证书。这个证书并不是基于知名、信任的证书机构发布的证书,而是由一个特殊浏览器发布。在这种情况下,该机构提供了一个同已签名的服务器证书相关联的捆绑证书链(服务器证书同捆绑证书链在同一个文件中)。在合并的文件中,服务器证书必需出现在所有证书链之前:$ cat www.example.com.crt bundle.crt > www.example.com.chained.crt // 服务器证书在最前面(bundle.crt-是证书链文件)
最终的结果文件,应该被使用到 "ssl_certificate" 指令:
server {
listen 443 ssl;
server_name www.example.com;
ssl_certificate www.example.com.chained.crt;
ssl_certificate_key www.example.com.key;
...
}
如果服务器证书和捆绑的证书,以错误的方式关联在一起,nginx启动失败,并且显示如下错误信息:
SSL_CTX_use_PrivateKey_file(" ... /www.example.com.key") failed
(SSL: error:0B080074:x509 certificate routines:
X509_check_private_key:key values mismatch)
因为nginx首先会尝试绑定证书中的第一个的私钥,替代之前的服务器证书私钥。
浏览器通常存储它们接收到的,以及信任机构签名过的中间证书,因此积极使用的浏览器可能已经有所需的中间证书,所以可能不会抱怨(complain about)一个发送过来的没有chained绑定证书(因为浏览器可能已经存储过,该证书的chained绑定证书)。为了确保服务器发送完整的证书链,可能需要使用 "openssl" 命令行工具,例如:
$ openssl s_client -connect www.godaddy.com:443
...
Certificate chain
0 s:/C=US/ST=Arizona/L=Scottsdale/1.3.6.1.4.1.311.60.2.1.3=US
/1.3.6.1.4.1.311.60.2.1.2=AZ/O=GoDaddy.com, Inc
/OU=MIS Department/CN=www.GoDaddy.com
/serialNumber=0796928-7/2.5.4.15=V1.0, Clause 5.(b)
i:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc.
/OU=http://certificates.godaddy.com/repository
/CN=Go Daddy Secure Certification Authority
/serialNumber=07969287
1 s:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc.
/OU=http://certificates.godaddy.com/repository
/CN=Go Daddy Secure Certification Authority
/serialNumber=07969287
i:/C=US/O=The Go Daddy Group, Inc.
/OU=Go Daddy Class 2 Certification Authority
2 s:/C=US/O=The Go Daddy Group, Inc.
/OU=Go Daddy Class 2 Certification Authority
i:/L=ValiCert Validation Network/O=ValiCert, Inc.
/OU=ValiCert Class 2 Policy Validation Authority
/CN=http://www.valicert.com//emailAddress=info@valicert.com
...
在这个例子中, 'www.GoDaddy.com'服务器证书 "#0" 的主题("S")被发行人("/")签名。而发行人("/")自己又是证书 "#1"的主题,被发行人签名,该发行人自身又是 证书 "#2" 的主题,被知名发行人 "ValiCert,inc" 签名。发行人 "ValiCert,inc" 的证书存储在浏览器的内置证书基地(that lay in the house that Jack built - 不知道是啥意思)
------
太难翻译,太难懂了,总之可以理解为一个首位相关联的证书链。。。
------
如果已经添加了一个证书捆绑,仅仅会显示服务器证书 "#0"
单个HTTP/HTTPS服务器
配置同时处理HTTP和HTTPS请求的单个服务器也是可能的:server {
listen 80;
listen 443 ssl;
server_name www.example.com;
ssl_certificate www.example.com.crt;
ssl_certificate_key www.example.com.key;
...
}
在0.7.14版本之前,SSL无法对单个监听sockets选择性地启用,就像上面展示的那样(现在是可以对单个sockets启用的)。SSL仅仅可以对使用了 "ssl" 指令的整个服务器("server"块)启用,使得配置单个HTTP/HTTPS服务器是不可能的。"listen"指令的 "ssl"参数的引入,就是为了解决这个问题。因此,在现代的这些版本中,不鼓励使用 "ssl" 指令。
基于名称的HTTPS服务器
一个普遍的问题是:一个IP地址,配置2个或更多的HTTPS服务器。server {
listen 443 ssl;
server_name www.example.com;
ssl_certificate www.example.com.crt;
...
}
server {
listen 443 ssl;
server_name www.example.org;
ssl_certificate www.example.org.crt;
...
}
使用这个配置,浏览器接收默认服务器的证书,即:www.example.com,而忽略请求的服务器名称。这是由 "ssl" 协议自身行为导致的。在浏览器发送HTTP请求之前,已经建立了 "ssl" 连接,这样浏览器不知道请求服务器的名字。因此,它仅仅提供默认服务器的证书。
解决这一问题的最古老、最健壮的方法是:为每个HTTPS服务器分配一个单独的IP地址。
server {
listen 192.168.1.1:443 ssl;
server_name www.example.com;
ssl_certificate www.example.com.crt;
...
}
server {
listen 192.168.1.2:443 ssl;
server_name www.example.org;
ssl_certificate www.example.org.crt;
...
}
多个server使用一个ssl证书
有其他方式,允许在几个HTTPS服务器之间分享一个单独的IP地址。然而,所有方法都有它们的缺点。一种方式是:使用一个证书,并且在 "SubjectAltName" 证书字段中使用多个服务器名称,例如:"www.example.com" 和 "www.example.org"。然而,"SubjectAltName" 字段长度有限制(只能添加有限个服务器名称)。另一种方式是:使用一个证书和一个通配符表示的服务器名称,例如:"*.example.org"。一个通配符证书,会保证指定域名的所有子域名的安全,但仅仅是一级域名。这个证书匹配到 "www.example.org",但是不会匹配到 "example.org" 和 "www.sub.example.org"。
上面的这两种方法也可以结合使用。一个证书的 "SubjectAltName" 字段,可以包含准确的服务器名称和通配符表示的服务器名称,例如:"example.org" 和 "*.example.org"。
更好的方式是:多个服务器名称,然后在配置文件的 "http" 块中,指定 "证书文件" 和 "证书文件的密钥文件",让所有服务器都可以继承它们都配置(配置在"server"块的上层上下文中,使每个"server"块都可以共享该配置):
ssl_certificate common.crt;
ssl_certificate_key common.key;
server {
listen 443 ssl;
server_name www.example.com;
...
}
server {
listen 443 ssl;
server_name www.example.org;
...
}
服务器名称说明
在一个单独的IP地址上,运行多个HTTPS服务器的更通用的解决方案是:TLS 服务器名称说明扩展(TLS Server Name Indication extension - SNI, RFC 6066,链接地址:http://en.wikipedia.org/wiki/Server_Name_Indication),允许浏览器在SSL握手期间传递请求服务器的名称,因此,ssl握手连接时,服务器将知道它应该使用哪个证书。然而,"SNI" 受浏览器支持的限制。目前,支持SNI的浏览器版本有:Opera 8.0;
MSIE 7.0 (but only on Windows Vista or higher);
Firefox 2.0 and other browsers using Mozilla Platform rv:1.8.1;
Safari 3.2.1 (Windows version supports SNI on Vista or higher);
and Chrome (Windows version supports SNI on Vista or higher, too).
注意:SNI中,仅可以传递域名,然而如果一个请求包含一个IP地址,一些浏览器可能错误的传递一个IP地址作为服务器名字。这是不应该依赖SNI的一个理由。(One should not rely on this - 翻译出来应该是这个意思)
为了在nginx中使用SNI,OpenSSL库和nginx二进制文件(nginx程序)都必须支持SNI,nginx中已经内置SNI的支持(不支持,可能得我们安装其他补丁或扩展?),运行时会动态链接到OpenSSL库。OpenSSL在0.9.8f版本后,开始支持SNI,安装时只需要指定配置选项 "--enable-tlsext"。OpenSSL在0.9.8f版本后,该选项是默认启用的。如果nginx内置了SNI支持,当运行'nginx -V',将显示如下信息:
$ nginx -V
...
TLS SNI support enabled
...
如果内置了SNI的nginx被动态链接到不支持SNI的OpenSSL库中,nginx将显示如下的警告:
nginx was built with SNI support, however, now it is linked
dynamically to an OpenSSL library which has no tlsext support,
therefore SNI is not available