UPDATE: Google no longer supports spdy. Instead it focuses on http/2. This blog-post is no longer up-to-date.

Today I tested nginx with Google’s spdy implementation.I already tested pagespeed separatly in a different post that showed the speed-boost gained from it. Now to add the security for you users. Screw you, NSA!

Installation

Spdy is not built into nginx by default, so you have to download it separatly and build nginx with the modules enabled from source. Since spdy uses encryption by default, you’ll need OpenSSL-packages. The OpenSSL-package CentOS release 6.4 is in version 1.0.0 and doesn’t support NPN. NPN is the “Next Protocol Negotiation” and used by spdy to negotiate which protocol (spdy or HTTPS) is used over a secure connection. So the OpenSSL-sources must be downloaded, too.

Download the latest versions of nginx, OpenSSL and spdy:

[root@ ~]# NGINX_VERSION=1.7.12
[root@ ~]# SSL_VERSION=1.0.2a
[root@ ~]# cd ~
[root@ ~]# wget http://nginx.org/download/nginx-$NGINX_VERSION.tar.gz && tar xzf nginx-$NGINX_VERSION.tar.gz
[root@ ~]# wget http://www.openssl.org/source/openssl-$SSL_VERSION.tar.gz && tar xzf openssl-$SSL_VERSION.tar.gz

Now build nginx with the modules:

[root@ ~]# cd nginx-$NGINX_VERSION
[root@ nginx]# ./configure --with-http_spdy_module --with-http_ssl_module --with-openssl=~/openssl-$SSL_VERSION/
[root@ nginx]# make
[root@ nginx]# make install

Configuration

Now you have to configure nginx to actually use spdy. If you already use HTTPS, just add “spdy” to the listen-directive and you’re good to go.

If you haven’t used encryption before, follow these steps:

First rewrite every non-encrypted request to encrypted request:

server {
        listen 80;
        rewrite ^(.*) https://domain.com/$request_uri permanent;
}

Then enable nginx to listen to Port 443 and accept requests with SSL(HTTPS) and spdy:

server {
    ssl on;
    ssl_certificate /etc/nginx/ssl/zufallsheld.de/ssl_unified.crt;
    ssl_certificate_key /etc/nginx/ssl/zufallsheld.de/ssl.key;
    server_tokens off;
    ####################################
    # Originally adapted from https://gist.github.com/konklone/6532544
    #https://github.com/18F/tls-standards/blob/008ad71ff13b368895351342142eea4fba671a50/configuration/nginx/ssl.rules
    # See some related discussion and detail there.
    ####################################
    # HTTP Strict Transport Security: tells browsers to require https:// without first checking
    # the http:// version for a redirect. Warning: it is difficult to change your mind.
    # 
    #    max-age: length of requirement in seconds (31536000 = 1 year)
    #    includeSubdomains: force SSL for *ALL* subdomains (remove if this is not what you want)
    #    preload: indicates you want browsers to ship with HSTS preloaded for your domain.
    # 
    #    Submit your domain for preloading in browsers at: https://hstspreload.appspot.com
    add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains; preload';
    # If you *can't* guarantee that all subdomains above the one you're securing will be TLS,
    # then comment out the above and uncomment the line below.
    # add_header Strict-Transport-Security 'max-age=31536000';
    # Prefer certain ciphersuites, to enforce Forward Secrecy and avoid known vulnerabilities.
    #
    # Forces forward secrecy in all browsers and clients that can use TLS,
    # but with a small exception (DES-CBC3-SHA) for IE8/XP users.
    #
    # Reference client: https://www.ssllabs.com/ssltest/analyze.html
    ssl_prefer_server_ciphers on;
    ssl_ciphers 'kEECDH+ECDSA+AES128 kEECDH+ECDSA+AES256 kEECDH+AES128 kEECDH+AES256 kEDH+AES128 kEDH+AES256 DES-CBC3-SHA +SHA !aNULL !eNULL !LOW !MD5 !EXP !DSS !PSK !SRP !kECDH !CAMELLIA !RC4 !SEED';
    # Cut out the old, broken, insecure SSLv2 and SSLv3 entirely. 
    ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
    # Turn on session resumption, using a 10 min cache shared across nginx processes,
    # as recommended by http://nginx.org/en/docs/http/configuring_https_servers.html
    ssl_session_cache   shared:SSL:10m;
    ssl_session_timeout 10m;
    # Buffer size of 1400 bytes fits in one MTU.
    ssl_buffer_size 1400;
    # SPDY header compression (0 for none, 9 for slow/heavy compression). Preferred is 6.
    #
    # BUT: header compression is flawed and vulnerable in SPDY versions 1 - 3.
    # Disable with 0, until using a version of nginx with SPDY 4.
    spdy_headers_comp 0;
    # Now let's really get fancy, and pre-generate a 2048 bit random parameter
    # for DH elliptic curves. If not created and specified, default is only 1024 bits.
    #
    # Generated by OpenSSL with the following command:
    #   openssl dhparam -outform pem -out dhparam2048.pem 2048
    ssl_dhparam /etc/nginx/ssl/dhparam2048.pem;

You’ll need a valid server certicate to enable encrypted traffic.

And that’s basically it. You just need to restart nginx and point your browser to your domain.

Resources

Nginx Documentation: http://nginx.org/en/docs/http/ngx_http_spdy_module.html



Related posts: