配置HTTPS服务器

HTTPS服务器优化

SSL证书链

单个HTTP / HTTPS服务器

基于HTTPS的服务器

具有多个名称的SSL证书

服务器名称指示

兼容性

要配置HTTPS服务器,必须在服务器块中的侦听套接字上启用ssl参数,服务器的位置证书私钥文件应该被指定:

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_protocolsssl_ciphers可用于限制连接,仅包括SSL / TLS的强大版本和密码。默认情况下,nginx使用“ssl_protocols TLSv1 TLSv1.1 TLSv1.2”和“ssl_ciphers HIGH:!aNULL:!MD5”,因此通常不需要配置它们。请注意,这些指令的默认值为已更改几次。

HTTPS server optimization

SSL操作会消耗额外的CPU资源。在多处理器系统上,应运行几个工作进程,不少于可用CPU内核的数量。最强大的CPU操作是SSL握手。有两种方法可以最大限度地减少每个客户端的这些操作数量:第一种是通过使keepalive连接通过一个连接发送多个请求,第二个是重用SSL会话参数,以避免SSL握手并行和后续连接。会话存储在工作人员共享的SSL会话缓存中,并由ssl_session_cache指令配置。一兆字节的缓存包含约4000个会话。默认缓存超时时间为5分钟。可以使用ssl_session_timeout指令来增加它。以下是针对具有10兆字节共享会话缓存的多核系统优化的示例配置:

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 certificate chains

某些浏览器可能会抱怨知名证书颁发机构签发的证书,而其他浏览器可能会接受该证书而没有问题。发生这种情况是因为颁发机构已经使用在特定浏览器分发的知名可信证书颁发机构的证书库中不存在的中间证书来签署服务器证书。在这种情况下,权限提供了一系列链接的证书,这些证书应连接到签名的服务器证书。服务器证书必须出现在组合文件中的链接证书之前:

$ cat www.example.com.crt bundle.crt > www.example.com.chained.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已尝试使用私钥使用捆绑包的第一个证书而不是服务器证书。

浏览器通常存储他们收到的中间证书,哪些由受信任的机构签名,所以主动使用的浏览器可能已经具有所需的中间证书,并且可能不会抱怨没有链接捆绑包发送的证书。为了确保服务器发送完整的证书链,可以使用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”)由颁发者签名(“i “),其本身是证书#1的主体,其由本身是证书#2的主体签发的发行方签名,该证书#2由公知的发行人ValiCert,Inc。签名,证书存储在浏览器的内置证书库(位于Jack建立的房屋中)。

如果未添加证书包,则仅显示服务器证书#0。

A single HTTP/HTTPS server

可以配置一个处理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,如上所示。只能使用ssl指令为整个服务器启用SSL,从而无法设置单个HTTP / HTTPS服务器。添加listen指令的ssl参数来解决此问题。因此,不建议在现代版本中使用ssl指令。

Name-based HTTPS servers

配置两个或多个HTTPS服务器侦听单个IP地址时,会出现常见问题:

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协议行为引起的。SSL连接建立在浏览器发送HTTP请求之前,并且nginx不知道请求的服务器的名称。因此,它只能提供默认服务器的证书。

解决问题的最古老和最强大的方法是为每个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;
    ...
}

An SSL certificate with several names

还有其他方法允许在多个HTTPS服务器之间共享一个IP地址。然而,他们都有自己的缺点。一种方法是在SubjectAltName证书字段中使用多个名称的证书,例如www.example.comwww.example.org但是,SubjectAltName字段长度有限。

另一种方法是使用通配符名称的证书,例如*。example.org通配符证书保护指定域的所有子域,但只能在一个级别上。此证书符合www.example.org,但与example.orgwww.sub.example.org不符。这两种方法也可以组合。证书可以在SubjectAltName字段中包含精确和通配符名称,例如example.org*。example.org

最好在多个名称和证书文件的http配置文件中继承其所有服务器中的单个内存副本:

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;
    ...
}

Server Name Indication

用于在单个IP地址上运行多个HTTPS服务器的更通用的解决方案是TLS服务器名称指示扩展(SNI,RFC 6066),允许浏览器在SSL握手期间传递所请求的服务器名称,因此,服务器将知道它应该用于连接的证书。然而,SNI的浏览器支持有限。目前,它支持从以下浏览器版本开始:

只有域名可以在SNI中传递,但是如果请求包含文字IP地址,某些浏览器可能会错误地将服务器的IP地址作为其名称。不应该依靠这个。

为了在nginx中使用SNI,必须在已经构建了nginx二进制文件的OpenSSL库以及运行时被动态链接的库中支持它。如果使用配置选项“enable-tlsext”构建,则OpenSSL支持SNI,因为0.9.8f版本。由于OpenSSL 0.9.8j,默认情况下启用此选项。如果nginx是用SNI支持构建的,那么当使用“-V”开关运行时,nginx会显示这个:

$ 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

Compatibility

written by Igor Sysoev
edited by Brian Mercer