Correctly configuring secure HTTPS/SSL/TLS in nginx

In the past I described how to manage an nginx configuration in a manageable way, through inclusion files. Today, I’m talking a bit about setting up HTTPS/SSL/TLS in nginx – in a good configuration (rather than the insecure defaults).

SSL Labs provides a great free service to check your websites effective SSL/TLS configuration, and will warn you about issues on the result page. They also provide guidelines for setting up a reasonably secure SSL/TLS.

As for the configuration in nginx, here is my includes/ssl file I now use:

# Enabling SSL for HTTPS access
#
# nginx HTTPS doc: http://nginx.org/en/docs/http/configuring_https_servers.html
# nginx ssl module doc: http://nginx.org/en/docs/http/ngx_http_ssl_module.html
# Secure HTTPS Guidelines: https://www.ssllabs.com/downloads/SSL_TLS_Deployment_Best_Practices_1.3.pdf

    # obsolete; use listen directive instead ('listen 443 ssl spdy;')
    #ssl  on;

    # SSLv2 SSLv3 must not be supported. TLS are the successors. Use TLSv1.1 and TLSv1.2.
    # TLSv1 is secure with careful configuration, but maybe should be supported for old clients.
    # TLS > 1.0 requires openssl > 1.0 (`openssl version`) - will only work if available.
    ssl_protocols  TLSv1 TLSv1.1 TLSv1.2;

    # default: HIGH:!aNULL:!MD5
    # example: ssl_ciphers  ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv3:+EXP;
    # For full list see command 'openssl ciphers'
    # Value result can be checked with openssl ciphers -v '<value>'
    #ssl_ciphers  DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA;
    ssl_ciphers  HIGH:!aNULL:!MD5:!DSS:!RC4;
    ssl_prefer_server_ciphers on;

    # For performance: Session cache, shared across workers.
    # Lifetime slightly increased. For effect, general keep-alive should already be enabled.
    ssl_session_cache   shared:SSL:10m;
    ssl_session_timeout  10m;

The only three other settings you need to specify in your server configuration is (including the include line):

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    […]
    include includes/ssl;
    ssl_certificate /path/to/cert.crt;
    ssl_certificate_key /path/to/cert.key;

If you do not have https-specific location rewrites you can even combine the HTTP and HTTPS server configurations.

To elaborate a bit on the SSL settings:

ssl_protocols: If you have an adequately recent openssl installation consider removing TLSv1. At this point in time, some stable linux distributions still deploy an openssl version below 1.0 by default though. The important part here is to remove the SSL protocols that are allowed by default. The SSL Labs guidelines clearly state theses should be considered vulnerable and must not be used.

ssl_ciphers: I was not too sure here, but set a plausible setting above. The SSL Labs guidelines clearly state which ciphers not to use, and recommend using ECDHE, and DHE as a fallback. You may want to experiment yourself a bit as well, especially which ciphers your systems openssl installation provides in general and with the filter set above.

ssl_session: As described in the comment, this setting should improve performance – overriding the default no-cache setting.