To configure an HTTPS server, you need to enable the ssl parameter on listening sockets in the server block, and specify the location of the server certificate and secret key files:
server {
listen 443 ssl;
server_name www.example.com;
ssl_certificate www.example.com.crt;
ssl_certificate_key www.example.com.key;
ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
...
}
The server certificate is public. It is sent to every client connecting to the server. The secret key should be stored in a file with restricted access (access permissions must allow the main nginx process to read this file). The secret key can also be stored in the same file as the certificate:
ssl_certificate www.example.com.cert;
ssl_certificate_key www.example.com.cert;
in which case, file access permissions should also be restricted. Although both the certificate and the key are stored in one file, only the certificate is sent to the client.
Using the ssl_protocols and ssl_ciphers directives, you can restrict connections to use only "strong" versions and ciphers of SSL/TLS. Starting from version 1.0.5, nginx uses " ssl_protocols SSLv3 TLSv1" and " ssl_ciphers HIGH:!aNULL:!MD5" by default, so explicit configuration is only meaningful for earlier versions of nginx. Starting from versions 1.1.13 and 1.0.12, nginx uses " ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2" by default.
It is known that ciphers using CBC mode are vulnerable to several attacks, in particular the BEAST attack (see CVE-2011-3389). Cipher configuration can be changed to prefer RC4-SHA:
ssl_ciphers RC4:HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
Optimizing the HTTPS Server
SSL operations consume additional CPU resources. On multiprocessor systems, it is recommended to run multiple worker processes, at least equal to the number of available CPU cores. The most CPU-intensive operation is the SSL handshake, during which cryptographic session parameters are established. There are two ways to reduce the number of these operations performed for each client: using persistent (keepalive) connections, which allow multiple requests to be handled within a single connection, and reusing SSL session parameters to avoid the need to perform an SSL handshake for parallel and subsequent connections. Sessions are stored in the SSL session cache, which is shared among worker processes and configured using the ssl_session_cache directive. Approximately 4000 sessions fit in 1 megabyte of cache. The default cache timeout is 5 minutes. It can be increased using the ssl_session_timeout directive. Here is an example configuration optimized for a multi-core system with a 10-megabyte shared session cache:
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 SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
...
SSL Certificate Chains
Some browsers may display a warning about a certificate signed by a well-known certificate authority, while other browsers accept this same certificate without issues. This happens because the certificate-issuing authority signed it with an intermediate certificate that is not present in the database of well-known trusted certificate authorities distributed with the browser. In such cases, the certificate authority provides a “chain” of certificates that should be appended to the server certificate. The server certificate should be placed before the certificate chain in the combined file:
$ cat www.example.com.crt bundle.crt > www.example.com.chained.crt
The resulting file should be specified in the ssl_certificate directive:
server {
listen 443 ssl;
server_name www.example.com;
ssl_certificate www.example.com.chained.crt;
ssl_certificate_key www.example.com.key;
...
}
If the server certificate and the certificate chain are concatenated in the wrong order, nginx will refuse to start and display an error message:
SSL_CTX_use_PrivateKey_file(" ... /www.example.com.key") failed
(SSL: error:0B080074:x509 certificate routines:
X509_check_private_key:key values mismatch)
because nginx will attempt to use the secret key with the first certificate in the chain instead of the server certificate.
Browsers usually store intermediate certificates signed by trusted certificate authorities, so actively used browsers may already have the required intermediate certificates and will not issue a warning about a certificate sent without its associated certificate chain. You can verify that the server sends the full certificate chain using the command-line utility openssl, for example:
$ 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
...
In this example, the subject (“s”) of server certificate #0 www.GoDaddy.com is signed by the issuer (“i”), which in turn is the subject of certificate #1, signed by an issuer that is in turn the subject of certificate #2, signed by the well-known issuer ValiCert, Inc., whose certificate is stored in the browser’s built-in certificate database (which, in a dark closet, is kept in the house that Jack built).
If the certificate chain is not added, only server certificate #0 will be shown.
Single HTTP/HTTPS server
You can configure a single server that handles both HTTP and HTTPS requests:
server {
listen 80;
listen 443 ssl;
server_name www.example.com;
ssl_certificate www.example.com.crt;
ssl_certificate_key www.example.com.key;
...
}
Up to version 0.7.14, SSL could not be enabled selectively for individual listening sockets as shown above. SSL could only be enabled for the entire server using the ssl directive, which did not allow configuring a single HTTP/HTTPS server. To solve this problem, the ssl parameter was added to the listen directive. Therefore, using the ssl directive is not recommended in modern versions.
Name-based HTTPS server selection
A typical problem arises when configuring two or more HTTPS servers listening on the same IP address:
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;
...
}
In this configuration, the browser will receive the default server certificate, i.e., www.example.com, regardless of the requested server name. This is due to the behavior of the SSL protocol. An SSL connection is established before the browser sends an HTTP request, and nginx does not know the name of the requested server. Therefore, it can only offer the default server certificate.
The oldest and most reliable way to solve this problem is to assign a unique IP address to each HTTPS server:
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;
...
}
SSL certificate with multiple names
There are other methods that allow using the same IP address for multiple HTTPS servers simultaneously. However, all of them have their drawbacks. One such method is using a certificate with multiple names in the SubjectAltName field, such as www.example.com and www.example.org. However, the length of the SubjectAltName field is limited.
Another method is using a wildcard certificate, such as *.example.org. Such a certificate protects all subdomains of the specified domain, but only at a given level. www.example.org fits under such a certificate, but example.org and www.sub.example.org do not. The two aforementioned methods can be combined. A certificate can simultaneously contain both exact and wildcard names in the SubjectAltName field, such as example.org and *.example.org.
It is better to place the certificate file with multiple names and its private key file at the http configuration level, so that all servers inherit their single copy in memory:
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;
...
}
